diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/AutoMute.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/AutoMute.kt new file mode 100644 index 00000000000..04d8587016a --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/AutoMute.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.test + +import org.junit.runner.notification.Failure +import org.junit.runner.notification.RunListener +import org.junit.runner.notification.RunNotifier +import java.io.File + +class AutoMute( + val file: String, + val issue: String +) + +val DO_AUTO_MUTE: AutoMute? by lazy { + val autoMuteFile = File("tests/automute") + if (autoMuteFile.exists()) { + val lines = autoMuteFile.readLines().filter { it.isNotBlank() }.map { it.trim() } + AutoMute( + lines.getOrNull(0) ?: error("A file path is expected in tne first line"), + lines.getOrNull(1) ?: error("An issue description is the second line") + ) + } else { + null + } +} + +fun AutoMute.muteTest(testKey: String) { + val file = File(file) + val lines = file.readLines() + val firstLine = lines[0] // Drop file header + val muted = lines.drop(1).toMutableList() + muted.add("$testKey, $issue") + val newMuted: List = mutableListOf() + firstLine + muted.sorted() + file.writeText(newMuted.joinToString("\n")) +} + +internal fun wrapWithAutoMute(f: () -> Unit, testKey: String): (() -> Unit)? { + val doAutoMute = DO_AUTO_MUTE + if (doAutoMute != null) { + return { + try { + f() + } catch (e: Throwable) { + doAutoMute.muteTest(testKey) + throw e + } + } + } else { + return null + } +} + +internal inline fun RunNotifier.withAutoMuteListener( + testKey: String, + crossinline run: () -> Unit, +) { + val doAutoMute = DO_AUTO_MUTE + if (doAutoMute != null) { + val autoMuteListener = object : RunListener() { + override fun testFailure(failure: Failure) { + doAutoMute.muteTest(testKey) + super.testFailure(failure) + } + } + + try { + addListener(autoMuteListener) + run() + } finally { + removeListener(autoMuteListener) + } + } else { + run() + } +} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt index 383a3a73ede..13b57d037cb 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt @@ -9,8 +9,6 @@ import junit.framework.TestCase import org.jetbrains.kotlin.test.mutes.* import org.junit.internal.runners.statements.InvokeMethod import org.junit.runner.Runner -import org.junit.runner.notification.Failure -import org.junit.runner.notification.RunListener import org.junit.runner.notification.RunNotifier import org.junit.runners.model.FrameworkMethod import org.junit.runners.model.Statement @@ -20,61 +18,63 @@ import org.junit.runners.parameterized.TestWithParameters private val SKIP_MUTED_TESTS = java.lang.Boolean.getBoolean("org.jetbrains.kotlin.skip.muted.tests") -private fun isMutedInDatabase(testCase: TestCase): Boolean { - return isMutedInDatabase(testCase.javaClass, testCase.name) -} - private fun isMutedInDatabase(testClass: Class<*>, methodKey: String): Boolean { val mutedTest = mutedSet.mutedTest(testClass, methodKey) return mutedTest != null && (if (SKIP_MUTED_TESTS) !mutedTest.hasFailFile else mutedTest.isFlaky) } -private fun getMutedTest(testCase: TestCase): MutedTest? { - return getMutedTest(testCase.javaClass, testCase.name) +private fun isMutedInDatabaseWithLog(testClass: Class<*>, methodKey: String): Boolean { + val mutedInDatabase = isMutedInDatabase(testClass, methodKey) + + if (mutedInDatabase) { + System.err.println(mutedMessage(testClass, methodKey)) + } + + return mutedInDatabase +} + +private fun isPresentedInDatabaseWithoutFailMarker(mutedTest: MutedTest?): Boolean { + return mutedTest != null && !mutedTest.hasFailFile } internal fun wrapWithMuteInDatabase(testCase: TestCase, f: () -> Unit): (() -> Unit)? { - if (isMutedInDatabase(testCase)) { - return { - System.err.println(mutedMessage(testKey(testCase))) - } - } + val testClass = testCase.javaClass + val methodKey = testCase.name - val mutedTest = getMutedTest(testCase) - if (mutedTest != null && !mutedTest.hasFailFile) { + val mutedTest = getMutedTest(testClass, methodKey) + val testKey = testKey(testClass, methodKey) + + if (isMutedInDatabase(testClass, methodKey)) { + return { + System.err.println(mutedMessage(testClass, methodKey)) + } + } else if (isPresentedInDatabaseWithoutFailMarker(mutedTest)) { return { - val testKey = testKey(testCase) invertMutedTestResultWithLog(f, testKey) } } else { - val doAutoMute = DO_AUTO_MUTE ?: return null - return { - try { - f() - } catch (e: Throwable) { - doAutoMute.muteTest(testKey(testCase)) - throw e - } - } + return wrapWithAutoMute(f, testKey) } - - } -private fun mutedMessage(key: String) = "MUTED TEST: $key" +private fun mutedMessage(klass: Class<*>, methodKey: String) = "MUTED TEST: ${testKey(klass, methodKey)}" private fun testKey(klass: Class<*>, methodKey: String) = "${klass.canonicalName}.$methodKey" -private fun testKey(testCase: TestCase) = testKey(testCase::class.java, testCase.name) class RunnerFactoryWithMuteInDatabase : ParametersRunnerFactory { override fun createRunnerForTestWithParameters(testWithParameters: TestWithParameters?): Runner { return object : BlockJUnit4ClassRunnerWithParameters(testWithParameters) { override fun isIgnored(child: FrameworkMethod): Boolean { - return super.isIgnored(child) || isIgnoredInDatabaseWithLog(child, name) + val methodWithParametersKey = parametrizedMethodKey(child, name) + + return super.isIgnored(child) + || isMutedInDatabaseWithLog(child.declaringClass, child.name) + || isMutedInDatabaseWithLog(child.declaringClass, methodWithParametersKey) } override fun runChild(method: FrameworkMethod, notifier: RunNotifier) { - notifier.withMuteFailureListener(method.declaringClass, parametrizedMethodKey(method, name)) { + val testKey = testKey(method.declaringClass, parametrizedMethodKey(method, name)) + notifier.withAutoMuteListener(testKey) { super.runChild(method, notifier) } } @@ -85,7 +85,7 @@ class RunnerFactoryWithMuteInDatabase : ParametersRunnerFactory { val methodClass = method.declaringClass val methodKey = parametrizedMethodKey(method, name) val mutedTest = getMutedTest(methodClass, methodKey) ?: getMutedTest(methodClass, method.method.name) - if (mutedTest != null && !mutedTest.hasFailFile) { + if (isPresentedInDatabaseWithoutFailMarker(mutedTest)) { val testKey = testKey(methodClass, methodKey) invertMutedTestResultWithLog({ super.evaluate() }, testKey) return @@ -96,6 +96,8 @@ class RunnerFactoryWithMuteInDatabase : ParametersRunnerFactory { } } } + + private fun parametrizedMethodKey(child: FrameworkMethod, parametersName: String) = "${child.method.name}$parametersName" } private fun invertMutedTestResultWithLog(f: () -> Unit, testKey: String) { @@ -106,73 +108,13 @@ private fun invertMutedTestResultWithLog(f: () -> Unit, testKey: String) { println("MUTED TEST STILL FAILS: $testKey") isTestGreen = false } + if (isTestGreen) { System.err.println("SUCCESS RESULT OF MUTED TEST: $testKey") throw Exception("Muted non-flaky test $testKey finished successfully. Please remove it from csv file") } } -private fun parametrizedMethodKey(child: FrameworkMethod, parametersName: String): String { - return child.method.name + parametersName -} - -private inline fun RunNotifier.withMuteFailureListener( - declaredClass: Class<*>, - methodKey: String, - crossinline run: () -> Unit, -) { - val doAutoMute = DO_AUTO_MUTE - if (doAutoMute == null) { - run() - return - } - - val muteFailureListener = object : RunListener() { - override fun testFailure(failure: Failure) { - doAutoMute.muteTest(testKey(declaredClass, methodKey)) - super.testFailure(failure) - } - } - - try { - addListener(muteFailureListener) - run() - } finally { - removeListener(muteFailureListener) - } -} - -fun isIgnoredInDatabaseWithLog(child: FrameworkMethod): Boolean { - if (isMutedInDatabase(child.declaringClass, child.name)) { - System.err.println(mutedMessage(testKey(child.declaringClass, child.name))) - return true - } - return false -} - -fun isIgnoredInDatabaseWithLog(child: FrameworkMethod, parametersName: String): Boolean { - if (isIgnoredInDatabaseWithLog(child)) { - return true - } - - val methodWithParametersKey = parametrizedMethodKey(child, parametersName) - if (isMutedInDatabase(child.declaringClass, methodWithParametersKey)) { - System.err.println(mutedMessage(testKey(child.declaringClass, methodWithParametersKey))) - return true - } - - return false -} - -fun isIgnoredInDatabaseWithLog(testCase: TestCase): Boolean { - if (isMutedInDatabase(testCase)) { - System.err.println(mutedMessage(testKey(testCase))) - return true - } - - return false -} - fun TestCase.runTest(test: () -> Unit) { (wrapWithMuteInDatabase(this, test) ?: test).invoke() } diff --git a/compiler/tests-mutes/src/org/jetbrains/kotlin/test/mutes/AutoMute.kt b/compiler/tests-mutes/src/org/jetbrains/kotlin/test/mutes/AutoMute.kt deleted file mode 100644 index ff3e6d1e2b0..00000000000 --- a/compiler/tests-mutes/src/org/jetbrains/kotlin/test/mutes/AutoMute.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.test.mutes - -import java.io.File - -class AutoMute( - val file: String, - val issue: String -) - -val DO_AUTO_MUTE: AutoMute? by lazy { - val autoMuteFile = File("tests/automute") - if (autoMuteFile.exists()) { - val lines = autoMuteFile.readLines().filter { it.isNotBlank() }.map { it.trim() } - AutoMute( - lines.getOrNull(0) ?: error("A file path is expected in tne first line"), - lines.getOrNull(1) ?: error("An issue description is the second line") - ) - } else { - null - } -} - -fun AutoMute.muteTest(testKey: String) { - val file = File(file) - val lines = file.readLines() - val firstLine = lines[0] // Drop file header - val muted = lines.drop(1).toMutableList() - muted.add("$testKey, $issue") - val newMuted: List = mutableListOf() + firstLine + muted.sorted() - file.writeText(newMuted.joinToString("\n")) -} \ No newline at end of file diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java index d30ecbef165..9c722ebd75c 100644 --- a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java +++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/KotlinCodeInsightTestCase.java @@ -18,13 +18,9 @@ package org.jetbrains.kotlin.idea.test; import com.intellij.codeInsight.CodeInsightTestCase; import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess; -import kotlin.Unit; import org.jetbrains.kotlin.test.KotlinTestUtils; -import org.jetbrains.kotlin.test.MuteWithDatabaseKt; import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest; -import static org.jetbrains.kotlin.test.MuteWithDatabaseKt.isIgnoredInDatabaseWithLog; - /** * Please use KotlinLightCodeInsightFixtureTestCase as the base class for all new tests. */ diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt index da76e3e1ce2..2c26b417088 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt @@ -20,12 +20,9 @@ import com.intellij.testFramework.UsefulTestCase import junit.framework.TestCase import org.jetbrains.kotlin.idea.configuration.KotlinWithLibraryConfigurator.FileState import org.jetbrains.kotlin.idea.framework.KotlinSdkType -import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.* -import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest -import org.jetbrains.kotlin.test.isIgnoredInDatabaseWithLog import org.jetbrains.kotlin.test.runTest import org.jetbrains.kotlin.utils.PathUtil import java.io.File