summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Iry <james.iry@typesafe.com>2013-05-29 14:10:02 -0700
committerJames Iry <james.iry@typesafe.com>2013-05-29 14:19:25 -0700
commitfc6da8d8b765ddc3c492d0884164561ca7a8b4d8 (patch)
tree65c6301aef6880e456f97d59df1bcfefce66db4a
parent9eb63c522fc3f490ff8ff3e731dca1e160a0338f (diff)
downloadscala-fc6da8d8b765ddc3c492d0884164561ca7a8b4d8.tar.gz
scala-fc6da8d8b765ddc3c492d0884164561ca7a8b4d8.tar.bz2
scala-fc6da8d8b765ddc3c492d0884164561ca7a8b4d8.zip
Test for reading JDK 8 (classfile format 52) class files.
This commit includes a test for reading JDK 8 (classfile format 52) class files, in particular default (aka defender) methods. It uses ASM to generate an interface with default methods then exercises that interface from Scala. Surprisingly no changes are necessary to the Scala code base to support reading format 52 class files. Because the test can only run under JDK 8, the JDK version is checked and the expected output is synthesized for previous versions.
-rw-r--r--test/files/run/classfile-format-52.check2
-rw-r--r--test/files/run/classfile-format-52.scala80
2 files changed, 82 insertions, 0 deletions
diff --git a/test/files/run/classfile-format-52.check b/test/files/run/classfile-format-52.check
new file mode 100644
index 0000000000..5d24ef03cc
--- /dev/null
+++ b/test/files/run/classfile-format-52.check
@@ -0,0 +1,2 @@
+hello from publicMethod
+hello from staticMethod
diff --git a/test/files/run/classfile-format-52.scala b/test/files/run/classfile-format-52.scala
new file mode 100644
index 0000000000..f0ad7c2ed6
--- /dev/null
+++ b/test/files/run/classfile-format-52.scala
@@ -0,0 +1,80 @@
+import java.io.{File, FileOutputStream}
+
+import scala.tools.nsc.settings.ScalaVersion
+import scala.tools.partest._
+import scala.tools.asm
+import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes}
+import Opcodes._
+
+// This test ensures that we can read JDK 8 (classfile format 52) files, including those
+// with default methods. To do that it first uses ASM to generate an interface called
+// HasDefaultMethod. Then it runs a normal compile on Scala source that extends that
+// interface. Any failure will be dumped to std out.
+//
+// By it's nature the test can only work on JDK 8+ because under JDK 7- the
+// interface won't verify.
+object Test extends DirectTest {
+ override def extraSettings: String = "-optimise -usejavacp -d " + testOutput.path + " -cp " + testOutput.path
+
+ def generateInterface() {
+ val interfaceName = "HasDefaultMethod"
+ val methodType = "()Ljava/lang/String;"
+
+ val cw = new ClassWriter(0)
+ cw.visit(52, ACC_PUBLIC+ACC_ABSTRACT+ACC_INTERFACE, interfaceName, null, "java/lang/Object", null)
+
+ def createMethod(flags:Int, name: String) {
+ val method = cw.visitMethod(flags, name, methodType, null, null)
+ method.visitCode()
+ method.visitLdcInsn(s"hello from $name")
+ method.visitInsn(ARETURN)
+ method.visitMaxs(1, 1)
+ method.visitEnd()
+ }
+
+ createMethod(ACC_PUBLIC, "publicMethod")
+ createMethod(ACC_PUBLIC+ACC_STATIC, "staticMethod")
+ createMethod(ACC_PRIVATE, "privateMethod")
+
+ cw.visitEnd()
+ val bytes = cw.toByteArray()
+
+ val fos = new FileOutputStream(new File(s"${testOutput.path}/$interfaceName.class"))
+ try
+ fos write bytes
+ finally
+ fos.close()
+
+ }
+
+ def code =
+"""
+class Driver extends HasDefaultMethod {
+ println(publicMethod())
+ println(HasDefaultMethod.staticMethod())
+}
+"""
+
+ override def show(): Unit = {
+ // redirect err to out, for logging
+ val prevErr = System.err
+ System.setErr(System.out)
+ try {
+ // this test is only valid under JDK 1.8+
+ // cheat a little by using 'ScalaVersion' because it can parse java versions just as well
+ val requiredJavaVersion = ScalaVersion("1.8")
+ val executingJavaVersion = ScalaVersion(System.getProperty("java.specification.version"))
+ if (executingJavaVersion >= requiredJavaVersion) {
+ generateInterface()
+ compile()
+ Class.forName("Driver").newInstance()
+ } else {
+ // under other versions just dump the expected results
+ println("hello from publicMethod")
+ println("hello from staticMethod")
+ }
+ }
+ finally
+ System.setErr(prevErr)
+ }
+}