From ec434411904c1ad0399b6dae1e968ca188803b03 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 13 Oct 2013 15:12:26 +0400 Subject: [PATCH] Generic mechanism for creating test suites --- test/org/jetbrains/eval4j/test/main.kt | 77 ++++--------------- .../org/jetbrains/eval4j/test/suiteBuilder.kt | 76 ++++++++++++++++++ 2 files changed, 89 insertions(+), 64 deletions(-) create mode 100644 test/org/jetbrains/eval4j/test/suiteBuilder.kt diff --git a/test/org/jetbrains/eval4j/test/main.kt b/test/org/jetbrains/eval4j/test/main.kt index 491abb64a16..fdcbaab200c 100644 --- a/test/org/jetbrains/eval4j/test/main.kt +++ b/test/org/jetbrains/eval4j/test/main.kt @@ -13,80 +13,29 @@ import java.lang.reflect.Field import java.lang.reflect.Constructor import java.lang.reflect.InvocationTargetException import java.lang.reflect.Array as JArray -import org.objectweb.asm.tree.analysis.Interpreter import org.objectweb.asm.tree.analysis.Frame -fun suite(): TestSuite { - val suite = TestSuite() +fun suite(): TestSuite = buildTestSuite { + methodNode, ownerClass, expected -> + object : TestCase("test" + methodNode.name.capitalize()) { - val ownerClass = javaClass() - val inputStream = ownerClass.getClassLoader()!!.getResourceAsStream(ownerClass.getInternalName() + ".class")!! + override fun runTest() { + val value = interpreterLoop( + methodNode, + initFrame( + ownerClass.getInternalName(), + methodNode + ), + REFLECTION_EVAL + ) - ClassReader(inputStream).accept(object : ClassVisitor(ASM4) { - - override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { - return object : MethodNode(access, name, desc, signature, exceptions) { - override fun visitEnd() { - val testCase = doTest(ownerClass, this) - if (testCase != null) { - suite.addTest(testCase) - } - } + assertEquals(expected, value) } } - }, 0) - - return suite } fun Class<*>.getInternalName(): String = Type.getType(this).getInternalName() -fun doTest(ownerClass: Class, methodNode: MethodNode): TestCase? { - var expected: InterpreterResult? = null - for (method in ownerClass.getDeclaredMethods()) { - if (method.getName() == methodNode.name) { - if ((method.getModifiers() and Modifier.STATIC) == 0) { - println("Skipping instance method: $method") - } - else if (method.getParameterTypes()!!.size > 0) { - println("Skipping method with parameters: $method") - } - else { - method.setAccessible(true) - val result = method.invoke(null) - val returnType = Type.getType(method.getReturnType()!!) - try { - expected = ValueReturned(objectToValue(result, returnType)) - } - catch (e: UnsupportedOperationException) { - println("Skipping $method: $e") - } - } - } - } - - if (expected == null) { - println("Method not found: ${methodNode.name}") - return null - } - - return object : TestCase("test" + methodNode.name.capitalize()) { - - override fun runTest() { - val value = interpreterLoop( - methodNode, - initFrame( - ownerClass.getInternalName(), - methodNode - ), - REFLECTION_EVAL - ) - - assertEquals(expected, value) - } - } -} - fun initFrame( owner: String, m: MethodNode diff --git a/test/org/jetbrains/eval4j/test/suiteBuilder.kt b/test/org/jetbrains/eval4j/test/suiteBuilder.kt new file mode 100644 index 00000000000..8b26aa120b8 --- /dev/null +++ b/test/org/jetbrains/eval4j/test/suiteBuilder.kt @@ -0,0 +1,76 @@ +package org.jetbrains.eval4j.test + +import org.objectweb.asm.* +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.tree.MethodNode +import java.lang.reflect.Modifier +import org.jetbrains.eval4j.* +import org.junit.Assert.* +import junit.framework.TestSuite +import junit.framework.TestCase +import java.lang.reflect.Method +import java.lang.reflect.Field +import java.lang.reflect.Constructor +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Array as JArray +import org.objectweb.asm.tree.analysis.Interpreter +import org.objectweb.asm.tree.analysis.Frame + +fun buildTestSuite( + create: (MethodNode, Class<*>, InterpreterResult?) -> TestCase +): TestSuite { + val suite = TestSuite() + + val ownerClass = javaClass() + val inputStream = ownerClass.getClassLoader()!!.getResourceAsStream(ownerClass.getInternalName() + ".class")!! + + ClassReader(inputStream).accept(object : ClassVisitor(ASM4) { + + override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { + return object : MethodNode(access, name, desc, signature, exceptions) { + override fun visitEnd() { + val testCase = buildTestCase(ownerClass, this, create) + if (testCase != null) { + suite.addTest(testCase) + } + } + } + } + }, 0) + + return suite +} + +fun buildTestCase(ownerClass: Class, + methodNode: MethodNode, + create: (MethodNode, Class, InterpreterResult?) -> TestCase): TestCase? { + var expected: InterpreterResult? = null + for (method in ownerClass.getDeclaredMethods()) { + if (method.getName() == methodNode.name) { + if ((method.getModifiers() and Modifier.STATIC) == 0) { + println("Skipping instance method: $method") + } + else if (method.getParameterTypes()!!.size > 0) { + println("Skipping method with parameters: $method") + } + else { + method.setAccessible(true) + val result = method.invoke(null) + val returnType = Type.getType(method.getReturnType()!!) + try { + expected = ValueReturned(objectToValue(result, returnType)) + } + catch (e: UnsupportedOperationException) { + println("Skipping $method: $e") + } + } + } + } + + if (expected == null) { + println("Method not found: ${methodNode.name}") + return null + } + + return create(methodNode, ownerClass, expected) +} \ No newline at end of file