J2K CompileKotlinAgainstCustomBinariesTest: prettify

This commit is contained in:
Alexander Udalov
2017-05-25 16:26:49 +03:00
parent 2ef48bfbca
commit 0899eb9924
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.jvm.compiler package org.jetbrains.kotlin.jvm.compiler
import com.google.common.collect.Iterables
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.cli.AbstractCliTest import org.jetbrains.kotlin.cli.AbstractCliTest
import org.jetbrains.kotlin.cli.WrongBytecodeVersionTest import org.jetbrains.kotlin.cli.WrongBytecodeVersionTest
import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.CLICompiler
@@ -41,21 +38,13 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isObject import org.jetbrains.kotlin.resolve.DescriptorUtils.isObject
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
import org.jetbrains.kotlin.test.* import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.util.DescriptorValidator
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.validateAndCompareDescriptorWithFile import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator.validateAndCompareDescriptorWithFile
import org.jetbrains.kotlin.utils.JsMetadataVersion import org.jetbrains.kotlin.utils.JsMetadataVersion
import org.jetbrains.kotlin.utils.join
import org.jetbrains.kotlin.utils.rethrow
import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.ClassWriter import org.jetbrains.org.objectweb.asm.ClassWriter
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.junit.Assert
import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import java.util.jar.JarEntry import java.util.jar.JarEntry
import java.util.jar.JarFile import java.util.jar.JarFile
import java.util.regex.Pattern import java.util.regex.Pattern
@@ -67,109 +56,77 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
get() = File(TEST_DATA_PATH, getTestName(true)) get() = File(TEST_DATA_PATH, getTestName(true))
private fun getTestDataFileWithExtension(extension: String): File { private fun getTestDataFileWithExtension(extension: String): File {
return File(testDataDirectory, getTestName(true) + "." + extension) return File(testDataDirectory, "${getTestName(true)}.$extension")
}
private fun compileLibrary(sourcePath: String, vararg extraClassPath: File): File {
return compileLibrary(sourcePath, emptyList<String>(), *extraClassPath)
}
private fun compileLibrary(sourcePath: String, additionalOptions: List<String>, vararg extraClassPath: File): File {
val destination = File(tmpdir, sourcePath + ".jar")
compileLibrary(K2JVMCompiler(), sourcePath, destination, additionalOptions, *extraClassPath)
return destination
} }
private fun compileLibrary( private fun compileLibrary(
compiler: CLICompiler<*>, sourcePath: String, destination: File, additionalOptions: List<String>, vararg extraClassPath: File sourcePath: String,
) { compiler: CLICompiler<*> = K2JVMCompiler(),
val output = compileKotlin(compiler, sourcePath, destination, additionalOptions, *extraClassPath) destination: File = File(tmpdir, "$sourcePath.jar"),
Assert.assertEquals(normalizeOutput(Pair("", ExitCode.OK)), normalizeOutput(output)) additionalOptions: List<String> = emptyList(),
vararg extraClassPath: File
): File {
val output = compileKotlin(sourcePath, destination, extraClassPath.toList(), compiler, additionalOptions)
assertEquals(normalizeOutput("" to ExitCode.OK), normalizeOutput(output))
return destination
} }
private fun normalizeOutput(output: Pair<String, ExitCode>): String { private fun normalizeOutput(output: Pair<String, ExitCode>): String {
return AbstractCliTest.getNormalizedCompilerOutput(output.first, output.second, testDataDirectory.path) return AbstractCliTest.getNormalizedCompilerOutput(output.first, output.second, testDataDirectory.path)
.replace(FileUtil.toSystemIndependentName(tmpdir.absolutePath), "\$TMP_DIR$") .replace(FileUtil.toSystemIndependentName(tmpdir.absolutePath), "\$TMP_DIR\$")
} }
@Throws(Exception::class)
private fun doTestWithTxt(vararg extraClassPath: File) { private fun doTestWithTxt(vararg extraClassPath: File) {
val packageView = analyzeFileToPackageView(*extraClassPath) validateAndCompareDescriptorWithFile(
analyzeFileToPackageView(*extraClassPath),
val comparator = AbstractLoadJavaTest.COMPARATOR_CONFIGURATION AbstractLoadJavaTest.COMPARATOR_CONFIGURATION,
.withValidationStrategy(DescriptorValidator.ValidationVisitor.errorTypesAllowed()) getTestDataFileWithExtension("txt")
validateAndCompareDescriptorWithFile(packageView, comparator, getTestDataFileWithExtension("txt")) )
} }
@Throws(IOException::class)
private fun analyzeFileToPackageView(vararg extraClassPath: File): PackageViewDescriptor { private fun analyzeFileToPackageView(vararg extraClassPath: File): PackageViewDescriptor {
val environment = createEnvironment(Arrays.asList(*extraClassPath)) val environment = createEnvironment(extraClassPath.toList())
val result = JvmResolveUtil.analyzeAndCheckForErrors( val ktFile = KotlinTestUtils.loadJetFile(environment.project, getTestDataFileWithExtension("kt"))
KotlinTestUtils.loadJetFile(environment.project, getTestDataFileWithExtension("kt")), environment val result = JvmResolveUtil.analyzeAndCheckForErrors(ktFile, environment)
)
val packageView = result.moduleDescriptor.getPackage(LoadDescriptorUtil.TEST_PACKAGE_FQNAME) return result.moduleDescriptor.getPackage(LoadDescriptorUtil.TEST_PACKAGE_FQNAME).also {
assertFalse("Failed to find package: " + LoadDescriptorUtil.TEST_PACKAGE_FQNAME, packageView.isEmpty()) assertFalse("Failed to find package: " + LoadDescriptorUtil.TEST_PACKAGE_FQNAME, it.isEmpty())
return packageView }
} }
private fun createEnvironment(extraClassPath: List<File>): KotlinCoreEnvironment { private fun createEnvironment(extraClassPath: List<File>): KotlinCoreEnvironment {
val extras = ArrayList<File>() val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, *extraClassPath.toTypedArray())
extras.addAll(extraClassPath)
extras.add(KotlinTestUtils.getAnnotationsJar())
val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK, *extras.toTypedArray())
return KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) return KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
} }
@Throws(IOException::class) private fun analyzeAndGetAllDescriptors(vararg extraClassPath: File): Collection<DeclarationDescriptor> =
private fun analyzeAndGetAllDescriptors(vararg extraClassPath: File): Collection<DeclarationDescriptor> { DescriptorUtils.getAllDescriptors(analyzeFileToPackageView(*extraClassPath).memberScope)
return DescriptorUtils.getAllDescriptors(analyzeFileToPackageView(*extraClassPath).memberScope)
}
@Throws(Exception::class)
private fun compileJava(libraryDir: String): File { private fun compileJava(libraryDir: String): File {
val allJavaFiles = FileUtil.findFilesByMask(JAVA_FILES, File(testDataDirectory, libraryDir)) val allJavaFiles = FileUtil.findFilesByMask(JAVA_FILES, File(testDataDirectory, libraryDir))
val result = File(tmpdir, libraryDir) val result = File(tmpdir, libraryDir)
assert(result.mkdirs()) { "Could not create directory: " + result } assert(result.mkdirs()) { "Could not create directory: $result" }
KotlinTestUtils.compileJavaFiles(allJavaFiles, Arrays.asList("-d", result.path)) KotlinTestUtils.compileJavaFiles(allJavaFiles, listOf("-d", result.path))
return result return result
} }
private fun compileKotlin( private fun compileKotlin(
fileName: String, fileName: String,
output: File, output: File,
vararg classpath: File classpath: List<File> = emptyList(),
compiler: CLICompiler<*> = K2JVMCompiler(),
additionalOptions: List<String> = emptyList()
): Pair<String, ExitCode> { ): Pair<String, ExitCode> {
return compileKotlin(fileName, output, emptyList<String>(), *classpath) val args = mutableListOf<String>()
}
private fun compileKotlin(
fileName: String,
output: File,
additionalOptions: List<String>,
vararg classpath: File
): Pair<String, ExitCode> {
return compileKotlin(K2JVMCompiler(), fileName, output, additionalOptions, *classpath)
}
private fun compileKotlin(
compiler: CLICompiler<*>,
fileName: String,
output: File,
additionalOptions: List<String>,
vararg classpath: File
): Pair<String, ExitCode> {
val args = ArrayList<String>()
val sourceFile = File(testDataDirectory, fileName) val sourceFile = File(testDataDirectory, fileName)
assert(sourceFile.exists()) { "Source file does not exist: " + sourceFile.absolutePath } assert(sourceFile.exists()) { "Source file does not exist: ${sourceFile.absolutePath}" }
args.add(sourceFile.path) args.add(sourceFile.path)
if (compiler is K2JSCompiler) { if (compiler is K2JSCompiler) {
if (classpath.isNotEmpty()) { if (classpath.isNotEmpty()) {
args.add("-libraries") args.add("-libraries")
args.add(join(Arrays.asList(*classpath), File.pathSeparator)) args.add(classpath.joinToString(File.pathSeparator))
} }
args.add("-output") args.add("-output")
args.add(output.path) args.add(output.path)
@@ -178,7 +135,7 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
else if (compiler is K2JVMCompiler) { else if (compiler is K2JVMCompiler) {
if (classpath.isNotEmpty()) { if (classpath.isNotEmpty()) {
args.add("-classpath") args.add("-classpath")
args.add(join(Arrays.asList(*classpath), File.pathSeparator)) args.add(classpath.joinToString(File.pathSeparator))
} }
args.add("-d") args.add("-d")
args.add(output.path) args.add(output.path)
@@ -192,25 +149,22 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
return AbstractCliTest.executeCompilerGrabOutput(compiler, args) return AbstractCliTest.executeCompilerGrabOutput(compiler, args)
} }
@Throws(Exception::class)
private fun doTestBrokenJavaLibrary(libraryName: String, vararg pathsToDelete: String) { private fun doTestBrokenJavaLibrary(libraryName: String, vararg pathsToDelete: String) {
// This function compiles a Java library, then deletes one class file and attempts to compile a Kotlin source against // This function compiles a Java library, then deletes one class file and attempts to compile a Kotlin source against
// this broken library. The expected result is an error message from the compiler // this broken library. The expected result is an error message from the compiler
val library = deletePaths(compileJava(libraryName), *pathsToDelete) val library = deletePaths(compileJava(libraryName), *pathsToDelete)
val output = compileKotlin("source.kt", tmpdir, library) val output = compileKotlin("source.kt", tmpdir, listOf(library))
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
private fun doTestBrokenKotlinLibrary(libraryName: String, vararg pathsToDelete: String) { private fun doTestBrokenKotlinLibrary(libraryName: String, vararg pathsToDelete: String) {
// Analogous to doTestBrokenJavaLibrary, but with a Kotlin library compiled to a JAR file // Analogous to doTestBrokenJavaLibrary, but with a Kotlin library compiled to a JAR file
val library = copyJarFileWithoutEntry(compileLibrary(libraryName), *pathsToDelete) val library = copyJarFileWithoutEntry(compileLibrary(libraryName), *pathsToDelete)
val output = compileKotlin("source.kt", tmpdir, library) val output = compileKotlin("source.kt", tmpdir, listOf(library))
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
private fun doTestKotlinLibraryWithWrongMetadataVersion( private fun doTestKotlinLibraryWithWrongMetadataVersion(
libraryName: String, libraryName: String,
additionalTransformation: ((fieldName: String, value: Any?) -> Any?)?, additionalTransformation: ((fieldName: String, value: Any?) -> Any?)?,
@@ -219,22 +173,19 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
val version = JvmMetadataVersion(42, 0, 0).toArray() val version = JvmMetadataVersion(42, 0, 0).toArray()
val library = transformJar( val library = transformJar(
compileLibrary(libraryName), compileLibrary(libraryName),
{ entryName, bytes -> { _, bytes ->
WrongBytecodeVersionTest.transformMetadataInClassFile(bytes) { fieldName, value -> WrongBytecodeVersionTest.transformMetadataInClassFile(bytes) { fieldName, value ->
if (additionalTransformation != null) { additionalTransformation?.invoke(fieldName, value) ?:
val result = additionalTransformation.invoke(fieldName, value) version.takeIf { JvmAnnotationNames.METADATA_VERSION_FIELD_NAME == fieldName }
if (result != null) return@transformMetadataInClassFile result
}
if (JvmAnnotationNames.METADATA_VERSION_FIELD_NAME == fieldName) version else null
} }
} }
) )
val output = compileKotlin("source.kt", tmpdir, Arrays.asList(*additionalOptions), library) val output = compileKotlin("source.kt", tmpdir, listOf(library), K2JVMCompiler(), additionalOptions.toList())
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
private fun doTestKotlinLibraryWithWrongMetadataVersionJs(libraryName: String, vararg additionalOptions: String) { private fun doTestKotlinLibraryWithWrongMetadataVersionJs(libraryName: String, vararg additionalOptions: String) {
compileLibrary(K2JSCompiler(), libraryName, File(tmpdir, "library.js"), emptyList<String>()) compileLibrary(libraryName, K2JSCompiler(), File(tmpdir, "library.js"), emptyList())
val library = File(tmpdir, "library.meta.js") val library = File(tmpdir, "library.meta.js")
library.writeText(library.readText(Charsets.UTF_8).replace( library.writeText(library.readText(Charsets.UTF_8).replace(
@@ -242,13 +193,10 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
"(" + JsMetadataVersion(42, 0, 0).toInteger() + ", " "(" + JsMetadataVersion(42, 0, 0).toInteger() + ", "
), Charsets.UTF_8) ), Charsets.UTF_8)
val output = compileKotlin( val output = compileKotlin("source.kt", File(tmpdir, "usage.js"), listOf(library), K2JSCompiler(), additionalOptions.toList())
K2JSCompiler(), "source.kt", File(tmpdir, "usage.js"), Arrays.asList(*additionalOptions), library
)
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
private fun doTestPreReleaseKotlinLibrary( private fun doTestPreReleaseKotlinLibrary(
compiler: CLICompiler<*>, compiler: CLICompiler<*>,
libraryName: String, libraryName: String,
@@ -261,7 +209,7 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
try { try {
System.setProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY, "true") System.setProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY, "true")
compileLibrary(compiler, libraryName, destination, emptyList<String>()) compileLibrary(libraryName, compiler, destination)
} }
finally { finally {
System.clearProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY) System.clearProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY)
@@ -270,7 +218,7 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
val output: Pair<String, ExitCode> val output: Pair<String, ExitCode>
try { try {
System.setProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY, "false") System.setProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY, "false")
output = compileKotlin(compiler, "source.kt", usageDestination, Arrays.asList(*additionalOptions), result) output = compileKotlin("source.kt", usageDestination, listOf(result), compiler, additionalOptions.toList())
} }
finally { finally {
System.clearProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY) System.clearProperty(TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY)
@@ -281,23 +229,21 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
@Throws(Exception::class)
fun testRawTypes() { fun testRawTypes() {
KotlinTestUtils.compileJavaFiles( KotlinTestUtils.compileJavaFiles(
listOf(File(testDataDirectory.toString() + "/library/test/A.java")), listOf(File(testDataDirectory.toString() + "/library/test/A.java")),
Arrays.asList("-d", tmpdir.path) listOf("-d", tmpdir.path)
) )
val outputLib = compileKotlin("library/test/lib.kt", tmpdir, tmpdir) val outputLib = compileKotlin("library/test/lib.kt", tmpdir, listOf(tmpdir))
val outputMain = compileKotlin("main.kt", tmpdir, tmpdir) val outputMain = compileKotlin("main.kt", tmpdir, listOf(tmpdir))
KotlinTestUtils.assertEqualsToFile( KotlinTestUtils.assertEqualsToFile(
File(testDataDirectory, "output.txt"), normalizeOutput(outputLib) + "\n" + normalizeOutput(outputMain) File(testDataDirectory, "output.txt"), normalizeOutput(outputLib) + "\n" + normalizeOutput(outputMain)
) )
} }
@Throws(Exception::class)
fun testDuplicateObjectInBinaryAndSources() { fun testDuplicateObjectInBinaryAndSources() {
val allDescriptors = analyzeAndGetAllDescriptors(compileLibrary("library")) val allDescriptors = analyzeAndGetAllDescriptors(compileLibrary("library"))
assertEquals(allDescriptors.toString(), 2, allDescriptors.size) assertEquals(allDescriptors.toString(), 2, allDescriptors.size)
@@ -307,109 +253,92 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
} }
} }
@Throws(Exception::class)
fun testBrokenJarWithNoClassForObject() { fun testBrokenJarWithNoClassForObject() {
val brokenJar = copyJarFileWithoutEntry(compileLibrary("library"), "test/Lol.class") val brokenJar = copyJarFileWithoutEntry(compileLibrary("library"), "test/Lol.class")
val allDescriptors = analyzeAndGetAllDescriptors(brokenJar) val allDescriptors = analyzeAndGetAllDescriptors(brokenJar)
assertEmpty("No descriptors should be found: " + allDescriptors, allDescriptors) assertEmpty("No descriptors should be found: " + allDescriptors, allDescriptors)
} }
@Throws(Exception::class)
fun testSameLibraryTwiceInClasspath() { fun testSameLibraryTwiceInClasspath() {
doTestWithTxt(compileLibrary("library-1"), compileLibrary("library-2")) doTestWithTxt(compileLibrary("library-1"), compileLibrary("library-2"))
} }
@Throws(Exception::class)
fun testMissingEnumReferencedInAnnotationArgument() { fun testMissingEnumReferencedInAnnotationArgument() {
doTestWithTxt(copyJarFileWithoutEntry(compileLibrary("library"), "test/E.class")) doTestWithTxt(copyJarFileWithoutEntry(compileLibrary("library"), "test/E.class"))
} }
@Throws(Exception::class)
fun testNoWarningsOnJavaKotlinInheritance() { fun testNoWarningsOnJavaKotlinInheritance() {
// This test checks that there are no PARAMETER_NAME_CHANGED_ON_OVERRIDE or DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES // This test checks that there are no PARAMETER_NAME_CHANGED_ON_OVERRIDE or DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES
// warnings when subclassing in Kotlin from Java binaries (in case when no parameter names are available for Java classes) // warnings when subclassing in Kotlin from Java binaries (in case when no parameter names are available for Java classes)
KotlinTestUtils.compileJavaFiles( KotlinTestUtils.compileJavaFiles(
listOf(getTestDataFileWithExtension("java")), listOf(getTestDataFileWithExtension("java")),
Arrays.asList("-d", tmpdir.path) listOf("-d", tmpdir.path)
) )
val environment = createEnvironment(listOf(tmpdir)) val environment = createEnvironment(listOf(tmpdir))
val result = JvmResolveUtil.analyze( val ktFile = KotlinTestUtils.loadJetFile(environment.project, getTestDataFileWithExtension("kt"))
KotlinTestUtils.loadJetFile(environment.project, getTestDataFileWithExtension("kt")), environment val result = JvmResolveUtil.analyze(ktFile, environment)
)
result.throwIfError() result.throwIfError()
val bindingContext = result.bindingContext
AnalyzerWithCompilerReport.reportDiagnostics( AnalyzerWithCompilerReport.reportDiagnostics(
bindingContext.diagnostics, result.bindingContext.diagnostics,
PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false) PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
) )
assertEquals("There should be no diagnostics", 0, Iterables.size(bindingContext.diagnostics)) assertEquals("There should be no diagnostics", 0, result.bindingContext.diagnostics.count())
} }
@Throws(Exception::class)
fun testIncompleteHierarchyInJava() { fun testIncompleteHierarchyInJava() {
doTestBrokenJavaLibrary("library", "test/Super.class") doTestBrokenJavaLibrary("library", "test/Super.class")
} }
@Throws(Exception::class)
fun testIncompleteHierarchyInKotlin() { fun testIncompleteHierarchyInKotlin() {
doTestBrokenKotlinLibrary("library", "test/Super.class") doTestBrokenKotlinLibrary("library", "test/Super.class")
} }
@Throws(Exception::class)
fun testMissingDependencySimple() { fun testMissingDependencySimple() {
doTestBrokenKotlinLibrary("library", "a/A.class") doTestBrokenKotlinLibrary("library", "a/A.class")
} }
@Throws(Exception::class)
fun testMissingDependencyDifferentCases() { fun testMissingDependencyDifferentCases() {
doTestBrokenKotlinLibrary("library", "a/A.class") doTestBrokenKotlinLibrary("library", "a/A.class")
} }
@Throws(Exception::class)
fun testMissingDependencyNestedAnnotation() { fun testMissingDependencyNestedAnnotation() {
doTestBrokenKotlinLibrary("library", "a/A\$Anno.class") doTestBrokenKotlinLibrary("library", "a/A\$Anno.class")
} }
@Throws(Exception::class)
fun testMissingDependencyConflictingLibraries() { fun testMissingDependencyConflictingLibraries() {
val library1 = copyJarFileWithoutEntry(compileLibrary("library1"), val library1 = copyJarFileWithoutEntry(compileLibrary("library1"),
"a/A.class", "a/A\$Inner.class", "a/AA.class", "a/AA\$Inner.class") "a/A.class", "a/A\$Inner.class", "a/AA.class", "a/AA\$Inner.class")
val library2 = copyJarFileWithoutEntry(compileLibrary("library2"), val library2 = copyJarFileWithoutEntry(compileLibrary("library2"),
"a/A.class", "a/A\$Inner.class", "a/AA.class", "a/AA\$Inner.class") "a/A.class", "a/A\$Inner.class", "a/AA.class", "a/AA\$Inner.class")
val output = compileKotlin("source.kt", tmpdir, library1, library2) val output = compileKotlin("source.kt", tmpdir, listOf(library1, library2))
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
fun testMissingDependencyJava() { fun testMissingDependencyJava() {
doTestBrokenJavaLibrary("library", "test/Bar.class") doTestBrokenJavaLibrary("library", "test/Bar.class")
} }
@Throws(Exception::class)
fun testMissingDependencyJavaConflictingLibraries() { fun testMissingDependencyJavaConflictingLibraries() {
val library1 = deletePaths(compileJava("library1"), "test/A.class", "test/A\$Inner.class") val library1 = deletePaths(compileJava("library1"), "test/A.class", "test/A\$Inner.class")
val library2 = deletePaths(compileJava("library2"), "test/A.class", "test/A\$Inner.class") val library2 = deletePaths(compileJava("library2"), "test/A.class", "test/A\$Inner.class")
val output = compileKotlin("source.kt", tmpdir, library1, library2) val output = compileKotlin("source.kt", tmpdir, listOf(library1, library2))
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
fun testMissingDependencyJavaNestedAnnotation() { fun testMissingDependencyJavaNestedAnnotation() {
doTestBrokenJavaLibrary("library", "test/A\$Anno.class") doTestBrokenJavaLibrary("library", "test/A\$Anno.class")
} }
@Throws(Exception::class)
fun testReleaseCompilerAgainstPreReleaseLibrary() { fun testReleaseCompilerAgainstPreReleaseLibrary() {
val destination = File(tmpdir, "library.jar") val destination = File(tmpdir, "library.jar")
doTestPreReleaseKotlinLibrary(K2JVMCompiler(), "library", destination, destination, tmpdir) doTestPreReleaseKotlinLibrary(K2JVMCompiler(), "library", destination, destination, tmpdir)
} }
@Throws(Exception::class)
fun testReleaseCompilerAgainstPreReleaseLibraryJs() { fun testReleaseCompilerAgainstPreReleaseLibraryJs() {
doTestPreReleaseKotlinLibrary( doTestPreReleaseKotlinLibrary(
K2JSCompiler(), "library", K2JSCompiler(), "library",
@@ -418,7 +347,6 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
) )
} }
@Throws(Exception::class)
fun testReleaseCompilerAgainstPreReleaseLibrarySkipVersionCheck() { fun testReleaseCompilerAgainstPreReleaseLibrarySkipVersionCheck() {
val destination = File(tmpdir, "library.jar") val destination = File(tmpdir, "library.jar")
doTestPreReleaseKotlinLibrary( doTestPreReleaseKotlinLibrary(
@@ -428,7 +356,6 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
) )
} }
@Throws(Exception::class)
fun testReleaseCompilerAgainstPreReleaseLibraryJsSkipVersionCheck() { fun testReleaseCompilerAgainstPreReleaseLibraryJsSkipVersionCheck() {
doTestPreReleaseKotlinLibrary( doTestPreReleaseKotlinLibrary(
K2JSCompiler(), "library", K2JSCompiler(), "library",
@@ -438,67 +365,49 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
) )
} }
@Throws(Exception::class)
fun testWrongMetadataVersion() { fun testWrongMetadataVersion() {
doTestKotlinLibraryWithWrongMetadataVersion("library", null) doTestKotlinLibraryWithWrongMetadataVersion("library", null)
} }
@Throws(Exception::class)
fun testWrongMetadataVersionJs() { fun testWrongMetadataVersionJs() {
doTestKotlinLibraryWithWrongMetadataVersionJs("library") doTestKotlinLibraryWithWrongMetadataVersionJs("library")
} }
@Throws(Exception::class)
fun testWrongMetadataVersionBadMetadata() { fun testWrongMetadataVersionBadMetadata() {
doTestKotlinLibraryWithWrongMetadataVersion( doTestKotlinLibraryWithWrongMetadataVersion("library", { name, value ->
"library", if (JvmAnnotationNames.METADATA_DATA_FIELD_NAME == name) {
{ name, value -> @Suppress("UNCHECKED_CAST")
if (JvmAnnotationNames.METADATA_DATA_FIELD_NAME == name) { val strings = value as Array<String>
val strings = value as Array<String> strings.map { string ->
for (i in strings.indices) { String(string.toByteArray().map { x -> x xor 42 }.toTypedArray().toByteArray())
val bytes = strings[i].toByteArray() }.toTypedArray()
for (j in bytes.indices) bytes[j] = bytes[j] xor 42 }
strings[i] = String(bytes) else null
} })
return@doTestKotlinLibraryWithWrongMetadataVersion strings
}
null
}
)
} }
@Throws(Exception::class)
fun testWrongMetadataVersionBadMetadata2() { fun testWrongMetadataVersionBadMetadata2() {
doTestKotlinLibraryWithWrongMetadataVersion( doTestKotlinLibraryWithWrongMetadataVersion("library", { name, _ ->
"library", if (JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME == name) arrayOf<String>() else null
{ name, value -> })
if (JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME == name) {
return@doTestKotlinLibraryWithWrongMetadataVersion ArrayUtil.EMPTY_STRING_ARRAY
}
null
}
)
} }
@Throws(Exception::class)
fun testWrongMetadataVersionSkipVersionCheck() { fun testWrongMetadataVersionSkipVersionCheck() {
doTestKotlinLibraryWithWrongMetadataVersion("library", null, "-Xskip-metadata-version-check") doTestKotlinLibraryWithWrongMetadataVersion("library", null, "-Xskip-metadata-version-check")
} }
@Throws(Exception::class)
fun testWrongMetadataVersionJsSkipVersionCheck() { fun testWrongMetadataVersionJsSkipVersionCheck() {
doTestKotlinLibraryWithWrongMetadataVersionJs("library", "-Xskip-metadata-version-check") doTestKotlinLibraryWithWrongMetadataVersionJs("library", "-Xskip-metadata-version-check")
} }
/*test source mapping generation when source info is absent*/ /*test source mapping generation when source info is absent*/
@Throws(Exception::class)
fun testInlineFunWithoutDebugInfo() { fun testInlineFunWithoutDebugInfo() {
compileKotlin("sourceInline.kt", tmpdir) compileKotlin("sourceInline.kt", tmpdir)
val inlineFunClass = File(tmpdir.absolutePath, "test/A.class") val inlineFunClass = File(tmpdir.absolutePath, "test/A.class")
val cw = ClassWriter(Opcodes.ASM5) val cw = ClassWriter(Opcodes.ASM5)
ClassReader(inlineFunClass.readBytes()).accept(object : ClassVisitor(Opcodes.ASM5, cw) { ClassReader(inlineFunClass.readBytes()).accept(object : ClassVisitor(Opcodes.ASM5, cw) {
override fun visitSource(source: String, debug: String) { override fun visitSource(source: String?, debug: String?) {
//skip debug info //skip debug info
} }
}, 0) }, 0)
@@ -508,54 +417,53 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
inlineFunClass.writeBytes(cw.toByteArray()) inlineFunClass.writeBytes(cw.toByteArray())
compileKotlin("source.kt", tmpdir, tmpdir) compileKotlin("source.kt", tmpdir, listOf(tmpdir))
val debugInfo = Ref<String>() var debugInfo: String? = null
val resultFile = File(tmpdir.absolutePath, "test/B.class") val resultFile = File(tmpdir.absolutePath, "test/B.class")
ClassReader(resultFile.readBytes()).accept(object : ClassVisitor(Opcodes.ASM5) { ClassReader(resultFile.readBytes()).accept(object : ClassVisitor(Opcodes.ASM5) {
override fun visitSource(source: String, debug: String) { override fun visitSource(source: String?, debug: String?) {
//skip debug info debugInfo = debug
debugInfo.set(debug)
} }
}, 0) }, 0)
val expected = "SMAP\n" + val expected = """
"source.kt\n" + SMAP
"Kotlin\n" + source.kt
"*S Kotlin\n" + Kotlin
"*F\n" + *S Kotlin
"+ 1 source.kt\n" + *F
"test/B\n" + + 1 source.kt
"*L\n" + test/B
"1#1,13:1\n" + *L
"*E\n" 1#1,13:1
*E
""".trimIndent() + "\n"
if (InlineCodegenUtil.GENERATE_SMAP) { if (InlineCodegenUtil.GENERATE_SMAP) {
assertEquals(expected, debugInfo.get()) assertEquals(expected, debugInfo)
} }
else { else {
assertEquals(null, debugInfo.get()) assertEquals(null, debugInfo)
} }
} }
@Throws(Exception::class)
fun testReplaceAnnotationClassWithInterface() { fun testReplaceAnnotationClassWithInterface() {
val library1 = compileLibrary("library-1") val library1 = compileLibrary("library-1")
val usage = compileLibrary("usage", library1) val usage = compileLibrary("usage", extraClassPath = *arrayOf(library1))
val library2 = compileLibrary("library-2") val library2 = compileLibrary("library-2")
doTestWithTxt(usage, library2) doTestWithTxt(usage, library2)
} }
@Throws(Exception::class)
fun testProhibitNestedClassesByDollarName() { fun testProhibitNestedClassesByDollarName() {
val library = compileLibrary("library") val library = compileLibrary("library")
KotlinTestUtils.compileJavaFiles( KotlinTestUtils.compileJavaFiles(
listOf(File(testDataDirectory.toString() + "/library/test/JavaOuter.java")), listOf(File(testDataDirectory.toString() + "/library/test/JavaOuter.java")),
Arrays.asList("-d", tmpdir.path) listOf("-d", tmpdir.path)
) )
val outputMain = compileKotlin("main.kt", tmpdir, tmpdir, library) val outputMain = compileKotlin("main.kt", tmpdir, listOf(tmpdir, library))
KotlinTestUtils.assertEqualsToFile( KotlinTestUtils.assertEqualsToFile(
File(testDataDirectory, "output.txt"), normalizeOutput(outputMain) File(testDataDirectory, "output.txt"), normalizeOutput(outputMain)
@@ -565,25 +473,22 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
fun testTypeAliasesAreInvisibleInCompatibilityMode() { fun testTypeAliasesAreInvisibleInCompatibilityMode() {
compileKotlin("typeAliases.kt", tmpdir) compileKotlin("typeAliases.kt", tmpdir)
val outputMain = compileKotlin("main.kt", tmpdir, Arrays.asList("-language-version", "1.0"), tmpdir) val outputMain = compileKotlin("main.kt", tmpdir, listOf(tmpdir), K2JVMCompiler(), listOf("-language-version", "1.0"))
KotlinTestUtils.assertEqualsToFile( KotlinTestUtils.assertEqualsToFile(
File(testDataDirectory, "output.txt"), normalizeOutput(outputMain) File(testDataDirectory, "output.txt"), normalizeOutput(outputMain)
) )
} }
@Throws(Exception::class)
fun testInnerClassPackageConflict() { fun testInnerClassPackageConflict() {
compileJava("library") compileJava("library")
FileUtil.copy(File(testDataDirectory, "library/test/Foo/x.txt"), File(testDataDirectory, "library/test/Foo/x.txt").copyTo(File(tmpdir, "library/test/Foo/x.txt"))
File(tmpdir, "library/test/Foo/x.txt"))
MockLibraryUtil.createJarFile(tmpdir, File(tmpdir, "library"), null, "library", false) MockLibraryUtil.createJarFile(tmpdir, File(tmpdir, "library"), null, "library", false)
val jarPath = File(tmpdir, "library.jar") val jarPath = File(tmpdir, "library.jar")
val output = compileKotlin("source.kt", tmpdir, jarPath) val output = compileKotlin("source.kt", tmpdir, listOf(jarPath))
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
fun testInnerClassPackageConflict2() { fun testInnerClassPackageConflict2() {
val library1 = compileJava("library1") val library1 = compileJava("library1")
val library2 = compileJava("library2") val library2 = compileJava("library2")
@@ -600,15 +505,14 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
true true
} }
val output = compileKotlin("source.kt", tmpdir, library1) val output = compileKotlin("source.kt", tmpdir, listOf(library1))
KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output)) KotlinTestUtils.assertEqualsToFile(File(testDataDirectory, "output.txt"), normalizeOutput(output))
} }
@Throws(Exception::class)
fun testWrongInlineTarget() { fun testWrongInlineTarget() {
val library = compileLibrary("library", Arrays.asList("-jvm-target", "1.8")) val library = compileLibrary("library", additionalOptions = listOf("-jvm-target", "1.8"))
val outputMain = compileKotlin("source.kt", tmpdir, library) val outputMain = compileKotlin("source.kt", tmpdir, listOf(library))
KotlinTestUtils.assertEqualsToFile( KotlinTestUtils.assertEqualsToFile(
File(testDataDirectory, "output.txt"), normalizeOutput(outputMain) File(testDataDirectory, "output.txt"), normalizeOutput(outputMain)
@@ -619,51 +523,40 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
private val TEST_DATA_PATH = "compiler/testData/compileKotlinAgainstCustomBinaries/" private val TEST_DATA_PATH = "compiler/testData/compileKotlinAgainstCustomBinaries/"
private val JAVA_FILES = Pattern.compile(".*\\.java$") private val JAVA_FILES = Pattern.compile(".*\\.java$")
private fun copyJarFileWithoutEntry(jarPath: File, vararg entriesToDelete: String): File { private fun copyJarFileWithoutEntry(jarPath: File, vararg entriesToDelete: String): File =
return transformJar(jarPath, { s, bytes -> bytes }, *entriesToDelete) transformJar(jarPath, { _, bytes -> bytes }, entriesToDelete.toSet())
}
private fun transformJar( private fun transformJar(
jarPath: File, jarPath: File,
transformEntry: Function2<String, ByteArray, ByteArray>, transformEntry: (String, ByteArray) -> ByteArray,
vararg entriesToDelete: String entriesToDelete: Set<String> = emptySet()
): File { ): File {
try { val outputFile = File(jarPath.parentFile, "${jarPath.nameWithoutExtension}-after.jar")
val outputFile = File(jarPath.parentFile, FileUtil.getNameWithoutExtension(jarPath) + "-after.jar")
val toDelete = setOf(*entriesToDelete)
JarFile(jarPath).use { jar -> JarFile(jarPath).use { jar ->
ZipOutputStream(BufferedOutputStream(FileOutputStream(outputFile))).use { output -> ZipOutputStream(outputFile.outputStream().buffered()).use { output ->
val enumeration = jar.entries() for (jarEntry in jar.entries()) {
while (enumeration.hasMoreElements()) { val name = jarEntry.name
val jarEntry = enumeration.nextElement() if (name in entriesToDelete) continue
val name = jarEntry.name
if (toDelete.contains(name)) { val bytes = jar.getInputStream(jarEntry).readBytes()
continue val newBytes = if (name.endsWith(".class")) transformEntry(name, bytes) else bytes
} val newEntry = JarEntry(name)
val bytes = FileUtil.loadBytes(jar.getInputStream(jarEntry)) newEntry.size = newBytes.size.toLong()
val newBytes = if (name.endsWith(".class")) transformEntry.invoke(name, bytes) else bytes output.putNextEntry(newEntry)
val newEntry = JarEntry(name) output.write(newBytes)
newEntry.size = newBytes.size.toLong() output.closeEntry()
output.putNextEntry(newEntry)
output.write(newBytes)
output.closeEntry()
}
} }
} }
return outputFile
}
catch (e: IOException) {
throw rethrow(e)
} }
return outputFile
} }
private fun deletePaths(library: File, vararg pathsToDelete: String): File { private fun deletePaths(library: File, vararg pathsToDelete: String): File {
for (pathToDelete in pathsToDelete) { for (pathToDelete in pathsToDelete) {
val fileToDelete = File(library, pathToDelete) val fileToDelete = File(library, pathToDelete)
assert(fileToDelete.delete()) { "Can't delete " + fileToDelete } assert(fileToDelete.delete()) { "Can't delete $fileToDelete" }
} }
return library return library
} }