From de3f096ae1ac95dbe9730c805f12820e5f88f357 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 28 Jan 2015 19:00:55 +0300 Subject: [PATCH] Test classpath order of sources vs library dependencies --- .../testData/classpathOrder/classpathOrder.kt | 12 ++++ .../kotlin/jvm/internal/KObject.java | 7 +++ .../kotlin/test/MockLibraryUtil.java | 35 ++++++++---- .../kotlin/jvm/compiler/ClasspathOrderTest.kt | 57 +++++++++++++++++++ 4 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/classpathOrder/classpathOrder.kt create mode 100644 compiler/testData/classpathOrder/kotlin/jvm/internal/KObject.java create mode 100644 idea/tests/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt diff --git a/compiler/testData/classpathOrder/classpathOrder.kt b/compiler/testData/classpathOrder/classpathOrder.kt new file mode 100644 index 00000000000..ad379c976fd --- /dev/null +++ b/compiler/testData/classpathOrder/classpathOrder.kt @@ -0,0 +1,12 @@ +package test + +import kotlin.jvm.internal.KObject +import kotlin.jvm.internal.Intrinsics + +fun foo(): String { + // This method call should be resolved to kotlin-runtime.jar + val r: String = Intrinsics.stringPlus(":", ")") + + // This method call should be resolved to sources + return KObject.methodWhichDoesNotExistInKotlinRuntime() +} diff --git a/compiler/testData/classpathOrder/kotlin/jvm/internal/KObject.java b/compiler/testData/classpathOrder/kotlin/jvm/internal/KObject.java new file mode 100644 index 00000000000..c75043326b9 --- /dev/null +++ b/compiler/testData/classpathOrder/kotlin/jvm/internal/KObject.java @@ -0,0 +1,7 @@ +package kotlin.jvm.internal; + +public class KObject { + public static String methodWhichDoesNotExistInKotlinRuntime() { + return ":)"; + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/test/MockLibraryUtil.java b/compiler/tests/org/jetbrains/kotlin/test/MockLibraryUtil.java index f64aa720a1f..1843d6bfb07 100644 --- a/compiler/tests/org/jetbrains/kotlin/test/MockLibraryUtil.java +++ b/compiler/tests/org/jetbrains/kotlin/test/MockLibraryUtil.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.test; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.io.ZipUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cli.common.ExitCode; @@ -96,23 +97,14 @@ public class MockLibraryUtil { } // Runs compiler in custom class loader to avoid effects caused by replacing Application with another one created in compiler. - public static void compileKotlin(@NotNull String sourcesPath, @NotNull File outDir, @NotNull String... extraClasspath) { + private static void runCompiler(@NotNull List args) { try { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); Class compilerClass = getCompilerClass(); - Object compilerObject = compilerClass.newInstance(); + Object compiler = compilerClass.newInstance(); Method execMethod = compilerClass.getMethod("exec", PrintStream.class, String[].class); - List classpath = new ArrayList(); - classpath.add(sourcesPath); - Collections.addAll(classpath, extraClasspath); - String newClasspath = StringUtil.join(classpath, File.pathSeparator); - - //noinspection IOResourceOpenedButNotSafelyClosed - Enum invocationResult = (Enum) execMethod.invoke( - compilerObject, new PrintStream(outStream), - new String[] {sourcesPath, "-d", outDir.getAbsolutePath(), "-classpath", newClasspath} - ); + Enum invocationResult = (Enum) execMethod.invoke(compiler, new PrintStream(outStream), ArrayUtil.toStringArray(args)); assertEquals(new String(outStream.toByteArray()), ExitCode.OK.name(), invocationResult.name()); } @@ -121,6 +113,25 @@ public class MockLibraryUtil { } } + public static void compileKotlin(@NotNull String sourcesPath, @NotNull File outDir, @NotNull String... extraClasspath) { + List classpath = new ArrayList(); + classpath.add(sourcesPath); + Collections.addAll(classpath, extraClasspath); + + List args = new ArrayList(); + args.add(sourcesPath); + args.add("-d"); + args.add(outDir.getAbsolutePath()); + args.add("-classpath"); + args.add(StringUtil.join(classpath, File.pathSeparator)); + + runCompiler(args); + } + + public static void compileKotlinModule(@NotNull String modulePath) { + runCompiler(Arrays.asList("-no-stdlib", "-module", modulePath)); + } + @NotNull private static synchronized Class getCompilerClass() throws IOException, ClassNotFoundException { Class compilerClass = compilerClassRef.get(); diff --git a/idea/tests/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt b/idea/tests/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt new file mode 100644 index 00000000000..e00892481a4 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/jvm/compiler/ClasspathOrderTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.jvm.compiler + +import org.jetbrains.kotlin.test.TestCaseWithTmpdir +import org.jetbrains.kotlin.test.JetTestUtils +import org.jetbrains.kotlin.test.MockLibraryUtil +import org.jetbrains.kotlin.modules.KotlinModuleXmlBuilderFactory +import java.io.File +import org.jetbrains.kotlin.utils.PathUtil + +/** + * This test checks that Java classes from sources have higher priority in Kotlin resolution process than classes from binaries. + * To test this, we compile a Kotlin+Java module (in two modes: CLI and module-based) where a runtime Java class was replaced + * with a "newer" version in sources, and check that this class resolves to the one from sources by calling a method absent in the runtime + */ +public class ClasspathOrderTest : TestCaseWithTmpdir() { + class object { + val sourceDir = File(JetTestUtils.getTestDataPathBase() + "/classpathOrder").getAbsoluteFile() + } + + public fun testClasspathOrderForCLI() { + MockLibraryUtil.compileKotlin(sourceDir.getPath(), tmpdir) + } + + public fun testClasspathOrderForModuleScriptBuild() { + val xmlContent = KotlinModuleXmlBuilderFactory.INSTANCE.create().addModule( + "name", + File(tmpdir, "output").getAbsolutePath(), + listOf(sourceDir), + listOf(sourceDir), + listOf(PathUtil.getKotlinPathsForDistDirectory().getRuntimePath()), + listOf(), + false, + setOf() + ).asText().toString() + + val xml = File(tmpdir, "module.xml") + xml.writeText(xmlContent) + + MockLibraryUtil.compileKotlinModule(xml.getAbsolutePath()) + } +}