From 01d3b8d9c4157f5a7d3f584d744102f30466e20b Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 22 Oct 2019 20:39:21 +0300 Subject: [PATCH] Store mute tests database in the code instead of build server --- .../kotlin/test/KotlinTestUtils.java | 6 + .../jetbrains/kotlin/test/muteWithDatabase.kt | 104 ++++++++++++++++++ .../org/jetbrains/kotlin/test/muteWithFile.kt | 6 +- tests/mute.csv | 1 + 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt create mode 100644 tests/mute.csv diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java index 4172781ee7f..bfbddaaca31 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java @@ -30,6 +30,7 @@ import junit.framework.TestCase; import kotlin.Unit; import kotlin.collections.CollectionsKt; import kotlin.collections.SetsKt; +import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -711,6 +712,11 @@ public class KotlinTestUtils { runTestImpl(testWithCustomIgnoreDirective(test, TargetBackend.ANY, IGNORE_BACKEND_DIRECTIVE_PREFIX), testCase, testDataFile); } + public static void runTest(@NotNull TestCase testCase, @NotNull Function0 test) { + //noinspection unchecked + MuteWithDatabaseKt.runTest(testCase, test); + } + // In this test runner version the `testDataFile` parameter is annotated by `TestDataFile`. // So only file paths passed to this parameter will be used in navigation actions, like "Navigate to testdata" and "Related Symbol..." public static void runTest(DoTest test, TargetBackend targetBackend, @TestDataFile String testDataFile) throws Exception { diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt new file mode 100644 index 00000000000..c128c547533 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithDatabase.kt @@ -0,0 +1,104 @@ +/* + * Copyright 2010-2019 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 junit.framework.TestCase +import java.io.File + +private class MutedTest( + val key: String, + val issue: String?, + val hasFailFile: Boolean +) { + val methodName = key.substringAfterLast(".", "").also { + if (it.isEmpty()) throw IllegalArgumentException("Can't get method name") + } + val classNameKey = key.substringBeforeLast(".", "").also { + if (it.isEmpty()) throw IllegalArgumentException("Can't get class name") + } + val simpleClassName = classNameKey.substringAfterLast(".") +} + +private class MutedSet(muted: List) { + // Method name -> Simple class name -> List of muted tests + private val cache: Map>> = + muted + .groupBy { it.methodName } // Method name -> List of muted tests + .mapValues { (_, tests) -> tests.groupBy { it.simpleClassName } } + + fun mutedTest(testCase: TestCase): MutedTest? { + val mutedTests = cache[testCase.name]?.get(testCase.javaClass.simpleName) ?: return null + + return mutedTests.singleOrNull { mutedTest -> + testCase.javaClass.canonicalName.endsWith(mutedTest.classNameKey) + } + } +} + +private fun loadMutedSet(file: File): MutedSet { + if (!file.exists()) { + System.err.println("Can't find mute file: ${file.absolutePath}") + return MutedSet(listOf()) + } + + try { + val testLines = file.readLines() + .asSequence() + .map { it.trim() } + .filter { it.isNotEmpty() } + .toList() + + val mutedTests = testLines.drop(1).map { parseMutedTest(it) } + + return MutedSet(mutedTests) + } catch (ex: Throwable) { + throw ParseError("Couldn't parse file with muted tests: $file", cause = ex) + } +} + +private fun parseMutedTest(str: String): MutedTest { + val components = str.splitToSequence(",").map { it.trim() }.toList() + + val key = components.getOrNull(0) ?: throw ParseError("Test key is absent (1 column): $str") + + val issue = components.getOrNull(1) + + val hasFailFile = when (val stateStr = components.getOrNull(2)) { + "MUTE", "", null -> false + "FAIL" -> true + else -> throw ParseError("Invalid state (`$stateStr`), MUTE, FAIL or empty are expected: $str") + } + + return MutedTest(key, issue, hasFailFile) +} + +private class ParseError(message: String, override val cause: Throwable? = null) : IllegalArgumentException(message) + +private val mutedSet by lazy { loadMutedSet(File("tests/mute.csv")) } + +internal fun isMutedInDatabase(testCase: TestCase): Boolean { + val mutedTest = mutedSet.mutedTest(testCase) + return mutedTest != null && !mutedTest.hasFailFile +} + +internal fun wrapWithMuteInDatabase(testCase: TestCase, f: () -> Unit): () -> Unit { + if (!isMutedInDatabase(testCase)) return f + return { MUTED_DO_TEST_LAMBDA(testCase) } +} + +internal val MUTED_DO_TEST_LAMBDA = { testCase: TestCase -> + System.err.println("MUTED TEST: ${testCase::class.java.name}.${testCase.name}") +} + +internal class MutedDoTest(val testCase: TestCase) : KotlinTestUtils.DoTest { + override fun invoke(filePath: String) { + MUTED_DO_TEST_LAMBDA(testCase) + } +} + +fun TestCase.runTest(test: () -> Unit) { + wrapWithMuteInDatabase(this, test).invoke() +} \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithFile.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithFile.kt index 54b7f9ac6e4..a0549f2200f 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithFile.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/muteWithFile.kt @@ -18,6 +18,10 @@ annotation class MuteExtraSuffix(val value: String = "") @Throws(Exception::class) fun testWithMuteInFile(test: DoTest, testCase: TestCase): DoTest { + if (isMutedInDatabase(testCase)) { + return MutedDoTest(testCase) + } + val extraSuffix = testCase.javaClass.getAnnotation(MuteExtraSuffix::class.java)?.value ?: "" return testWithMuteInFile(test, extraSuffix) } @@ -30,7 +34,7 @@ fun testWithMuteInFile(test: DoTest, extraSuffix: String): DoTest { val isMutedWithFile = isMutedWithFile(testDataFile, extraSuffix) if (isMutedWithFile && !RUN_MUTED_TESTS) { - System.err.println("IGNORED TEST: $filePath") + System.err.println("MUTED TEST: $filePath") return } diff --git a/tests/mute.csv b/tests/mute.csv new file mode 100644 index 00000000000..9fde1154b6e --- /dev/null +++ b/tests/mute.csv @@ -0,0 +1 @@ +Test key, Issue, State (optional: MUTE or FAIL) \ No newline at end of file