blob: e9ff7bb576765c472cd8c452e0ea2dd91396e9ed (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
/*
* Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.atomicfu.plugin.gradle.test
import kotlinx.atomicfu.plugin.gradle.internal.*
import org.objectweb.asm.*
import java.io.File
import kotlin.test.*
abstract class BaseKotlinGradleTest(private val projectName: String) {
internal val rootProjectDir: File
private val ATOMIC_FU_REF = "Lkotlinx/atomicfu/".toByteArray()
private val KOTLIN_METADATA_DESC = "Lkotlin/Metadata;"
init {
rootProjectDir = File("build${File.separator}test-$projectName").absoluteFile
rootProjectDir.deleteRecursively()
rootProjectDir.mkdirs()
}
internal abstract fun BaseKotlinScope.createProject()
val runner = test {
createProject()
runner {
arguments.add(":build")
}
}
fun checkTaskOutcomes(executedTasks: List<String>, excludedTasks: List<String>) {
runner.build().apply {
val tasks = tasks.map { it.path }
excludedTasks.forEach {
check(it !in tasks) { "Post-compilation transformation task $it was added in the compiler plugin mode" }
}
executedTasks.forEach {
assertTaskSuccess(it)
}
}
// check that task outcomes are cached for the second build
runner.build().apply {
executedTasks.forEach {
assertTaskUpToDate(it)
}
}
}
fun checkJvmCompilationClasspath(originalClassFile: String, transformedClassFile: String) {
// check that test compile and runtime classpath does not contain original non-transformed classes
val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_jvm_classpath.txt")
val testRuntimeClasspathFiles = rootProjectDir.filesFrom("build/test_runtime_jvm_classpath.txt")
rootProjectDir.resolve(transformedClassFile).let {
it.checkExists()
check(it in testCompileClasspathFiles) { "Transformed '$it' is missing from test compile classpath" }
check(it in testRuntimeClasspathFiles) { "Transformed '$it' is missing from test runtime classpath" }
}
rootProjectDir.resolve(originalClassFile).let {
it.checkExists()
check(it !in testCompileClasspathFiles) { "Original '$it' is present in test compile classpath" }
check(it !in testRuntimeClasspathFiles) { "Original '$it' is present in test runtime classpath" }
}
}
fun checkJsCompilationClasspath() {
// check that test compilation depends on transformed main sources
val testCompileClasspathFiles = rootProjectDir.filesFrom("build/test_compile_js_classpath.txt")
rootProjectDir.resolve("build/classes/atomicfu/js/main/$projectName.js").let {
it.checkExists()
check(it in testCompileClasspathFiles) { "Transformed '$it' is missing from test compile classpath" }
}
}
fun checkBytecode(classFilePath: String) {
rootProjectDir.resolve(classFilePath).let {
it.checkExists()
assertFalse(it.readBytes().findAtomicfuRef(), "Found 'Lkotlinx/atomicfu/' reference in $it" )
}
}
private fun ByteArray.findAtomicfuRef(): Boolean {
val bytes = this.eraseMetadata()
loop@for (i in 0 until bytes.size - ATOMIC_FU_REF.size) {
for (j in 0 until ATOMIC_FU_REF.size) {
if (bytes[i + j] != ATOMIC_FU_REF[j]) continue@loop
}
return true
}
return false
}
// The atomicfu compiler plugin does not remove atomic properties from metadata,
// so for now we check that there are no ATOMIC_FU_REF left in the class bytecode excluding metadata.
// This may be reverted after the fix in the compiler plugin transformer (See #254).
private fun ByteArray.eraseMetadata(): ByteArray {
val cw = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES)
ClassReader(this).accept(object : ClassVisitor(Opcodes.ASM9, cw) {
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
return if (descriptor == KOTLIN_METADATA_DESC) null else super.visitAnnotation(descriptor, visible)
}
}, ClassReader.SKIP_FRAMES)
return cw.toByteArray()
}
}
|