Parcel: Invoke box tests as an external process to prevent class clashes with IntelliJ platform

This commit is contained in:
Yan Zhulanow
2017-07-27 21:02:01 +03:00
committed by Yan Zhulanow
parent 11b6382518
commit 5641909d1d
4 changed files with 137 additions and 70 deletions
+15 -33
View File
@@ -2,58 +2,40 @@
<library name="robolectric">
<CLASSES>
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/accessibility-test-framework-2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/android-all-6.0.0_r1-robolectric-0.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/annotations-12.0.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/ant-1.8.0.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/ant-launcher-1.8.0.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-5.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-analysis-5.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-commons-5.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-tree-5.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/assertj-core-2.6.0.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/backport-util-concurrent-3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-util-5.0.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/bcprov-jdk16-1.46.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/classworlds-1.1-alpha-2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/guava-20.0.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/guava-19.0-rc2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/hamcrest-core-1.3.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/hamcrest-library-1.3.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/icu4j-53.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/junit-4.8.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-ant-tasks-2.1.3.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-artifact-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-artifact-manager-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-error-diagnostics-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-model-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-plugin-registry-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-profile-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-project-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-repository-metadata-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-settings-2.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/nekohtml-1.9.6.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/plexus-container-default-1.0-alpha-9-stable-1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/plexus-interpolation-1.11.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/plexus-utils-1.5.15.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/protobuf-java-2.6.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-annotations-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-junit-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-resources-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-sandbox-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-utils-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/shadow-api-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/shadows-core-3.3.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-annotations-3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-resources-3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-utils-3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/shadows-core-3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/sqlite4java-0.282.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-file-1.0-beta-6.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-http-lightweight-1.0-beta-6.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-http-shared-1.0-beta-6.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-provider-api-1.0-beta-6.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xercesMinimal-1.9.6.2.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/vtd-xml-2.11.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xmlpull-1.1.3.1.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xpp3_min-1.1.4c.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xstream-1.4.8.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2-javadoc.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2-sources-source.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2-sources.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-ant-tasks-2.1.3-sources.jar!/" />
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.1-sources.jar!/" />
</SOURCES>
</library>
</component>
@@ -22,52 +22,142 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.getClassFiles
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.org.objectweb.asm.ClassWriter
import org.jetbrains.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES
import org.jetbrains.org.objectweb.asm.ClassWriter.COMPUTE_MAXS
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.junit.runner.JUnitCore
import java.io.File
import java.net.URLClassLoader
import java.nio.ByteBuffer
import java.security.ProtectionDomain
import java.nio.file.Files
import java.util.concurrent.TimeUnit
abstract class AbstractParcelBoxTest : CodegenTestCase() {
protected companion object {
val BASE_DIR = "plugins/android-extensions/android-extensions-compiler/testData/parcel/box"
val LIBRARY_KT = File(File(BASE_DIR).parentFile, "boxLib.kt")
private val JUNIT_GENERATED_TEST_CLASS_BYTES by lazy { constructSyntheticTestClass() }
private val JUNIT_GENERATED_TEST_CLASS_FQNAME = "test.JunitTest"
private fun constructSyntheticTestClass(): ByteArray {
return with(ClassWriter(COMPUTE_MAXS or COMPUTE_FRAMES)) {
visit(49, ACC_PUBLIC, JUNIT_GENERATED_TEST_CLASS_FQNAME.replace('.', '/'), null, "java/lang/Object", emptyArray())
visitSource(null, null)
with(visitAnnotation("Lorg/junit/runner/RunWith;", true)) {
visit("value", Type.getType("Lorg/robolectric/RobolectricTestRunner;"))
visitEnd()
}
with(visitAnnotation("Lorg/robolectric/annotation/Config;", true)) {
visit("manifest", "--none")
visitEnd()
}
with(visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)) {
visitVarInsn(ALOAD, 0)
visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
visitInsn(RETURN)
visitMaxs(-1, -1)
visitEnd()
}
with(visitMethod(ACC_PUBLIC, "test", "()V", null, null)) {
visitAnnotation("Lorg/junit/Test;", true).visitEnd()
val v = InstructionAdapter(this)
val assertionOk = Label()
v.invokestatic("test/TestKt", "box", "()Ljava/lang/String;", false) // -> ret
v.dup() // -> ret, ret
v.aconst("OK") // -> ret, ret, ok
v.invokevirtual("java/lang/String", "equals", "(Ljava/lang/Object;)Z", false) // -> ret, eq
v.ifne(assertionOk) // -> ret
val assertionErrorType = Type.getObjectType("java/lang/AssertionError")
v.anew(assertionErrorType) // -> ret, ae
v.dupX1() // -> ae, ret, ae
v.swap() // -> ae, ae, ret
v.invokespecial(assertionErrorType.internalName, "<init>", "(Ljava/lang/Object;)V", false) // -> ae
v.athrow()
v.visitLabel(assertionOk)
v.pop() // -> [empty]
v.areturn(Type.VOID_TYPE)
visitMaxs(-1, -1)
visitEnd()
}
visitEnd()
toByteArray()
}
}
}
override fun doTest(filePath: String) {
super.doTest(File(BASE_DIR, filePath + ".kt").absolutePath)
}
open protected fun getClassLoaderWithGeneratedFiles(): ClassLoader {
return object : URLClassLoader(arrayOf(), this::class.java.classLoader) {
init {
for (classFile in classFileFactory.getClassFiles().sortedBy { it.relativePath }) {
val bytes = classFile.asByteArray()
val className = ClassNode().also { ClassReader(bytes).accept(it, ClassReader.EXPAND_FRAMES) }.name
try {
defineClass(className.replace('/', '.'), ByteBuffer.wrap(bytes), null as ProtectionDomain?)
} catch (e: Throwable) {
throw RuntimeException("Can't load class $className", e)
}
}
}
}
private fun getClasspathForTest(): List<File> {
val kotlinRuntimeJar = PathUtil.kotlinPathsForIdeaPlugin.stdlibPath
val layoutLibJars = listOf(File("ideaSDK/plugins/android/lib/layoutlib.jar"), File("ideaSDK/plugins/android/lib/layoutlib-api.jar"))
val robolectricJars = File("dependencies/robolectric")
.listFiles { f: File -> f.extension == "jar" }
.sortedBy { it.nameWithoutExtension }
val junitCoreResourceName = JUnitCore::class.java.name.replace('.', '/') + ".class"
val junitJar = File(JUnitCore::class.java.classLoader.getResource(junitCoreResourceName).file.substringBeforeLast('!'))
val androidExtensionsRuntime = File("out/production/android-extensions-runtime")
return listOf(kotlinRuntimeJar) + layoutLibJars + robolectricJars + junitJar + androidExtensionsRuntime
}
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
if (true) { // TODO Parcelable box tests are disabled because of OOM. Currently investigating
return
}
compile(files + TestFile(LIBRARY_KT.name, LIBRARY_KT.readText()), javaFilesDir)
val testClass = Class.forName("test.TestKt", false, getClassLoaderWithGeneratedFiles())
val javaBin = File(System.getProperty("java.home").takeIf { it.isNotEmpty() } ?: error("JAVA_HOME is not set"), "bin")
val javaExe = File(javaBin, "java.exe").takeIf { it.exists() } ?: File(javaBin, "java")
assert(javaExe.exists()) { "Can't find 'java' executable in $javaBin" }
val libraryClasspath = getClasspathForTest()
val dirForTestClasses = Files.createTempDirectory("parcel").toFile()
fun writeClass(fqNameOrPath: String, bytes: ByteArray) {
val path = if (fqNameOrPath.endsWith(".class")) fqNameOrPath else (fqNameOrPath.replace('.', '/') + ".class")
File(dirForTestClasses, path).also { it.parentFile.mkdirs() }.writeBytes(bytes)
}
try {
testClass.getDeclaredMethod("box").invoke(testClass)
} catch (e: Throwable) {
throw AssertionError(classFileFactory.createText(), e)
writeClass(JUNIT_GENERATED_TEST_CLASS_FQNAME, JUNIT_GENERATED_TEST_CLASS_BYTES)
classFileFactory.getClassFiles().forEach { writeClass(it.relativePath, it.asByteArray()) }
val process = ProcessBuilder(
javaExe.absolutePath,
"-ea",
"-classpath",
(libraryClasspath + dirForTestClasses).joinToString(File.pathSeparator),
JUnitCore::class.java.name,
JUNIT_GENERATED_TEST_CLASS_FQNAME
).inheritIO().start()
process.waitFor(3, TimeUnit.MINUTES)
if (process.exitValue() != 0) {
throw AssertionError(classFileFactory.createText())
}
} finally {
if (!dirForTestClasses.deleteRecursively()) {
throw AssertionError("Unable to delete $dirForTestClasses")
}
}
}
@@ -16,14 +16,6 @@
package org.jetbrains.kotlin.android.parcel
import org.junit.Test
import org.junit.runner.RunWith
//import org.robolectric.RobolectricTestRunner
//import org.robolectric.annotation.Config
// This class is not generated because it uses the custom test runner
//@RunWith(RobolectricTestRunner::class)
//@Config(manifest = Config.NONE)
class ParcelBoxTest : AbstractParcelBoxTest() {
fun testSimple() = doTest("simple")
fun testPrimitiveTypes() = doTest("primitiveTypes")
+4 -1
View File
@@ -247,9 +247,12 @@
<get-maven-library-with-dependencies
group="org.robolectric"
artifact="robolectric"
version="3.3.2"
version="3.1"
target.dir="robolectric"/>
<get-maven-library prefix="org/apache/maven" lib="maven-ant-tasks" version="2.1.3"
target.jar.name.base="maven-ant-tasks" download="${dependencies}/robolectric" />
<!-- kotlinx.coroutines -->
<get-maven-library prefix="org/jetbrains/kotlinx" lib="kotlinx-coroutines-core" version="${kotlinx.coroutines.version}"
target.jar.name.base="kotlinx-coroutines-core" server="http://dl.bintray.com/kotlin/kotlinx/"/>