Refactor test framework to process directives in one place

Perform directive processing in base test class
This commit is contained in:
Mikhael Bogdanov
2017-04-13 13:31:25 +02:00
parent c2f275faec
commit df65b3f6b3
10 changed files with 112 additions and 208 deletions
@@ -27,9 +27,6 @@ import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.psi.KtProperty;
import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.TestJdkKind;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.io.File;
@@ -38,45 +35,14 @@ import java.util.ArrayList;
import java.util.List;
public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {
private boolean addRuntime = false;
private boolean addReflect = false;
@Override
protected void doMultiFileTest(@NotNull File wholeFile, @NotNull List<TestFile> files, @Nullable File javaFilesDir) throws Exception {
TestJdkKind jdkKind = getJdkKind(files);
List<String> javacOptions = new ArrayList<>(0);
for (TestFile file : files) {
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_RUNTIME")) {
addRuntime = true;
}
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_REFLECT")) {
addReflect = true;
}
javacOptions.addAll(InTextDirectivesUtils.findListWithPrefixes(file.content, "// JAVAC_OPTIONS:"));
}
configurationKind =
addReflect ? ConfigurationKind.ALL :
addRuntime ? ConfigurationKind.NO_KOTLIN_REFLECT :
ConfigurationKind.JDK_ONLY;
compileAndRun(files, javaFilesDir, jdkKind, javacOptions);
}
@SuppressWarnings("WeakerAccess")
protected void compileAndRun(
@NotNull List<TestFile> files,
@Nullable File javaSourceDir,
@NotNull TestJdkKind jdkKind,
@NotNull List<String> javacOptions
) {
compile(files, javaSourceDir, configurationKind, jdkKind, javacOptions);
compile(files, javaFilesDir);
blackBox();
}
@NotNull
protected static List<String> findJavaSourcesInDirectory(@NotNull File directory) {
List<String> javaFilePaths = new ArrayList<>(1);
@@ -16,68 +16,17 @@
package org.jetbrains.kotlin.codegen
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.KotlinTestUtils.getAnnotationsJar
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.Opcodes.*
import java.io.File
abstract class AbstractBytecodeListingTest : CodegenTestCase() {
protected open val classBuilderFactory: ClassBuilderFactory
get() = ClassBuilderFactories.TEST
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt")
doTest(testRootDisposable, files, javaFilesDir, txtFile, classBuilderFactory, this::setupEnvironment)
}
protected open fun setupEnvironment(environment: KotlinCoreEnvironment) {}
companion object {
@JvmStatic
fun doTest(
disposable: Disposable,
files: List<TestFile>,
javaFilesDir: File?,
txtFile: File,
classBuilderFactory: ClassBuilderFactory,
setupEnvironment: (KotlinCoreEnvironment) -> Unit = {}
) {
val classFileFactory = compileClasses(disposable, files, javaFilesDir, classBuilderFactory, setupEnvironment)
val actualTxt = BytecodeListingTextCollectingVisitor.getText(classFileFactory)
KotlinTestUtils.assertEqualsToFile(txtFile, actualTxt)
}
fun compileClasses(
disposable: Disposable,
files: List<TestFile>,
javaFilesDir: File?,
classBuilderFactory: ClassBuilderFactory,
setupEnvironment: (KotlinCoreEnvironment) -> Unit = {}
): ClassFileFactory {
val addRuntime = files.any { InTextDirectivesUtils.isDirectiveDefined(it.content, "WITH_RUNTIME") }
val addReflect = files.any { InTextDirectivesUtils.isDirectiveDefined(it.content, "WITH_REFLECT") }
val configurationKind = when {
addReflect -> ConfigurationKind.ALL
addRuntime -> ConfigurationKind.NO_KOTLIN_REFLECT
else -> ConfigurationKind.JDK_ONLY
}
val configuration = createConfiguration(
configurationKind, getJdkKind(files), listOf(getAnnotationsJar()), javaFilesDir?.let(::listOf).orEmpty(), files
)
val environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
setupEnvironment(environment)
val testFiles = loadMultiFiles(files, environment.project)
return GenerationUtils.compileFiles(testFiles.psiFiles, environment, classBuilderFactory).factory
}
compile(files, javaFilesDir)
val actualTxt = BytecodeListingTextCollectingVisitor.getText(classFileFactory)
KotlinTestUtils.assertEqualsToFile(txtFile, actualTxt)
}
}
@@ -16,50 +16,29 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
abstract class AbstractDumpDeclarationsTest : CodegenTestCase() {
private lateinit var dumpToFile: File
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val expectedResult = KotlinTestUtils.replaceExtension(wholeFile, "json")
compileAndCompareDump(files, expectedResult)
}
private fun compileAndCompareDump(files: List<TestFile>, expectedResult: File) {
configurationKind = ConfigurationKind.NO_KOTLIN_REFLECT
val dumpToFile = KotlinTestUtils.tmpDirForTest(this).resolve(this.name + ".json")
val configuration =
KotlinTestUtils.newConfiguration(configurationKind, TestJdkKind.MOCK_JDK, KotlinTestUtils.getAnnotationsJar())
configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, dumpToFile.path)
myEnvironment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
loadMultiFiles(files)
compileManyFilesGetDeclarationsDump(myFiles.psiFiles)
dumpToFile = KotlinTestUtils.tmpDirForTest(this).resolve(name + ".json")
compile(files, null)
classFileFactory.generationState.destroy()
KotlinTestUtils.assertEqualsToFile(expectedResult, dumpToFile.readText())
}
private fun compileManyFilesGetDeclarationsDump(files: List<KtFile>) {
val (bindingContext, moduleDescriptor) =
JvmResolveUtil.analyzeAndCheckForErrors(files, myEnvironment).apply(AnalysisResult::throwIfError)
override fun updateConfiguration(configuration: CompilerConfiguration) {
configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, dumpToFile.path)
}
val state = GenerationState(
myEnvironment.project, ClassBuilderFactories.TEST, moduleDescriptor, bindingContext, files, myEnvironment.configuration
)
KotlinCodegenFacade.compileCorrectFiles(state, org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION)
state.destroy()
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind {
return ConfigurationKind.NO_KOTLIN_REFLECT
}
}
@@ -16,21 +16,18 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.KotlinTestUtils.getAnnotationsJar
import org.jetbrains.org.objectweb.asm.Opcodes.*
import java.io.File
import java.util.ArrayList
abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
private companion object {
@@ -40,35 +37,13 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
}
override fun doMultiFileTest(wholeFile: File, files: List<CodegenTestCase.TestFile>, javaFilesDir: File?) {
val jdkKind = CodegenTestCase.getJdkKind(files)
val javacOptions = ArrayList<String>(0)
var addRuntime = false
var addReflect = false
for (file in files) {
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_RUNTIME")) {
addRuntime = true
}
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_REFLECT")) {
addReflect = true
}
if (file.content.contains("// IGNORE_LIGHT_ANALYSIS")) {
return
}
javacOptions.addAll(InTextDirectivesUtils.findListWithPrefixes(file.content, "// JAVAC_OPTIONS:"))
}
configurationKind = if (addReflect)
ConfigurationKind.ALL
else if (addRuntime)
ConfigurationKind.NO_KOTLIN_REFLECT
else
ConfigurationKind.JDK_ONLY
val fullTxt = compileWithFullAnalysis(files, javaFilesDir, jdkKind, javacOptions)
val fullTxt = compileWithFullAnalysis(files, javaFilesDir)
.replace("final enum class", "enum class")
val liteTxt = compileWithLightAnalysis(wholeFile, files, javaFilesDir)
@@ -83,21 +58,23 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
// Fail if this test is not under codegen/box
assert(!relativePath.startsWith(".."))
val classFileFactory = AbstractBytecodeListingTest.compileClasses(
testRootDisposable, files, javaFilesDir, TEST_LIGHT_ANALYSIS,
setupEnvironment = { env -> AnalysisHandlerExtension.registerExtension(env.project, PartialAnalysisHandlerExtension()) }
val configuration = createConfiguration(
configurationKind, getJdkKind(files), listOf(getAnnotationsJar()), javaFilesDir?.let(::listOf).orEmpty(), files
)
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
AnalysisHandlerExtension.registerExtension(environment.project, PartialAnalysisHandlerExtension())
val testFiles = loadMultiFiles(files, environment.project)
val classFileFactory = GenerationUtils.compileFiles(testFiles.psiFiles, environment, TEST_LIGHT_ANALYSIS).factory
return BytecodeListingTextCollectingVisitor.getText(classFileFactory, ListAnalysisFilter(), replaceHash = false)
}
protected fun compileWithFullAnalysis(
files: List<CodegenTestCase.TestFile>,
javaSourceDir: File?,
jdkKind: TestJdkKind,
javacOptions: List<String>
files: List<TestFile>,
javaSourceDir: File?
): String {
compile(files, javaSourceDir, configurationKind, jdkKind, javacOptions)
compile(files, javaSourceDir)
classFileFactory.getClassFiles()
val classInternalNames = classFileFactory.generationState.bindingContext
@@ -399,7 +399,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
protected ClassFileFactory generateClassesInFile() {
if (classFileFactory == null) {
try {
classFileFactory = generateFiles(myEnvironment, myFiles);
classFileFactory = generateFiles(myEnvironment, myFiles, getClassBuilderFactory());
if (DxChecker.RUN_DX_CHECKER) {
DxChecker.check(classFileFactory);
@@ -496,7 +496,15 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
}
}
protected void updateConfiguration(CompilerConfiguration configuration) {
protected void updateConfiguration(@NotNull CompilerConfiguration configuration) {
}
protected ClassBuilderFactory getClassBuilderFactory(){
return ClassBuilderFactories.TEST;
}
protected void setupEnvironment(@NotNull KotlinCoreEnvironment environment) {
}
@@ -511,13 +519,14 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
protected void compile(
@NotNull List<TestFile> files,
@Nullable File javaSourceDir,
@NotNull ConfigurationKind configurationKind,
@NotNull TestJdkKind jdkKind,
@NotNull List<String> javacOptions
@Nullable File javaSourceDir
) {
configurationKind = extractConfigurationKind(files);
List<String> javacOptions = extractJavacOptions(files);
CompilerConfiguration configuration = createConfiguration(
configurationKind, jdkKind,
configurationKind, getJdkKind(files),
Collections.singletonList(getAnnotationsJar()),
ArraysKt.filterNotNull(new File[] {javaSourceDir}),
files
@@ -526,6 +535,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
myEnvironment = KotlinCoreEnvironment.createForTests(
getTestRootDisposable(), configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES
);
setupEnvironment(myEnvironment);
loadMultiFiles(files);
@@ -551,6 +561,32 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
}
}
protected ConfigurationKind extractConfigurationKind(@NotNull List<TestFile> files) {
boolean addRuntime = false;
boolean addReflect = false;
for (TestFile file : files) {
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_RUNTIME")) {
addRuntime = true;
}
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_REFLECT")) {
addReflect = true;
}
}
return addReflect ? ConfigurationKind.ALL :
addRuntime ? ConfigurationKind.NO_KOTLIN_REFLECT :
ConfigurationKind.JDK_ONLY;
}
@NotNull
protected List<String> extractJavacOptions(@NotNull List<TestFile> files) {
List<String> javacOptions = new ArrayList<>(0);
for (TestFile file : files) {
javacOptions.addAll(InTextDirectivesUtils.findListWithPrefixes(file.content, "// JAVAC_OPTIONS:"));
}
return javacOptions;
}
public static class TestFile implements Comparable<TestFile> {
public final String name;
public final String content;
@@ -43,6 +43,15 @@ public class CodegenTestUtil {
return GenerationUtils.compileFiles(files.getPsiFiles(), environment).getFactory();
}
@NotNull
public static ClassFileFactory generateFiles(
@NotNull KotlinCoreEnvironment environment,
@NotNull CodegenTestFiles files,
@NotNull ClassBuilderFactory factory
) {
return GenerationUtils.compileFiles(files.getPsiFiles(), environment, factory).getFactory();
}
public static void assertThrows(@NotNull Method foo, @NotNull Class<? extends Throwable> exceptionClass,
@Nullable Object instance, @NotNull Object... args) throws IllegalAccessException {
boolean caught = false;
@@ -21,14 +21,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.codegen.CodegenTestCase;
import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.test.TestJdkKind;
import org.jetbrains.org.objectweb.asm.*;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.test.InTextDirectivesUtils.findListWithPrefixes;
@@ -57,7 +54,7 @@ public abstract class AbstractWriteFlagsTest extends CodegenTestCase {
protected void doMultiFileTest(
@NotNull File wholeFile, @NotNull List<TestFile> files, @Nullable File javaFilesDir
) throws Exception {
compile(files, null, ConfigurationKind.JDK_ONLY, TestJdkKind.MOCK_JDK, Collections.emptyList());
compile(files, null);
String fileText = FileUtil.loadFile(wholeFile, true);
@@ -16,33 +16,26 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
abstract class AbstractBlackBoxAgainstJavaCodegenTest : AbstractBlackBoxCodegenTest() {
override fun compileAndRun(
files: List<CodegenTestCase.TestFile>,
javaSourceDir: File?,
jdkKind: TestJdkKind,
javacOptions: List<String>
) {
val javaOutputDir = javaSourceDir?.let { directory ->
CodegenTestUtil.compileJava(findJavaSourcesInDirectory(directory), emptyList(), javacOptions)
private lateinit var javaOutputDir: File
override fun doMultiFileTest(wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?) {
javaOutputDir = javaFilesDir!!.let { directory ->
CodegenTestUtil.compileJava(findJavaSourcesInDirectory(directory), emptyList(), extractJavacOptions(files))
}
val configuration = createConfiguration(
ConfigurationKind.ALL, jdkKind,
/* classpath = */ listOf(KotlinTestUtils.getAnnotationsJar(), javaOutputDir),
/* javaSource = */ emptyList(),
files)
super.doMultiFileTest(wholeFile, files, null)
}
myEnvironment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
override fun updateConfiguration(configuration: CompilerConfiguration) {
configuration.addJvmClasspathRoots(listOf(javaOutputDir!!))
}
loadMultiFiles(files)
blackBox()
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind {
return ConfigurationKind.ALL
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -30,17 +31,15 @@ abstract class AbstractKapt3BuilderModeBytecodeShapeTest : CodegenTestCase() {
override fun doMultiFileTest(wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?) {
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt")
KotlinTestUtils.assertEqualsToFile(txtFile, compile(files, javaFilesDir))
compile(files, javaFilesDir)
KotlinTestUtils.assertEqualsToFile(txtFile, BytecodeListingTextCollectingVisitor.getText(classFileFactory))
}
private fun compile(files: List<TestFile>, javaFilesDir: File?): String {
val classFileFactory = AbstractBytecodeListingTest.compileClasses(
testRootDisposable, files, javaFilesDir,
TEST_LIGHT_ANALYSIS,
setupEnvironment = { env -> AnalysisHandlerExtension.registerExtension(env.project, PartialAnalysisHandlerExtension()) }
)
return BytecodeListingTextCollectingVisitor.getText(classFileFactory)
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
AnalysisHandlerExtension.registerExtension(environment.project, PartialAnalysisHandlerExtension())
}
override fun getClassBuilderFactory(): ClassBuilderFactory {
return TEST_LIGHT_ANALYSIS
}
}
@@ -21,11 +21,10 @@ import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
abstract class AbstractBytecodeListingTestForSourceRetention : AbstractBytecodeListingTest() {
override val classBuilderFactory: ClassBuilderFactory
get() {
return if (getTestName(true).contains("withSource", ignoreCase = true))
ClassBuilderFactories.TEST_WITH_SOURCE_RETENTION_ANNOTATIONS
else
ClassBuilderFactories.TEST
}
override fun getClassBuilderFactory(): ClassBuilderFactory {
return if (getTestName(true).contains("withSource", ignoreCase = true))
ClassBuilderFactories.TEST_WITH_SOURCE_RETENTION_ANNOTATIONS
else
ClassBuilderFactories.TEST
}
}