Add IR tests to Android codegen test

This commit is contained in:
Mikhael Bogdanov
2021-02-11 13:46:33 +01:00
parent c0759f96e9
commit f493766563
7 changed files with 84 additions and 57 deletions
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.1'
classpath 'com.android.tools.build:gradle:4.1.2'
}
}
apply plugin: 'com.android.application'
@@ -37,14 +37,6 @@ android {
packagingOptions { exclude 'META-INF/build.txt' }
//TODO run under java 6, cause there is error on implicit 'stream' import in 'asWithMutable' test
lintOptions {
abortOnError false
}
compileOptions {
incremental = false
}
dexOptions {
dexInProcess false
@@ -80,6 +72,22 @@ android {
reflect0 {
dimension "box"
}
common_ir0 {
dimension "box"
}
common_ir1 {
dimension "box"
}
common_ir2 {
dimension "box"
}
reflect_ir0 {
dimension "box"
}
}
}
@@ -12,7 +12,6 @@ import com.intellij.openapi.util.io.FileUtilRt
import org.jetbrains.kotlin.cli.common.output.writeAllTo
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.CodegenTestFiles
import org.jetbrains.kotlin.codegen.GenerationUtils
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
@@ -22,8 +21,6 @@ import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
@@ -57,15 +54,18 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
//keep it globally to avoid test grouping on TC
private val generatedTestNames = hashSetOf<String>()
private val COMMON = FlavorConfig("common", 3)
private val REFLECT = FlavorConfig("reflect", 1)
private val COMMON = FlavorConfig(TargetBackend.ANDROID,"common", 3)
private val REFLECT = FlavorConfig(TargetBackend.ANDROID, "reflect", 1)
class FlavorConfig(private val prefix: String, val limit: Int) {
private val COMMON_IR = FlavorConfig(TargetBackend.ANDROID_IR, "common_ir", 3)
private val REFLECT_IR = FlavorConfig(TargetBackend.ANDROID_IR,"reflect_ir", 1)
class FlavorConfig(private val backend: TargetBackend, private val prefix: String, val limit: Int) {
private var writtenFilesCount = 0
fun printStatistics() {
println("FlavorTestCompiler: $prefix, generated file count: $writtenFilesCount")
println("FlavorTestCompiler for $backend: $prefix, generated file count: $writtenFilesCount")
}
fun getFlavorForNewFiles(newFilesCount: Int): String {
@@ -148,25 +148,47 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
private fun generateTestsAndFlavourSuites() {
println("Generating test files...")
generateTestMethodsForDirectories(File("compiler/testData/codegen/box"), File("compiler/testData/codegen/boxInline"))
val folders = arrayOf(
File("compiler/testData/codegen/box"),
File("compiler/testData/codegen/boxInline")
)
generateTestMethodsForDirectories(
TargetBackend.ANDROID,
COMMON,
REFLECT,
*folders
)
generateTestMethodsForDirectories(
TargetBackend.ANDROID_IR,
COMMON_IR,
REFLECT_IR,
*folders
)
pendingUnitTestGenerators.values.forEach { it.generate() }
}
private fun generateTestMethodsForDirectories(vararg dirs: File) {
private fun generateTestMethodsForDirectories(
backend: TargetBackend,
commonFlavor: FlavorConfig,
reflectionFlavor: FlavorConfig,
vararg dirs: File
) {
val holders = mutableMapOf<ConfigurationKey, FilesWriter>()
for (dir in dirs) {
val files = dir.listFiles() ?: error("Folder with testData is empty: ${dir.absolutePath}")
processFiles(files, holders)
processFiles(files, holders, backend, commonFlavor, reflectionFlavor)
}
holders.values.forEach {
it.writeFilesOnDisk()
}
COMMON.printStatistics()
REFLECT.printStatistics()
commonFlavor.printStatistics()
reflectionFlavor.printStatistics()
}
internal inner class FilesWriter(
@@ -254,7 +276,10 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
@Throws(IOException::class)
private fun processFiles(
files: Array<File>,
holders: MutableMap<ConfigurationKey, FilesWriter>
holders: MutableMap<ConfigurationKey, FilesWriter>,
backend: TargetBackend,
commmonFlavor: FlavorConfig,
reflectionFlavor: FlavorConfig
) {
holders.values.forEach {
it.writeFilesOnDiskIfNeeded()
@@ -264,7 +289,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
if (file.isDirectory) {
val listFiles = file.listFiles()
if (listFiles != null) {
processFiles(listFiles, holders)
processFiles(listFiles, holders, backend, commmonFlavor, reflectionFlavor)
}
} else if (FileUtilRt.getExtension(file.name) != KotlinFileType.EXTENSION) {
// skip non kotlin files
@@ -273,7 +298,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
continue
}
if (!InTextDirectivesUtils.isPassingTarget(TargetBackend.JVM, file) ||
if (!InTextDirectivesUtils.isPassingTarget(backend.compatibleWith, file) ||
InTextDirectivesUtils.isIgnoredTarget(TargetBackend.ANDROID, file)
) {
continue
@@ -304,7 +329,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
if (fullFileText.contains("// SKIP_JDK6")) continue
if (hasBoxMethod(fullFileText)) {
val testConfiguration = createTestConfiguration(file)
val testConfiguration = createTestConfiguration(file, backend)
val services = testConfiguration.testServices
val moduleStructure = try {
@@ -335,7 +360,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
keyConfiguration.languageVersionSettings = module.languageVersionSettings
val key = ConfigurationKey(kind, jdkKind, keyConfiguration.toString())
val compiler = if (kind.withReflection) REFLECT else COMMON
val compiler = if (kind.withReflection) reflectionFlavor else commmonFlavor
val compilerConfigurationProvider = services.compilerConfigurationProvider as CompilerConfigurationProviderImpl
val filesHolder = holders.getOrPut(key) {
FilesWriter(compiler, compilerConfigurationProvider.createCompilerConfiguration(module)).also {
@@ -349,9 +374,9 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
}
}
private fun createTestConfiguration(testDataFile: File): TestConfiguration {
private fun createTestConfiguration(testDataFile: File, backend: TargetBackend): TestConfiguration {
return TestConfigurationBuilder().apply {
testConfiguration()
configure(backend)
testInfo = KotlinTestInfo(
"org.jetbrains.kotlin.android.tests.AndroidRunner",
"test${testDataFile.nameWithoutExtension.capitalize()}",
@@ -360,10 +385,10 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
}.build(testDataFile.path)
}
private val testConfiguration: TestConfigurationBuilder.() -> Unit = {
private fun TestConfigurationBuilder.configure(backend: TargetBackend) {
globalDefaults {
frontend = FrontendKinds.ClassicFrontend
targetBackend = TargetBackend.ANDROID
targetBackend = backend
targetPlatform = JvmPlatforms.defaultJvmPlatform
dependencyKind = DependencyKind.Binary
}
@@ -386,9 +411,6 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
useDirectives(*AbstractKotlinCompilerTest.defaultDirectiveContainers.toTypedArray())
}
private fun createTestFiles(file: File, expectedText: String): List<KotlinBaseTest.TestFile> =
CodegenTestCase.createTestFilesFromFile(file, expectedText, false, TargetBackend.JVM)
companion object {
const val GRADLE_VERSION = "6.8.1" // update GRADLE_SHA_256 on change
const val GRADLE_SHA_256 = "fd591a34af7385730970399f473afabdb8b28d57fd97d6625c388d090039d6fd"
@@ -71,15 +71,20 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P
return rootSuite
}
private fun processReport(suite: TestSuite, resultOutput: String) {
private fun processReport(rootSuite: TestSuite, resultOutput: String) {
val reportFolder = File(flavorFolder())
try {
val folders = reportFolder.listFiles()
assertTrue(folders != null && folders.isNotEmpty(), "No folders in ${reportFolder.path}")
folders.forEach {
assertTrue("${it.path} is not directory") { it.isDirectory }
val isIr = it.name.contains("_ir")
val testCases = parseSingleReportInFolder(it)
testCases.forEach { aCase -> suite.addTest(aCase) }
testCases.forEach { aCase ->
if (isIr) aCase.name += "_ir"
rootSuite.addTest(aCase)
}
Assert.assertNotEquals("There is no test results in report", 0, testCases.size.toLong())
}
} catch (e: Throwable) {
@@ -87,10 +92,6 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P
}
}
private fun renameFlavorFolder() {
val reportFolder = File(flavorFolder())
reportFolder.renameTo(File(reportFolder.parentFile, reportFolder.name + "_d8"))
}
private fun flavorFolder() = pathManager.tmpFolder + "/build/test/results/connected/flavors"
@@ -119,7 +120,7 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P
private fun cleanAndBuildProject(gradleRunner: GradleRunner) {
gradleRunner.clean()
gradleRunner.build()
gradleRunner.assembleAndroidTest()
}
@Throws(IOException::class, SAXException::class, ParserConfigurationException::class)
@@ -138,21 +139,14 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P
return (0 until testCases.length).map { i ->
val item = testCases.item(i) as Element
val failure = item.getElementsByTagName("failure")
val failure = item.getElementsByTagName("failure").takeIf { it.length != 0 }?.item(0)
val name = item.getAttribute("name")
if (failure.length == 0) {
object : TestCase(name) {
@Throws(Throwable::class)
override fun runTest() {
}
}
} else {
object : TestCase(name) {
@Throws(Throwable::class)
override fun runTest() {
Assert.fail(failure.item(0).textContent)
object : TestCase(name) {
@Throws(Throwable::class)
override fun runTest() {
if (failure != null) {
Assert.fail(failure.textContent)
}
}
}
@@ -45,9 +45,9 @@ public class GradleRunner {
OutputUtils.checkResult(result);
}
public void build() {
public void assembleAndroidTest() {
System.out.println("Building gradle project...");
GeneralCommandLine build = generateCommandLine("build");
GeneralCommandLine build = generateCommandLine("assembleAndroidTest");
build.addParameter("--stacktrace");
build.addParameter("--warn");
RunResult result = RunUtils.execute(build);
@@ -20,6 +20,7 @@ enum class TargetBackend(
JS_IR_ES6(true, JS_IR),
WASM(true),
ANDROID(false, JVM),
ANDROID_IR(true, JVM_IR),
NATIVE(true);
val compatibleWith get() = compatibleWithTargetBackend ?: ANY
@@ -1,6 +1,5 @@
// EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: ANDROID
// JVM_TARGET: 1.8
// WITH_REFLECT
// FULL_JDK
@@ -4,11 +4,14 @@
// LAMBDAS: INDY
// WITH_RUNTIME
// desugaring on Android
// IGNORE_BACKEND: ANDROID
fun lambdaToString(fn: () -> Unit) = fn.toString()
fun box(): String {
val str = lambdaToString {}
if (!str.startsWith("LambdaToStingKt"))
return "Failed: indy lambda toString is inherited from java.lang.Object"
return "Failed: indy lambda toString is inherited from java.lang.Object: $str"
return "OK"
}