diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2014-08-27 14:00:36 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2014-09-10 00:05:11 +0200 |
commit | 35c53af7e3bbe19d50845e698c02a49d0a022409 (patch) | |
tree | 2d9dce67ed018e48b8342a1bd65773af301870bc /test | |
parent | 44b5c261a8e585c5747380895aa06c84f9d63f6c (diff) | |
download | scala-35c53af7e3bbe19d50845e698c02a49d0a022409.tar.gz scala-35c53af7e3bbe19d50845e698c02a49d0a022409.tar.bz2 scala-35c53af7e3bbe19d50845e698c02a49d0a022409.zip |
Tools to run the compiler in JUnit tests
Diffstat (limited to 'test')
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala | 34 | ||||
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala | 81 |
2 files changed, 115 insertions, 0 deletions
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala index 256dff85c3..8518d5c832 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala @@ -1,7 +1,11 @@ package scala.tools.nsc.backend.jvm +import scala.reflect.internal.util.BatchSourceFile +import scala.reflect.io.VirtualDirectory import scala.tools.asm.Opcodes import scala.tools.asm.tree.{AbstractInsnNode, LabelNode, ClassNode, MethodNode} +import scala.tools.cmd.CommandLineParser +import scala.tools.nsc.{Settings, Global} import scala.tools.partest.ASMConverters import scala.collection.JavaConverters._ @@ -24,4 +28,34 @@ object CodeGenTools { cls.methods.add(method) cls } + + private def resetOutput(compiler: Global): Unit = { + compiler.settings.outputDirs.setSingleOutput(new VirtualDirectory("(memory)", None)) + } + + def newCompiler(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = { + val settings = new Settings() + val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs) + settings.processArguments(args, processAll = true) + val compiler = new Global(settings) + resetOutput(compiler) + compiler + } + + def compile(compiler: Global = newCompiler())(code: String): List[(String, Array[Byte])] = { + compiler.reporter.reset() + resetOutput(compiler) + val run = new compiler.Run() + run.compileSources(List(new BatchSourceFile("unitTestSource.scala", code))) + val outDir = compiler.settings.outputDirs.getSingleOutput.get + (for (f <- outDir.iterator if !f.isDirectory) yield (f.name, f.toByteArray)).toList + } + + def compileClasses(compiler: Global = newCompiler())(code: String): List[ClassNode] = { + compile(compiler)(code).map(p => AsmUtils.readClass(p._2)).sortBy(_.name) + } + + def compileMethods(compiler: Global = newCompiler())(code: String): List[MethodNode] = { + compileClasses(compiler)(s"class C { $code }").head.methods.asScala.toList.filterNot(_.name == "<init>") + } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala new file mode 100644 index 0000000000..640f22fc47 --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/DirectCompileTest.scala @@ -0,0 +1,81 @@ +package scala.tools.nsc.backend.jvm + +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Assert._ +import CodeGenTools._ +import scala.tools.asm.Opcodes._ +import scala.tools.partest.ASMConverters._ + +@RunWith(classOf[JUnit4]) +class DirectCompileTest { + val compiler = newCompiler(extraArgs = "-Ybackend:GenBCode") + + @Test + def testCompile(): Unit = { + val List(("C.class", bytes)) = compile(compiler)( + """ + |class C { + | def f = 1 + |} + """.stripMargin) + def s(i: Int, n: Int) = (bytes(i) & 0xff) << n + assertTrue((s(0, 24) | s(1, 16) | s(2, 8) | s(3, 0)) == 0xcafebabe) // mocha java latte machiatto surpreme dark roasted espresso + } + + @Test + def testCompileClasses(): Unit = { + val List(cClass, cModuleClass) = compileClasses(compiler)( + """ + |class C + |object C + """.stripMargin) + + assertTrue(cClass.name == "C") + assertTrue(cModuleClass.name == "C$") + + val List(dMirror, dModuleClass) = compileClasses(compiler)( + """ + |object D + """.stripMargin) + + assertTrue(dMirror.name == "D") + assertTrue(dModuleClass.name == "D$") + } + + @Test + def testCompileMethods(): Unit = { + val List(f, g) = compileMethods(compiler)( + """ + |def f = 10 + |def g = f + """.stripMargin) + assertTrue(f.name == "f") + assertTrue(g.name == "g") + + assertTrue(instructionsFromMethod(f).dropNonOp === + List(IntOp(BIPUSH, 10), Op(IRETURN))) + + assertTrue(instructionsFromMethod(g).dropNonOp === + List(VarOp(ALOAD, 0), Method(INVOKEVIRTUAL, "C", "f", "()I", false), Op(IRETURN))) + } + + @Test + def testDropNonOpAliveLabels(): Unit = { + val List(f) = compileMethods(compiler)("""def f(x: Int) = if (x == 0) "a" else "b"""") + assertTrue(instructionsFromMethod(f).dropNonOp === List( + VarOp(ILOAD, 1), + Op(ICONST_0), + Jump(IF_ICMPEQ, Label(6)), + Jump(GOTO, Label(10)), + Label(6), + Ldc(LDC, "a"), + Jump(GOTO, Label(13)), + Label(10), + Ldc(LDC, "b"), + Label(13), + Op(ARETURN) + )) + } +} |