[Test] ReplCompilerJava8Test: Fix lifetime of setUp environment

- For each test, `ReplCompilerJava8Test` effectively created two
  environments: one in `setUp` for pre-compilation and one in `runTest`
  managed by `GenericReplCompiler`. The `setUp` environment is unshared,
  so it wasn't the same as the one managed by `GenericReplCompiler`.
  Because the `setUp` environment was registered with
  `testRootDisposable`, its application and project were effectively
  disposed at the end of the test, together with the other environment.
- Adding a call to `resetApplicationManager` to
  `KotlinCoreEnvironment.disposeApplicationEnvironment` in a previous
  commit caused `ReplCompilerJava8Test` to fail with the following
  sequence:
  1. At the end of a test, `testRootDisposable` is disposed.
  2. The project count disposable registered in
     `getOrCreateApplicationEnvironment` is disposed first. This causes
     the shared application's project count to go to 0 and triggers its
     disposal via `disposeApplicationEnvironment`.
  3. In `disposeApplicationEnvironment`, the application manager's
     application is reset to `null`.
  4. The disposer continues with disposables which were registered for
     the `setUp` environment initially. One of these is
     `PsiManagerImpl`, which disposes `FileManagerImpl`, during whose
     disposal `ApplicationManager.getApplication()` is called. Since the
     application was reset, it is now `null` and an NPE occurs.
- The solution disposes the `setUp` environment early so that it cannot
  clash with the shared environment from `GenericReplCompiler`.

^KT-64099
This commit is contained in:
Marco Pennekamp
2023-12-06 23:53:46 +01:00
committed by Space Team
parent 5f6ffc55b8
commit 24a2f72a6b
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.jvm.repl
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.test.testFramework.resetApplicationToNull
import org.junit.Assert
import java.io.File
@@ -59,10 +61,17 @@ class ReplCompilerJava8Test : KtUsefulTestCase() {
loadScriptingPlugin(this)
}
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val res = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
Assert.assertTrue(res)
// The following environment can be disposed right away since it's only needed to compile the bytecode. The test will use a separate
// environment managed by `GenericReplCompiler`.
val disposable = Disposer.newDisposable("Disposable for ${ReplCompilerJava8Test::class.simpleName}.setUp")
try {
val environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val res = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
Assert.assertTrue(res)
} finally {
Disposer.dispose(disposable)
resetApplicationToNull()
}
}
fun testIncompatibleScriptJvmTargetConfig() {
@@ -82,8 +91,7 @@ class ReplCompilerJava8Test : KtUsefulTestCase() {
val result = runTest(configuration)
Assert.assertTrue(result is ReplCompileResult.Error)
Assert.assertTrue((result as ReplCompileResult.Error).message.contains("error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6"))
}
finally {
} finally {
System.clearProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY)
}
}
@@ -99,8 +107,7 @@ class ReplCompilerJava8Test : KtUsefulTestCase() {
System.setProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY, "1.8")
try {
Assert.assertTrue(runTest(configuration) is ReplCompileResult.CompiledClasses)
}
finally {
} finally {
System.clearProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY)
}
}
@@ -113,8 +120,7 @@ class ReplCompilerJava8Test : KtUsefulTestCase() {
private fun runTest(configuration: CompilerConfiguration): ReplCompileResult {
val collector = PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false)
val replCompiler = GenericReplCompiler(testRootDisposable,
StandardScriptDefinition, configuration, collector)
val replCompiler = GenericReplCompiler(testRootDisposable, StandardScriptDefinition, configuration, collector)
val state = replCompiler.createState()
return replCompiler.compile(state, ReplCodeLine(0, 0, script))