Move common logic from CodegenTestCase to KotlinBaseTest

This commit is contained in:
Mikhail Bogdanov
2020-06-10 14:30:47 +02:00
parent 9d48ecfac3
commit 929bb0e8d1
32 changed files with 247 additions and 240 deletions
@@ -294,7 +294,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
val kind = KotlinBaseTest.extractConfigurationKind(testFiles)
val jdkKind = KotlinBaseTest.getTestJdkKind(testFiles)
val keyConfiguration = CompilerConfiguration()
CodegenTestCase.updateConfigurationByDirectivesInTestFiles(testFiles, keyConfiguration)
KotlinBaseTest.updateConfigurationByDirectivesInTestFiles(testFiles, keyConfiguration)
val key = ConfigurationKey(kind, jdkKind, keyConfiguration.toString())
val compiler = if (isJvm8Target) {
@@ -303,7 +303,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
val filesHolder = holders.getOrPut(key) {
FilesWriter(compiler, KotlinTestUtils.newConfiguration(kind, jdkKind, KotlinTestUtils.getAnnotationsJar()).apply {
println("Creating new configuration by $key")
CodegenTestCase.updateConfigurationByDirectivesInTestFiles(testFiles, this)
KotlinBaseTest.updateConfigurationByDirectivesInTestFiles(testFiles, this)
})
}
@@ -24,7 +24,7 @@ abstract class AbstractCompileKotlinAgainstKlibTest : AbstractBlackBoxCodegenTes
lateinit var klibName: String
lateinit var outputDir: File
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>) {
outputDir = javaSourcesOutputDirectory
@@ -56,6 +56,7 @@ abstract class AbstractCompileKotlinAgainstKlibTest : AbstractBlackBoxCodegenTes
}
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
configuration.put(JVMConfigurationKeys.KLIB_PATHS, listOf(klibName + ".klib"))
}
@@ -21,8 +21,8 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
abstract class AbstractForeignAnnotationsNoAnnotationInClasspathWithPsiClassReadingTest :
AbstractForeignAnnotationsNoAnnotationInClasspathTest() {
override fun performCustomConfiguration(configuration: CompilerConfiguration) {
super.performCustomConfiguration(configuration)
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
configuration.put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, true)
}
}
@@ -44,11 +44,12 @@ abstract class KotlinMultiFileTestWithJava<M : KotlinBaseTest.TestModule, F : Ko
file: File,
files: List<F>
): KotlinCoreEnvironment {
val configuration = KotlinTestUtils.newConfiguration(
val configuration = createConfiguration(
extractConfigurationKind(files),
getTestJdkKind(files),
getClasspath(file),
if (isJavaSourceRootNeeded()) listOf(javaFilesDir) else emptyList()
if (isJavaSourceRootNeeded()) listOf(javaFilesDir) else emptyList(),
files
)
if (isScriptingNeeded(file)) {
loadScriptingPlugin(configuration)
@@ -61,16 +62,12 @@ abstract class KotlinMultiFileTestWithJava<M : KotlinBaseTest.TestModule, F : Ko
// The main difference is the fact that the new class file reading implementation doesn't load parameter names from JDK classes.
configuration.put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, true)
performCustomConfiguration(configuration)
updateConfiguration(configuration)
return createForTests(testRootDisposable, configuration, getEnvironmentConfigFiles())
}
protected open fun isJavaSourceRootNeeded(): Boolean = true
protected open fun performCustomConfiguration(configuration: CompilerConfiguration) {}
protected open fun setupEnvironment(environment: KotlinCoreEnvironment) {}
protected open fun setupEnvironment(
environment: KotlinCoreEnvironment,
testDataFile: File,
@@ -35,6 +35,7 @@ abstract class AbstractBlackBoxAgainstJavaCodegenTest : AbstractBlackBoxCodegenT
}
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
configuration.addJvmClasspathRoot(javaClassesOutputDirectory)
}
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
@@ -26,6 +25,7 @@ abstract class AbstractDumpDeclarationsTest : CodegenTestCase() {
}
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, dumpToFile.path)
}
}
@@ -38,6 +38,7 @@ public abstract class AbstractScriptCodegenTest extends CodegenTestCase {
@Override
protected void updateConfiguration(@NotNull CompilerConfiguration configuration) {
super.updateConfiguration(configuration);
loadScriptingPlugin(configuration);
}
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.codegen;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.testFramework.TestDataFile;
@@ -21,7 +19,6 @@ import org.jetbrains.kotlin.TestsCompilerError;
import org.jetbrains.kotlin.TestsCompiletimeError;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.output.OutputUtilsKt;
@@ -29,14 +26,14 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace;
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot;
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.config.*;
import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.config.JvmTarget;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider;
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper;
import org.jetbrains.kotlin.test.*;
@@ -55,17 +52,13 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt.parseLanguageVersionSettings;
import static org.jetbrains.kotlin.cli.common.output.OutputUtilsKt.writeAllTo;
import static org.jetbrains.kotlin.codegen.CodegenTestUtil.*;
import static org.jetbrains.kotlin.codegen.TestUtilsKt.extractUrls;
@@ -118,192 +111,6 @@ public abstract class CodegenTestCase extends KotlinBaseTest<KotlinBaseTest.Test
);
}
protected void configureTestSpecific(@NotNull CompilerConfiguration configuration, @NotNull List<TestFile> testFiles) {}
@NotNull
protected CompilerConfiguration createConfiguration(
@NotNull ConfigurationKind kind,
@NotNull TestJdkKind jdkKind,
@NotNull List<File> classpath,
@NotNull List<File> javaSource,
@NotNull List<TestFile> testFilesWithConfigurationDirectives
) {
CompilerConfiguration configuration = KotlinTestUtils.newConfiguration(kind, jdkKind, classpath, javaSource);
configuration.put(JVMConfigurationKeys.IR, getBackend().isIR());
updateConfigurationByDirectivesInTestFiles(testFilesWithConfigurationDirectives, configuration, coroutinesPackage, parseDirectivesPerFiles());
updateConfiguration(configuration);
setCustomDefaultJvmTarget(configuration);
configureTestSpecific(configuration, testFilesWithConfigurationDirectives);
return configuration;
}
public static void updateConfigurationByDirectivesInTestFiles(
@NotNull List<TestFile> testFilesWithConfigurationDirectives,
@NotNull CompilerConfiguration configuration
) {
updateConfigurationByDirectivesInTestFiles(testFilesWithConfigurationDirectives, configuration, "", false);
}
private static void updateConfigurationByDirectivesInTestFiles(
@NotNull List<TestFile> testFilesWithConfigurationDirectives,
@NotNull CompilerConfiguration configuration,
@NotNull String coroutinesPackage,
boolean usePreparsedDirectives
) {
LanguageVersionSettings explicitLanguageVersionSettings = null;
boolean disableReleaseCoroutines = false;
boolean includeCompatExperimentalCoroutines = false;
List<String> kotlinConfigurationFlags = new ArrayList<>(0);
for (TestFile testFile : testFilesWithConfigurationDirectives) {
String content = testFile.content;
Directives directives = usePreparsedDirectives ? testFile.directives : KotlinTestUtils.parseDirectives(content);
List<String> flags = directives.listValues("KOTLIN_CONFIGURATION_FLAGS");
if (flags != null) {
kotlinConfigurationFlags.addAll(flags);
}
String targetString = directives.get("JVM_TARGET");
if (targetString != null) {
JvmTarget jvmTarget = JvmTarget.Companion.fromString(targetString);
assert jvmTarget != null : "Unknown target: " + targetString;
configuration.put(JVMConfigurationKeys.JVM_TARGET, jvmTarget);
}
String version = directives.get("LANGUAGE_VERSION");
if (version != null) {
throw new AssertionError(
"Do not use LANGUAGE_VERSION directive in compiler tests because it's prone to limiting the test\n" +
"to a specific language version, which will become obsolete at some point and the test won't check\n" +
"things like feature intersection with newer releases. Use `// !LANGUAGE: [+-]FeatureName` directive instead,\n" +
"where FeatureName is an entry of the enum `LanguageFeature`\n"
);
}
if (directives.contains("COMMON_COROUTINES_TEST")) {
assert !directives.contains("COROUTINES_PACKAGE") : "Must replace COROUTINES_PACKAGE prior to tests compilation";
if (DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.asString().equals(coroutinesPackage)) {
disableReleaseCoroutines = true;
includeCompatExperimentalCoroutines = true;
}
}
if (content.contains(DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.asString())) {
includeCompatExperimentalCoroutines = true;
}
LanguageVersionSettings fileLanguageVersionSettings = parseLanguageVersionSettings(directives);
if (fileLanguageVersionSettings != null) {
assert explicitLanguageVersionSettings == null : "Should not specify !LANGUAGE directive twice";
explicitLanguageVersionSettings = fileLanguageVersionSettings;
}
}
if (disableReleaseCoroutines) {
explicitLanguageVersionSettings = new CompilerTestLanguageVersionSettings(
Collections.singletonMap(LanguageFeature.ReleaseCoroutines, LanguageFeature.State.DISABLED),
ApiVersion.LATEST_STABLE,
LanguageVersion.LATEST_STABLE,
Collections.emptyMap()
);
}
if (includeCompatExperimentalCoroutines) {
JvmContentRootsKt.addJvmClasspathRoot(configuration, ForTestCompileRuntime.coroutinesCompatForTests());
}
if (explicitLanguageVersionSettings != null) {
CommonConfigurationKeysKt.setLanguageVersionSettings(configuration, explicitLanguageVersionSettings);
}
updateConfigurationWithFlags(configuration, kotlinConfigurationFlags);
}
private static final Map<String, Class<?>> FLAG_NAMESPACE_TO_CLASS = ImmutableMap.of(
"CLI", CLIConfigurationKeys.class,
"JVM", JVMConfigurationKeys.class
);
private static final List<Class<?>> FLAG_CLASSES = ImmutableList.of(CLIConfigurationKeys.class, JVMConfigurationKeys.class);
private static final Pattern BOOLEAN_FLAG_PATTERN = Pattern.compile("([+-])(([a-zA-Z_0-9]*)\\.)?([a-zA-Z_0-9]*)");
private static final Pattern CONSTRUCTOR_CALL_NORMALIZATION_MODE_FLAG_PATTERN = Pattern.compile(
"CONSTRUCTOR_CALL_NORMALIZATION_MODE=([a-zA-Z_\\-0-9]*)");
private static final Pattern ASSERTIONS_MODE_FLAG_PATTERN = Pattern.compile("ASSERTIONS_MODE=([a-zA-Z_0-9-]*)");
private static void updateConfigurationWithFlags(@NotNull CompilerConfiguration configuration, @NotNull List<String> flags) {
for (String flag : flags) {
Matcher m = BOOLEAN_FLAG_PATTERN.matcher(flag);
if (m.matches()) {
boolean flagEnabled = !"-".equals(m.group(1));
String flagNamespace = m.group(3);
String flagName = m.group(4);
tryApplyBooleanFlag(configuration, flag, flagEnabled, flagNamespace, flagName);
continue;
}
m = CONSTRUCTOR_CALL_NORMALIZATION_MODE_FLAG_PATTERN.matcher(flag);
if (m.matches()) {
String flagValueString = m.group(1);
JVMConstructorCallNormalizationMode mode = JVMConstructorCallNormalizationMode.fromStringOrNull(flagValueString);
assert mode != null : "Wrong CONSTRUCTOR_CALL_NORMALIZATION_MODE value: " + flagValueString;
configuration.put(JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE, mode);
}
m = ASSERTIONS_MODE_FLAG_PATTERN.matcher(flag);
if (m.matches()) {
String flagValueString = m.group(1);
JVMAssertionsMode mode = JVMAssertionsMode.fromStringOrNull(flagValueString);
assert mode != null : "Wrong ASSERTIONS_MODE value: " + flagValueString;
configuration.put(JVMConfigurationKeys.ASSERTIONS_MODE, mode);
}
}
}
private static void tryApplyBooleanFlag(
@NotNull CompilerConfiguration configuration,
@NotNull String flag,
boolean flagEnabled,
@Nullable String flagNamespace,
@NotNull String flagName
) {
Class<?> configurationKeysClass;
Field configurationKeyField = null;
if (flagNamespace == null) {
for (Class<?> flagClass : FLAG_CLASSES) {
try {
configurationKeyField = flagClass.getField(flagName);
break;
}
catch (Exception ignored) {
}
}
}
else {
configurationKeysClass = FLAG_NAMESPACE_TO_CLASS.get(flagNamespace);
assert configurationKeysClass != null : "Expected [+|-][namespace.]configurationKey, got: " + flag;
try {
configurationKeyField = configurationKeysClass.getField(flagName);
}
catch (Exception e) {
configurationKeyField = null;
}
}
assert configurationKeyField != null : "Expected [+|-][namespace.]configurationKey, got: " + flag;
try {
@SuppressWarnings("unchecked")
CompilerConfigurationKey<Boolean> configurationKey = (CompilerConfigurationKey<Boolean>) configurationKeyField.get(null);
configuration.put(configurationKey, flagEnabled);
}
catch (Exception e) {
assert false : "Expected [+|-][namespace.]configurationKey, got: " + flag;
}
}
@Override
protected void tearDown() throws Exception {
myFiles = null;
@@ -638,19 +445,16 @@ public abstract class CodegenTestCase extends KotlinBaseTest<KotlinBaseTest.Test
return findDeclaredMethodByName(generateFacadeClass(), name);
}
@Override
protected void updateConfiguration(@NotNull CompilerConfiguration configuration) {
setCustomDefaultJvmTarget(configuration);
}
protected ClassBuilderFactory getClassBuilderFactory() {
return ClassBuilderFactories.TEST;
}
protected void setupEnvironment(@NotNull KotlinCoreEnvironment environment) {
}
protected void setCustomDefaultJvmTarget(CompilerConfiguration configuration) {
private static void setCustomDefaultJvmTarget(CompilerConfiguration configuration) {
if (DEFAULT_JVM_TARGET != null) {
JvmTarget customDefaultTarget = JvmTarget.fromString(DEFAULT_JVM_TARGET);
assert customDefaultTarget != null : "Can't construct JvmTarget for " + DEFAULT_JVM_TARGET;
@@ -750,6 +554,8 @@ public abstract class CodegenTestCase extends KotlinBaseTest<KotlinBaseTest.Test
}
}
@NotNull
@Override
protected TargetBackend getBackend() {
return TargetBackend.JVM;
}
@@ -801,9 +607,6 @@ public abstract class CodegenTestCase extends KotlinBaseTest<KotlinBaseTest.Test
return testFiles;
}
protected boolean parseDirectivesPerFiles() {
return false;
}
@NotNull
protected File getJavaSourcesOutputDirectory() {
@@ -8,5 +8,6 @@ package org.jetbrains.kotlin.codegen.debugInformation
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrLocalVariableTest : AbstractLocalVariableTest() {
override fun getBackend(): TargetBackend = TargetBackend.JVM_IR
override val backend: TargetBackend
get() = TargetBackend.JVM_IR
}
@@ -8,5 +8,6 @@ package org.jetbrains.kotlin.codegen.debugInformation
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrSteppingTest : AbstractSteppingTest() {
override fun getBackend(): TargetBackend = TargetBackend.JVM_IR
override val backend: TargetBackend
get() = TargetBackend.JVM_IR
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
abstract class AbstractFirBlackBoxCodegenTest : AbstractIrBlackBoxCodegenTest() {
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
configuration.put(CommonConfigurationKeys.USE_FIR, true)
configuration.put(JVMConfigurationKeys.IR, true)
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractAsmLikeInstructionListingTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrAsmLikeInstructionListingTest : AbstractAsmLikeInstructionListingTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractBlackBoxAgainstJavaCodegenTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrBlackBoxAgainstJavaCodegenTest : AbstractBlackBoxAgainstJavaCodegenTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -20,5 +20,5 @@ import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrBlackBoxCodegenTest : AbstractBlackBoxCodegenTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -20,5 +20,5 @@ import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrBlackBoxInlineCodegenTest : AbstractBlackBoxCodegenTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractBytecodeListingTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrBytecodeListingTest : AbstractBytecodeListingTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractBytecodeTextTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrBytecodeTextTest : AbstractBytecodeTextTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractCheckLocalVariablesTableTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrCheckLocalVariablesTableTest : AbstractCheckLocalVariablesTableTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractCompileKotlinAgainstInlineKotlinTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrCompileKotlinAgainstInlineKotlinTest : AbstractCompileKotlinAgainstInlineKotlinTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.AbstractCompileKotlinAgainstKotlinTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrCompileKotlinAgainstKotlinTest : AbstractCompileKotlinAgainstKotlinTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrWriteFlagsTest : AbstractWriteFlagsTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,5 +9,5 @@ import org.jetbrains.kotlin.jvm.compiler.AbstractWriteSignatureTest
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrWriteSignatureTest : AbstractWriteSignatureTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -5,8 +5,22 @@
package org.jetbrains.kotlin.test
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings
import org.jetbrains.kotlin.checkers.parseLanguageVersionSettings
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.JvmTarget.Companion.fromString
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import java.io.File
import java.lang.reflect.Field
import java.util.*
import java.util.regex.Pattern
abstract class KotlinBaseTest<F : KotlinBaseTest.TestFile> : KtUsefulTestCase() {
@@ -58,6 +72,35 @@ abstract class KotlinBaseTest<F : KotlinBaseTest.TestFile> : KtUsefulTestCase()
return Companion.extractConfigurationKind(files)
}
protected open fun updateConfiguration(configuration: CompilerConfiguration) {}
protected open fun setupEnvironment(environment: KotlinCoreEnvironment) {}
protected open fun parseDirectivesPerFiles() = false
protected open val backend = TargetBackend.ANY
protected open fun configureTestSpecific(configuration: CompilerConfiguration, testFiles: List<TestFile>) {}
protected open fun createConfiguration(
kind: ConfigurationKind,
jdkKind: TestJdkKind,
classpath: List<File?>,
javaSource: List<File?>,
testFilesWithConfigurationDirectives: List<TestFile>
): CompilerConfiguration {
val configuration = KotlinTestUtils.newConfiguration(kind, jdkKind, classpath, javaSource)
configuration.put(JVMConfigurationKeys.IR, backend.isIR)
updateConfigurationByDirectivesInTestFiles(
testFilesWithConfigurationDirectives,
configuration,
coroutinesPackage,
parseDirectivesPerFiles()
)
updateConfiguration(configuration)
configureTestSpecific(configuration, testFilesWithConfigurationDirectives)
return configuration
}
open class TestFile @JvmOverloads constructor(
@JvmField val name: String,
@@ -97,6 +140,161 @@ abstract class KotlinBaseTest<F : KotlinBaseTest.TestFile> : KtUsefulTestCase()
}
companion object {
private val FLAG_NAMESPACE_TO_CLASS: Map<String, Class<*>> = ImmutableMap.of(
"CLI", CLIConfigurationKeys::class.java,
"JVM", JVMConfigurationKeys::class.java
)
private val FLAG_CLASSES: List<Class<*>> = ImmutableList.of(
CLIConfigurationKeys::class.java,
JVMConfigurationKeys::class.java
)
private val BOOLEAN_FLAG_PATTERN = Pattern.compile("([+-])(([a-zA-Z_0-9]*)\\.)?([a-zA-Z_0-9]*)")
private val CONSTRUCTOR_CALL_NORMALIZATION_MODE_FLAG_PATTERN = Pattern.compile(
"CONSTRUCTOR_CALL_NORMALIZATION_MODE=([a-zA-Z_\\-0-9]*)"
)
private val ASSERTIONS_MODE_FLAG_PATTERN = Pattern.compile("ASSERTIONS_MODE=([a-zA-Z_0-9-]*)")
private fun tryApplyBooleanFlag(
configuration: CompilerConfiguration,
flag: String,
flagEnabled: Boolean,
flagNamespace: String?,
flagName: String
) {
val configurationKeysClass: Class<*>?
var configurationKeyField: Field? = null
if (flagNamespace == null) {
for (flagClass in FLAG_CLASSES) {
try {
configurationKeyField = flagClass.getField(flagName)
break
} catch (ignored: java.lang.Exception) {
}
}
} else {
configurationKeysClass = FLAG_NAMESPACE_TO_CLASS[flagNamespace]
assert(configurationKeysClass != null) { "Expected [+|-][namespace.]configurationKey, got: $flag" }
configurationKeyField = try {
configurationKeysClass!!.getField(flagName)
} catch (e: java.lang.Exception) {
null
}
}
assert(configurationKeyField != null) { "Expected [+|-][namespace.]configurationKey, got: $flag" }
try {
val configurationKey = configurationKeyField!![null] as CompilerConfigurationKey<Boolean>
configuration.put(configurationKey, flagEnabled)
} catch (e: java.lang.Exception) {
assert(false) { "Expected [+|-][namespace.]configurationKey, got: $flag" }
}
}
@JvmStatic
fun updateConfigurationByDirectivesInTestFiles1(
testFilesWithConfigurationDirectives: List<TestFile>,
configuration: CompilerConfiguration
) {
updateConfigurationByDirectivesInTestFiles(testFilesWithConfigurationDirectives, configuration, "", false)
}
private fun updateConfigurationByDirectivesInTestFiles(
testFilesWithConfigurationDirectives: List<TestFile>,
configuration: CompilerConfiguration,
coroutinesPackage: String,
usePreparsedDirectives: Boolean
) {
var explicitLanguageVersionSettings: LanguageVersionSettings? = null
var disableReleaseCoroutines = false
var includeCompatExperimentalCoroutines = false
val kotlinConfigurationFlags: MutableList<String> = ArrayList(0)
for (testFile in testFilesWithConfigurationDirectives) {
val content = testFile.content
val directives = if (usePreparsedDirectives) testFile.directives else KotlinTestUtils.parseDirectives(content)
val flags = directives.listValues("KOTLIN_CONFIGURATION_FLAGS")
if (flags != null) {
kotlinConfigurationFlags.addAll(flags)
}
val targetString = directives["JVM_TARGET"]
if (targetString != null) {
val jvmTarget = fromString(targetString)
?: error("Unknown target: $targetString")
configuration.put(JVMConfigurationKeys.JVM_TARGET, jvmTarget)
}
val version = directives["LANGUAGE_VERSION"]
if (version != null) {
throw AssertionError(
"""
Do not use LANGUAGE_VERSION directive in compiler tests because it's prone to limiting the test
to a specific language version, which will become obsolete at some point and the test won't check
things like feature intersection with newer releases. Use `// !LANGUAGE: [+-]FeatureName` directive instead,
where FeatureName is an entry of the enum `LanguageFeature`
""".trimIndent()
)
}
if (directives.contains("COMMON_COROUTINES_TEST")) {
assert(!directives.contains("COROUTINES_PACKAGE")) { "Must replace COROUTINES_PACKAGE prior to tests compilation" }
if (DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.asString() == coroutinesPackage) {
disableReleaseCoroutines = true
includeCompatExperimentalCoroutines = true
}
}
if (content.contains(DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.asString())) {
includeCompatExperimentalCoroutines = true
}
val fileLanguageVersionSettings: LanguageVersionSettings? = parseLanguageVersionSettings(directives)
if (fileLanguageVersionSettings != null) {
assert(explicitLanguageVersionSettings == null) { "Should not specify !LANGUAGE directive twice" }
explicitLanguageVersionSettings = fileLanguageVersionSettings
}
}
if (disableReleaseCoroutines) {
explicitLanguageVersionSettings = CompilerTestLanguageVersionSettings(
Collections.singletonMap(LanguageFeature.ReleaseCoroutines, LanguageFeature.State.DISABLED),
ApiVersion.LATEST_STABLE,
LanguageVersion.LATEST_STABLE, emptyMap()
)
}
if (includeCompatExperimentalCoroutines) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.coroutinesCompatForTests())
}
if (explicitLanguageVersionSettings != null) {
configuration.languageVersionSettings = explicitLanguageVersionSettings
}
updateConfigurationWithFlags(configuration, kotlinConfigurationFlags)
}
private fun updateConfigurationWithFlags(configuration: CompilerConfiguration, flags: List<String>) {
for (flag in flags) {
var m = BOOLEAN_FLAG_PATTERN.matcher(flag)
if (m.matches()) {
val flagEnabled = "-" != m.group(1)
val flagNamespace = m.group(3)
val flagName = m.group(4)
tryApplyBooleanFlag(configuration, flag, flagEnabled, flagNamespace, flagName)
continue
}
m = CONSTRUCTOR_CALL_NORMALIZATION_MODE_FLAG_PATTERN.matcher(flag)
if (m.matches()) {
val flagValueString = m.group(1)
val mode = JVMConstructorCallNormalizationMode.fromStringOrNull(flagValueString)
?: error("Wrong CONSTRUCTOR_CALL_NORMALIZATION_MODE value: $flagValueString")
configuration.put(JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE, mode)
}
m = ASSERTIONS_MODE_FLAG_PATTERN.matcher(flag)
if (m.matches()) {
val flagValueString = m.group(1)
val mode = JVMAssertionsMode.fromStringOrNull(flagValueString)
?: error("Wrong ASSERTIONS_MODE value: $flagValueString")
configuration.put(JVMConfigurationKeys.ASSERTIONS_MODE, mode)
}
}
}
fun extractConfigurationKind(files: List<TestFile>): ConfigurationKind {
var addRuntime = false
var addReflect = false
@@ -37,6 +37,7 @@ abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() {
}
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
if (scriptDefinitions.isNotEmpty()) {
configureScriptDefinitions(
scriptDefinitions, configuration, this::class.java.classLoader, MessageCollector.NONE, defaultJvmScriptingHostConfiguration
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.ir;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.AbstractGenerateNotNullAssertionsTest;
import org.jetbrains.kotlin.test.TargetBackend;
@@ -13,6 +14,7 @@ public class IrGenerateNotNullAssertionsTest extends AbstractGenerateNotNullAsse
doTestNoAssertionsForKotlinFromBinary("noAssertionsForKotlin.kt", "noAssertionsForKotlinMain.kt");
}
@NotNull
@Override
protected TargetBackend getBackend() {
return TargetBackend.JVM_IR;
@@ -8,5 +8,5 @@ package org.jetbrains.kotlin.android.parcel
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractParcelIrBoxTest : AbstractParcelBoxTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.test.TargetBackend
import java.io.File
abstract class AbstractParcelIrBytecodeListingTest : AbstractParcelBytecodeListingTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
override fun getExpectedTextFileName(wholeFile: File): String {
return wholeFile.nameWithoutExtension + ".ir.txt"
@@ -8,5 +8,5 @@ package org.jetbrains.kotlin.android.synthetic.test
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractAndroidIrBoxTest : AbstractAndroidBoxTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -17,8 +17,8 @@ abstract class AbstractFirAllOpenDiagnosticTest : AbstractFirDiagnosticsTest() {
service.registerExtensions(FirAllOpenComponentRegistrar().configure())
}
override fun performCustomConfiguration(configuration: CompilerConfiguration) {
super.performCustomConfiguration(configuration)
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
val jar = File("plugins/fir/fir-plugin-prototype/plugin-annotations/build/libs/plugin-annotations-1.4.255-SNAPSHOT.jar")
if (!jar.exists()) {
throw AssertionError("Jar with annotations does not exist. Please run :plugins:fir:fir-plugin-prototype:plugin-annotations:jar")
@@ -8,5 +8,5 @@ package org.jetbrains.kotlin.kapt3.test
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrKotlinKapt3IntegrationTest : AbstractKotlinKapt3IntegrationTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -12,9 +12,9 @@ Currently Kapt3 only works with the old backend. To enable IR, modify the isIrBa
*/
abstract class AbstractIrClassFileToSourceStubConverterTest : AbstractClassFileToSourceStubConverterTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
abstract class AbstractIrKotlinKaptContextTest : AbstractKotlinKaptContextTest() {
override fun getBackend() = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
}
@@ -19,7 +19,7 @@ abstract class AbstractSerializationIrBytecodeListingTest : AbstractAsmLikeInstr
return wholeFile.nameWithoutExtension + ".ir.txt"
}
override fun getBackend(): TargetBackend = TargetBackend.JVM_IR
override val backend = TargetBackend.JVM_IR
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
SerializationComponentRegistrar.registerExtensions(environment.project)