|
| 1 | +import java.io.{File, FileOutputStream} |
| 2 | + |
| 3 | +import scala.tools.nsc.settings.ScalaVersion |
| 4 | +import scala.tools.partest._ |
| 5 | +import scala.tools.asm |
| 6 | +import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes} |
| 7 | +import Opcodes._ |
| 8 | + |
| 9 | +// This test ensures that we can read JDK 8 (classfile format 52) files, including those |
| 10 | +// with default methods. To do that it first uses ASM to generate an interface called |
| 11 | +// HasDefaultMethod. Then it runs a normal compile on Scala source that extends that |
| 12 | +// interface. Any failure will be dumped to std out. |
| 13 | +// |
| 14 | +// By it's nature the test can only work on JDK 8+ because under JDK 7- the |
| 15 | +// interface won't verify. |
| 16 | +object Test extends DirectTest { |
| 17 | + override def extraSettings: String = "-optimise -usejavacp -d " + testOutput.path + " -cp " + testOutput.path |
| 18 | + |
| 19 | + def generateInterface() { |
| 20 | + val interfaceName = "HasDefaultMethod" |
| 21 | + val methodType = "()Ljava/lang/String;" |
| 22 | + |
| 23 | + val cw = new ClassWriter(0) |
| 24 | + cw.visit(52, ACC_PUBLIC+ACC_ABSTRACT+ACC_INTERFACE, interfaceName, null, "java/lang/Object", null) |
| 25 | + |
| 26 | + def createMethod(flags:Int, name: String) { |
| 27 | + val method = cw.visitMethod(flags, name, methodType, null, null) |
| 28 | + method.visitCode() |
| 29 | + method.visitLdcInsn(s"hello from $name") |
| 30 | + method.visitInsn(ARETURN) |
| 31 | + method.visitMaxs(1, 1) |
| 32 | + method.visitEnd() |
| 33 | + } |
| 34 | + |
| 35 | + createMethod(ACC_PUBLIC, "publicMethod") |
| 36 | + createMethod(ACC_PUBLIC+ACC_STATIC, "staticMethod") |
| 37 | + createMethod(ACC_PRIVATE, "privateMethod") |
| 38 | + |
| 39 | + cw.visitEnd() |
| 40 | + val bytes = cw.toByteArray() |
| 41 | + |
| 42 | + val fos = new FileOutputStream(new File(s"${testOutput.path}/$interfaceName.class")) |
| 43 | + try |
| 44 | + fos write bytes |
| 45 | + finally |
| 46 | + fos.close() |
| 47 | + |
| 48 | + } |
| 49 | + |
| 50 | + def code = |
| 51 | +""" |
| 52 | +class Driver extends HasDefaultMethod { |
| 53 | + println(publicMethod()) |
| 54 | + println(HasDefaultMethod.staticMethod()) |
| 55 | +} |
| 56 | +""" |
| 57 | + |
| 58 | + override def show(): Unit = { |
| 59 | + // redirect err to out, for logging |
| 60 | + val prevErr = System.err |
| 61 | + System.setErr(System.out) |
| 62 | + try { |
| 63 | + // this test is only valid under JDK 1.8+ |
| 64 | + // cheat a little by using 'ScalaVersion' because it can parse java versions just as well |
| 65 | + val requiredJavaVersion = ScalaVersion("1.8") |
| 66 | + val executingJavaVersion = ScalaVersion(System.getProperty("java.specification.version")) |
| 67 | + if (executingJavaVersion >= requiredJavaVersion) { |
| 68 | + generateInterface() |
| 69 | + compile() |
| 70 | + Class.forName("Driver").newInstance() |
| 71 | + } else { |
| 72 | + // under other versions just dump the expected results |
| 73 | + println("hello from publicMethod") |
| 74 | + println("hello from staticMethod") |
| 75 | + } |
| 76 | + } |
| 77 | + finally |
| 78 | + System.setErr(prevErr) |
| 79 | + } |
| 80 | +} |
0 commit comments