diff --git a/compiler/android-tests/android-module/android-module.ipr b/compiler/android-tests/android-module/android-module.ipr deleted file mode 100644 index 6d88254ff08..00000000000 --- a/compiler/android-tests/android-module/android-module.ipr +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - diff --git a/compiler/android-tests/android-module/build.gradle b/compiler/android-tests/android-module/build.gradle index ba2d5676be7..16a2df2a240 100644 --- a/compiler/android-tests/android-module/build.gradle +++ b/compiler/android-tests/android-module/build.gradle @@ -5,9 +5,8 @@ buildscript { google() jcenter() } - dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' - + dependencies { + classpath 'com.android.tools.build:gradle:3.3.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -31,7 +30,6 @@ android { versionName "1.0" testApplicationId "org.jetbrains.kotlin.android.tests.gradle" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - multiDexEnabled true } buildTypes { debug { @@ -62,6 +60,19 @@ android { resultsDir = "build/test/results" } + + flavorDimensions "box" + + productFlavors { + ktest0 { + dimension "box" + } + + ktest1 { + dimension "box" + } + } + } task jarTestFolders() { @@ -81,7 +92,8 @@ tasks.withType(JavaCompile) { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) androidTestImplementation 'junit:junit:4.12' - implementation 'com.android.support:multidex:1.0.3' androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation fileTree(dir: 'libs/test', include: ['*.jar']) + + ktest0Implementation fileTree(dir: 'libs/test', include: ['libtest0.jar']) + ktest1Implementation fileTree(dir: 'libs/test', include: ['libtest1.jar']) } diff --git a/compiler/android-tests/android-module/project.properties b/compiler/android-tests/android-module/project.properties deleted file mode 100644 index 5383d8efb40..00000000000 --- a/compiler/android-tests/android-module/project.properties +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt - -# Project target. -target=android-16 diff --git a/compiler/android-tests/build.gradle.kts b/compiler/android-tests/build.gradle.kts index 1513e4e9665..5e23d88bc7d 100644 --- a/compiler/android-tests/build.gradle.kts +++ b/compiler/android-tests/build.gradle.kts @@ -53,3 +53,7 @@ projectTest { workingDir = rootDir } + +val generateTests by generator("org.jetbrains.kotlin.android.tests.CodegenTestsOnAndroidGenerator") + +generateTests.workingDir = rootDir diff --git a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidRunner.kt b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidRunner.kt index 37d6fb39cd7..82f143c98aa 100644 --- a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidRunner.kt +++ b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidRunner.kt @@ -30,6 +30,7 @@ import java.io.File import java.io.IOException import javax.xml.parsers.DocumentBuilderFactory import javax.xml.parsers.ParserConfigurationException +import kotlin.test.assertTrue class CodegenTestsOnAndroidRunner private constructor(private val pathManager: PathManager) { @@ -59,7 +60,7 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P rootSuite.addTest(this) } - renameReport() + renameFlavorFolder() enableD8(true) runTestsOnEmulator(gradleRunner, TestSuite("D8")).apply { (0 until this.countTestCases()).forEach { @@ -95,22 +96,27 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P } private fun processReport(suite: TestSuite, resultOutput: String) { - val reportFolder = reportFolder() + val reportFolder = File(flavorFolder()) try { - val testCases = parseSingleReportInFolder(reportFolder) - testCases.forEach { aCase -> suite.addTest(aCase) } - Assert.assertNotEquals("There is no test results in report", 0, testCases.size.toLong()) + 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 testCases = parseSingleReportInFolder(it) + testCases.forEach { aCase -> suite.addTest(aCase) } + Assert.assertNotEquals("There is no test results in report", 0, testCases.size.toLong()) + } } catch (e: Exception) { throw RuntimeException("Can't parse test results in $reportFolder\n$resultOutput", e) } } - private fun renameReport() { - val reportFolder = File(reportFolder()) + private fun renameFlavorFolder() { + val reportFolder = File(flavorFolder()) reportFolder.renameTo(File(reportFolder.parentFile, reportFolder.name + "_dex")) } - private fun reportFolder() = pathManager.tmpFolder + "/build/test/results/connected/" + private fun flavorFolder() = pathManager.tmpFolder + "/build/test/results/connected/flavors" private fun runTestsOnEmulator(gradleRunner: GradleRunner, suite: TestSuite): TestSuite { val platformPrefixProperty = System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, "Idea") @@ -153,11 +159,10 @@ class CodegenTestsOnAndroidRunner private constructor(private val pathManager: P } @Throws(IOException::class, SAXException::class, ParserConfigurationException::class) - private fun parseSingleReportInFolder(reportFolder: String): List { - val folder = File(reportFolder) + private fun parseSingleReportInFolder(folder: File): List { val files = folder.listFiles()!! assert(files.size == 1) { - "Expecting one file but ${files.size}: ${files.joinToString { it.name }}" + "Expecting one file but ${files.size}: ${files.joinToString { it.name }} in ${folder.path}" } val reportFile = files[0] diff --git a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/PathManager.java b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/PathManager.java index 147e09b7488..39ea00fbbc8 100644 --- a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/PathManager.java +++ b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/PathManager.java @@ -60,10 +60,6 @@ public class PathManager { return tmpFolder + "/libs/libtest" + index; } - public String getLibsFolderInAndroidTestedModuleTmpFolder() { - return tmpFolder + "/tested-module/libs"; - } - public String getLibsFolderInAndroidTmpFolder() { return tmpFolder + "/libs"; } diff --git a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/download/SDKDownloader.java b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/download/SDKDownloader.java index 04d18a466ea..9e149ad6efc 100644 --- a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/download/SDKDownloader.java +++ b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/download/SDKDownloader.java @@ -43,7 +43,7 @@ public class SDKDownloader { private static final String SDK_TOOLS = "4333796"; //"26.1.1"; public static final String BUILD_TOOLS = "28.0.3"; private static final int ANDROID_VERSION = 19; - public static final String GRADLE_VERSION = "4.6"; + public static final String GRADLE_VERSION = "5.1.1"; public static final String EMULATOR_TOOLS_VERSION = "5264690"; //"28.0.23"; diff --git a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/gradle/GradleRunner.java b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/gradle/GradleRunner.java index 0f3b7d9d680..99c51e2c1e2 100644 --- a/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/gradle/GradleRunner.java +++ b/compiler/android-tests/src/org/jetbrains/kotlin/android/tests/gradle/GradleRunner.java @@ -70,8 +70,7 @@ public class GradleRunner { System.out.println("Starting tests..."); GeneralCommandLine test = generateCommandLine("connectedAndroidTest"); test.addParameters("--stacktrace"); - //To avoid problem with discovering tests on Android in multidex build - test.addParameters("-Pandroid.testInstrumentationRunnerArguments.class=org.jetbrains.kotlin.android.tests.CodegenTestCaseOnAndroid"); + test.addParameters("--continue"); //run all flavors even if any fail return RunUtils.execute(test).getOutput(); } diff --git a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidRunner.java b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidRunner.java index 127adffde31..a95405af339 100644 --- a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidRunner.java +++ b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidRunner.java @@ -19,14 +19,11 @@ package org.jetbrains.kotlin.android.tests; import com.google.common.io.Files; import com.intellij.openapi.util.io.FileUtil; import junit.framework.TestSuite; -import kotlin.io.FilesKt; import org.jetbrains.annotations.NotNull; import org.junit.runner.RunWith; import org.junit.runners.AllTests; import java.io.File; -import java.io.FileWriter; -import java.io.IOException; @RunWith(AllTests.class) public class AndroidRunner { @@ -47,9 +44,6 @@ public class AndroidRunner { public static TestSuite suite() throws Throwable { PathManager pathManager = getPathManager(); - FileUtil.copyDir(new File(pathManager.getAndroidModuleRoot()), new File(pathManager.getTmpFolder())); - writeAndroidSkdToLocalProperties(); - CodegenTestsOnAndroidGenerator.generate(pathManager); System.out.println("Run tests on android..."); @@ -65,12 +59,4 @@ public class AndroidRunner { FileUtil.delete(new File(pathManager.getTmpFolder())); } - private static void writeAndroidSkdToLocalProperties() throws IOException { - String sdkRoot = FilesKt.getInvariantSeparatorsPath(new File(pathManager.getAndroidSdkRoot())); - System.out.println("Writing android sdk to local.properties: " + sdkRoot); - File file = new File(pathManager.getTmpFolder() + "/local.properties"); - try (FileWriter fw = new FileWriter(file)) { - fw.write("sdk.dir=" + sdkRoot); - } - } } diff --git a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidTestGenerator.kt b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidTestGenerator.kt index fbdfd853eca..be40b754114 100644 --- a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidTestGenerator.kt +++ b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/AndroidTestGenerator.kt @@ -32,7 +32,7 @@ private val importPattern = Pattern.compile("import[ |\t]([\\w|]*\\.)") private data class OldPackageAndNew(val oldFqName: FqName, val newFqName: FqName) -internal fun patchFiles( +internal fun patchFilesAndAddTest( testFile: File, testFiles: List, filesHolder: CodegenTestsOnAndroidGenerator.FilesWriter @@ -103,16 +103,16 @@ internal fun patchFiles( file.content = file.content.patchSelfImports(file.newPackage) } - resultFiles.forEach { resultFile -> - if (resultFile.name.endsWith(".kt") || resultFile.name.endsWith(".kts")) { - filesHolder.addFile(resultFile.name, resultFile.content) - } - } - val boxFiles = resultFiles.filter { hasBoxMethod(it.content) } if (boxFiles.size != 1) { println("Several box methods in $testFile") } + + filesHolder.addTest( + resultFiles.filter { resultFile -> resultFile.name.endsWith(".kt") || resultFile.name.endsWith(".kts") }, + TestInfo("", boxFiles.last().newClassId, testFile) + ) + return boxFiles.last().newClassId } diff --git a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidGenerator.kt b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidGenerator.kt index fc16d57edcc..620d71c25a5 100644 --- a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidGenerator.kt +++ b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/CodegenTestsOnAndroidGenerator.kt @@ -5,11 +5,9 @@ package org.jetbrains.kotlin.android.tests -import com.google.common.collect.Lists import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtilRt -import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.cli.common.output.writeAllTo import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment @@ -20,16 +18,13 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.idea.KotlinFileType -import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.* -import org.jetbrains.kotlin.utils.Printer import org.junit.Assert import org.junit.Ignore import java.io.File import java.io.FileWriter import java.io.IOException -import java.util.* data class ConfigurationKey(val kind: ConfigurationKind, val jdkKind: TestJdkKind, val configuration: String) @@ -39,24 +34,31 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager private var currentModuleIndex = 1 - private val generatedTestNames = Lists.newArrayList() - private val pathFilter: String? = System.getProperties().getProperty("kotlin.test.android.path.filter") - private fun generateOutputFiles() { + private val pendingUnitTestGenerators = hashMapOf() + + //keep it globally to avoid test grouping on TC + private val generatedTestNames = hashSetOf() + + fun getFlavorUnitTestFilePath(index: Int): String { + return pathManager.srcFolderInAndroidTmpFolder + "/androidTestKtest$index/java/" + testClassPackage.replace( + ".", + "/" + ) + "/" + testClassName + "$index.java" + } + + private fun prepareAndroidModuleAndGenerateTests() { prepareAndroidModule() - generateAndSave() + generateTestsAndFlavourSuites() } private fun prepareAndroidModule() { + FileUtil.copyDir(File(pathManager.androidModuleRoot), File(pathManager.tmpFolder)) + writeAndroidSkdToLocalProperties(pathManager) + println("Copying kotlin-stdlib.jar and kotlin-reflect.jar in android module...") copyKotlinRuntimeJars() - - println("Check 'libs' folder in tested android module...") - val libsFolderInTestedModule = File(pathManager.libsFolderInAndroidTestedModuleTmpFolder) - if (!libsFolderInTestedModule.exists()) { - libsFolderInTestedModule.mkdirs() - } } private fun copyKotlinRuntimeJars() { @@ -75,38 +77,20 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager ) } - private fun generateAndSave() { + private fun generateTestsAndFlavourSuites() { println("Generating test files...") - val testSourceFilePath = - pathManager.srcFolderInAndroidTmpFolder + "/androidTest/java/" + testClassPackage.replace(".", "/") + "/" + testClassName + ".java" - FileWriter(File(testSourceFilePath).also { it.parentFile.mkdirs() }).use { - val p = Printer(it) - p.println( - """package $testClassPackage; - | - |import $baseTestClassPackage.$baseTestClassName; - | - |/* This class is generated by $generatorName. DO NOT MODIFY MANUALLY */ - |public class $testClassName extends $baseTestClassName { - | - """.trimMargin() - ) - p.pushIndent() + generateTestMethodsForDirectories(File("compiler/testData/codegen/box"), File("compiler/testData/codegen/boxInline")) - generateTestMethodsForDirectories(p, File("compiler/testData/codegen/box"), File("compiler/testData/codegen/boxInline")) - - p.popIndent() - p.println("}") - } + pendingUnitTestGenerators.values.forEach { it.generate() } } - private fun generateTestMethodsForDirectories(p: Printer, vararg dirs: File) { + private fun generateTestMethodsForDirectories(vararg dirs: File) { val holders = mutableMapOf() for (dir in dirs) { val files = dir.listFiles() ?: error("Folder with testData is empty: ${dir.absolutePath}") - processFiles(p, files, holders) + processFiles(files, holders) } holders.values.forEach { @@ -117,7 +101,8 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager internal inner class FilesWriter( private val configuration: CompilerConfiguration ) { - private val rawFiles: MutableList> = ArrayList() + private val rawFiles = arrayListOf() + private val unitTestDescriptions = arrayListOf() private fun shouldWriteFilesOnDisk(): Boolean = rawFiles.size > 300 @@ -139,27 +124,26 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager writeFiles( rawFiles.map { try { - CodegenTestFiles.create(it.first, it.second, environment.project).psiFile + CodegenTestFiles.create(it.name, it.content, environment.project).psiFile } catch (e: Throwable) { - throw RuntimeException("Error on processing ${it.first}:\n${it.second}", e) + throw RuntimeException("Error on processing ${it.name}:\n${it.content}", e) } }, environment ) Disposer.dispose(disposable) rawFiles.clear() - } - - fun addFile(name: String, content: String) { - rawFiles.add(name to content) + unitTestDescriptions.clear() } private fun writeFiles(filesToCompile: List, environment: KotlinCoreEnvironment) { if (filesToCompile.isEmpty()) return - //1000 files per folder, each folder would be jared by build.gradle script - // We can't create one big jar with all test cause dex has problem with memory on teamcity + //3000 files per folder that would be used by flavor to avoid multidex usage, + // each folder would be jared by build.gradle script writtenFilesCount += filesToCompile.size - val outputDir = File(pathManager.getOutputForCompiledFiles(writtenFilesCount / 1000)) + val index = writtenFilesCount / 3000 + val outputDir = File(pathManager.getOutputForCompiledFiles(index)) + assertTrue("Add flavors for ktest$index", index < 2) println("Generating ${filesToCompile.size} files into ${outputDir.name}, configuration: '${environment.configuration}'...") @@ -169,14 +153,25 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager outputDir.mkdirs() } Assert.assertTrue("Cannot create directory for compiled files", outputDir.exists()) - + val unitTestFileWriter = pendingUnitTestGenerators.getOrPut(index) { + UnitTestFileWriter( + getFlavorUnitTestFilePath(index), + index, + generatedTestNames + ) + } + unitTestFileWriter.addTests(unitTestDescriptions) outputFiles.writeAllTo(outputDir) } + + fun addTest(testFiles: List, info: TestInfo) { + rawFiles.addAll(testFiles) + unitTestDescriptions.add(info) + } } @Throws(IOException::class) private fun processFiles( - printer: Printer, files: Array, holders: MutableMap ) { @@ -191,7 +186,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager if (file.isDirectory) { val listFiles = file.listFiles() if (listFiles != null) { - processFiles(printer, listFiles, holders) + processFiles(listFiles, holders) } } else if (FileUtilRt.getExtension(file.name) != KotlinFileType.EXTENSION) { // skip non kotlin files @@ -204,9 +199,8 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager continue } - val fullFileText = FileUtil.loadFile(file, true).let { - it.replace("COROUTINES_PACKAGE", "kotlin.coroutines") - } + val fullFileText = + FileUtil.loadFile(file, true).replace("COROUTINES_PACKAGE", "kotlin.coroutines") if (fullFileText.contains("// WITH_COROUTINES")) { if (fullFileText.contains("kotlin.coroutines.experimental")) continue @@ -237,70 +231,57 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager }) } - val classWithBoxMethod = patchFiles(file, testFiles, filesHolder) ?: continue - - val generatedTestName = generateTestName(file.name) - generateTestMethod( - printer, - generatedTestName, - classWithBoxMethod.asString(), - StringUtil.escapeStringCharacters(file.path) - ) + patchFilesAndAddTest(file, testFiles, filesHolder) } } } } - private fun createTestFiles(file: File, expectedText: String): List = + private fun createTestFiles(file: File, expectedText: String): List = KotlinTestUtils.createTestFiles( file.name, expectedText, - object : KotlinTestUtils.TestFileFactoryNoModules() { - override fun create(fileName: String, text: String, directives: Map): CodegenTestCase.TestFile { - return CodegenTestCase.TestFile(fileName, text) + object : KotlinTestUtils.TestFileFactoryNoModules() { + override fun create(fileName: String, text: String, directives: Map): TestFile { + return TestFile(fileName, text) } }, false, "kotlin.coroutines" ) - - private fun generateTestName(fileName: String): String { - var result = NameUtils.sanitizeAsJavaIdentifier(FileUtil.getNameWithoutExtension(StringUtil.capitalize(fileName))) - - var i = 0 - while (generatedTestNames.contains(result)) { - result += "_" + i++ - } - generatedTestNames.add(result) - return result - } - companion object { - private const val testClassPackage = "org.jetbrains.kotlin.android.tests" - private const val testClassName = "CodegenTestCaseOnAndroid" - private const val baseTestClassPackage = "org.jetbrains.kotlin.android.tests" - private const val baseTestClassName = "AbstractCodegenTestCaseOnAndroid" - private const val generatorName = "CodegenTestsOnAndroidGenerator" + const val testClassPackage = "org.jetbrains.kotlin.android.tests" + const val testClassName = "CodegenTestCaseOnAndroid" + const val baseTestClassPackage = "org.jetbrains.kotlin.android.tests" + const val baseTestClassName = "AbstractCodegenTestCaseOnAndroid" + const val generatorName = "CodegenTestsOnAndroidGenerator" @JvmStatic @Throws(Throwable::class) fun generate(pathManager: PathManager) { - CodegenTestsOnAndroidGenerator(pathManager).generateOutputFiles() + CodegenTestsOnAndroidGenerator(pathManager).prepareAndroidModuleAndGenerateTests() } - private fun hasBoxMethod(text: String): Boolean { return text.contains("fun box()") } - private fun generateTestMethod(p: Printer, testName: String, className: String, filePath: String) { - p.println("public void test$testName() throws Exception {") - p.pushIndent() - p.println("invokeBoxMethod($className.class, \"$filePath\", \"OK\");") - p.popIndent() - p.println("}") - p.println() + @Throws(IOException::class) + internal fun writeAndroidSkdToLocalProperties(pathManager: PathManager) { + val sdkRoot = File(pathManager.androidSdkRoot).invariantSeparatorsPath + println("Writing android sdk to local.properties: $sdkRoot") + val file = File(pathManager.tmpFolder + "/local.properties") + FileWriter(file).use { fw -> fw.write("sdk.dir=$sdkRoot") } + } + + @JvmStatic + fun main(args: Array) { + val tmpFolder = createTempDir() + println("Created temporary folder for android tests: " + tmpFolder.absolutePath) + val rootFolder = File("") + val pathManager = PathManager(rootFolder.absolutePath, tmpFolder.absolutePath) + generate(pathManager) } } } diff --git a/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/UnitTestFileWriter.kt b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/UnitTestFileWriter.kt new file mode 100644 index 00000000000..fa1581963ff --- /dev/null +++ b/compiler/android-tests/tests/org/jetbrains/kotlin/android/tests/UnitTestFileWriter.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.android.tests + +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.NameUtils +import org.jetbrains.kotlin.utils.Printer +import java.io.File +import java.io.FileWriter + +class TestInfo(val name: String, val fqName: FqName, val file: File) + +class UnitTestFileWriter(private val fileName: String, private val index: Int, private val generatedTestNames: MutableSet) { + private val infos = arrayListOf() + + fun addTests(info: List) { + infos.addAll(info) + } + + fun generate() { + FileWriter(File(fileName).also { it.parentFile.mkdirs() }).use { suite -> + val p = Printer(suite) + p.println( + """package ${CodegenTestsOnAndroidGenerator.testClassPackage}; + | + |import ${CodegenTestsOnAndroidGenerator.baseTestClassPackage}.${CodegenTestsOnAndroidGenerator.baseTestClassName}; + | + |/* This class is generated by ${CodegenTestsOnAndroidGenerator.generatorName}. DO NOT MODIFY MANUALLY */ + |public class ${CodegenTestsOnAndroidGenerator.testClassName}$index extends ${CodegenTestsOnAndroidGenerator.baseTestClassName} { + | + """.trimMargin() + ) + p.pushIndent() + + infos.forEach { info -> + generateTestMethod( + p, + generateTestName(info.file.name), + info.fqName.asString(), + StringUtil.escapeStringCharacters(info.file.path) + ) + } + + p.popIndent() + p.println("}") + } + } + + private fun generateTestName(fileName: String): String { + var result = NameUtils.sanitizeAsJavaIdentifier(FileUtil.getNameWithoutExtension(StringUtil.capitalize(fileName))) + + var i = 0 + while (generatedTestNames.contains(result)) { + result += "_" + i++ + } + generatedTestNames.add(result) + return result + } + + private fun generateTestMethod(p: Printer, testName: String, className: String, filePath: String) { + p.println("public void test$testName() throws Exception {") + p.pushIndent() + p.println("invokeBoxMethod($className.class, \"$filePath\", \"OK\");") + p.popIndent() + p.println("}") + p.println() + } + +} \ No newline at end of file