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