Extract classes and related functions of muteWithDatabase to separate module
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.test
|
||||
|
||||
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
|
||||
@@ -16,149 +17,9 @@ import org.junit.runners.model.Statement
|
||||
import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters
|
||||
import org.junit.runners.parameterized.ParametersRunnerFactory
|
||||
import org.junit.runners.parameterized.TestWithParameters
|
||||
import java.io.File
|
||||
|
||||
private class AutoMute(
|
||||
val file: String,
|
||||
val issue: String
|
||||
)
|
||||
|
||||
private val SKIP_MUTED_TESTS = java.lang.Boolean.getBoolean("org.jetbrains.kotlin.skip.muted.tests")
|
||||
|
||||
private 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
|
||||
}
|
||||
}
|
||||
|
||||
private 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<String> = mutableListOf<String>() + firstLine + muted.sorted()
|
||||
file.writeText(newMuted.joinToString("\n"))
|
||||
}
|
||||
|
||||
private class MutedTest(
|
||||
val key: String,
|
||||
@Suppress("unused") val issue: String?,
|
||||
val hasFailFile: Boolean,
|
||||
val isFlaky: Boolean
|
||||
) {
|
||||
val methodKey: String
|
||||
val classNameKey: String
|
||||
val simpleClassName: String
|
||||
|
||||
init {
|
||||
val noQuoteKey = key.replace("`", "")
|
||||
val beforeParamsKey = noQuoteKey.substringBefore("[")
|
||||
val params = noQuoteKey.substringAfterWithDelimiter("[", "")
|
||||
|
||||
methodKey = (beforeParamsKey.substringAfterLast(".", "") + params)
|
||||
.also {
|
||||
if (it.isEmpty()) throw IllegalArgumentException("Can't get method name: '$key'")
|
||||
}
|
||||
|
||||
classNameKey = beforeParamsKey.substringBeforeLast(".", "").also {
|
||||
if (it.isEmpty()) throw IllegalArgumentException("Can't get class name: '$key'")
|
||||
}
|
||||
|
||||
simpleClassName = classNameKey.substringAfterLast(".")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun String.substringAfterWithDelimiter(delimiter: String, missingDelimiterValue: String = this): String {
|
||||
val index = indexOf(delimiter)
|
||||
return if (index == -1) missingDelimiterValue else (delimiter + substring(index + 1, length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MutedSet(muted: List<MutedTest>) {
|
||||
// Method key -> Simple class name -> List of muted tests
|
||||
private val cache: Map<String, Map<String, List<MutedTest>>> =
|
||||
muted
|
||||
.groupBy { it.methodKey } // Method key -> List of muted tests
|
||||
.mapValues { (_, tests) -> tests.groupBy { it.simpleClassName } }
|
||||
|
||||
fun mutedTest(testClass: Class<*>, methodKey: String): MutedTest? {
|
||||
val mutedTests = cache[methodKey]?.get(testClass.simpleName) ?: return null
|
||||
|
||||
return mutedTests.firstOrNull { mutedTest ->
|
||||
testClass.canonicalName.endsWith(mutedTest.classNameKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMutedSet(files: List<File>): MutedSet {
|
||||
return MutedSet(files.flatMap { file -> loadMutedTests(file) })
|
||||
}
|
||||
|
||||
private fun loadMutedTests(file: File): List<MutedTest> {
|
||||
if (!file.exists()) {
|
||||
System.err.println("Can't find mute file: ${file.absolutePath}")
|
||||
return listOf()
|
||||
}
|
||||
|
||||
try {
|
||||
val testLines = file.readLines()
|
||||
.asSequence()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toList()
|
||||
|
||||
return testLines.drop(1).map { parseMutedTest(it) }
|
||||
} catch (ex: Throwable) {
|
||||
throw ParseError("Couldn't parse file with muted tests: $file", cause = ex)
|
||||
}
|
||||
}
|
||||
|
||||
private val COLUMN_PARSE_REGEXP = Regex("\\s*(?:(?:\"((?:[^\"]|\"\")*)\")|([^,]*))\\s*")
|
||||
private val MUTE_LINE_PARSE_REGEXP = Regex("$COLUMN_PARSE_REGEXP,$COLUMN_PARSE_REGEXP,$COLUMN_PARSE_REGEXP,$COLUMN_PARSE_REGEXP")
|
||||
|
||||
private fun parseMutedTest(str: String): MutedTest {
|
||||
val matchResult = MUTE_LINE_PARSE_REGEXP.matchEntire(str) ?: throw ParseError("Can't parse the line: $str")
|
||||
val resultValues = matchResult.groups.filterNotNull()
|
||||
|
||||
val testKey = resultValues[1].value
|
||||
val issue = resultValues[2].value
|
||||
val stateStr = resultValues[3].value
|
||||
val statusStr = resultValues[4].value
|
||||
|
||||
val hasFailFile = when (stateStr) {
|
||||
"MUTE", "" -> false
|
||||
"FAIL" -> true
|
||||
else -> throw ParseError("Invalid state (`$stateStr`), MUTE, FAIL or empty are expected: $str")
|
||||
}
|
||||
val isFlaky = when (statusStr) {
|
||||
"FLAKY" -> true
|
||||
"" -> false
|
||||
else -> throw ParseError("Invalid status (`$statusStr`), FLAKY or empty are expected: $str")
|
||||
}
|
||||
|
||||
return MutedTest(testKey, issue, hasFailFile, isFlaky)
|
||||
}
|
||||
|
||||
private class ParseError(message: String, override val cause: Throwable? = null) : IllegalArgumentException(message)
|
||||
|
||||
private val mutedSet by lazy {
|
||||
loadMutedSet(
|
||||
listOf(
|
||||
File("tests/mute-common.csv"),
|
||||
File("tests/mute-platform.csv")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun isMutedInDatabase(testCase: TestCase): Boolean {
|
||||
return isMutedInDatabase(testCase.javaClass, testCase.name)
|
||||
}
|
||||
@@ -172,10 +33,6 @@ private fun getMutedTest(testCase: TestCase): MutedTest? {
|
||||
return getMutedTest(testCase.javaClass, testCase.name)
|
||||
}
|
||||
|
||||
private fun getMutedTest(testClass: Class<*>, methodKey: String): MutedTest? {
|
||||
return mutedSet.mutedTest(testClass, methodKey)
|
||||
}
|
||||
|
||||
internal fun wrapWithMuteInDatabase(testCase: TestCase, f: () -> Unit): (() -> Unit)? {
|
||||
if (isMutedInDatabase(testCase)) {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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<String> = mutableListOf<String>() + firstLine + muted.sorted()
|
||||
file.writeText(newMuted.joinToString("\n"))
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 MutedSet(muted: List<MutedTest>) {
|
||||
// Method key -> Simple class name -> List of muted tests
|
||||
private val cache: Map<String, Map<String, List<MutedTest>>> =
|
||||
muted
|
||||
.groupBy { it.methodKey } // Method key -> List of muted tests
|
||||
.mapValues { (_, tests) -> tests.groupBy { it.simpleClassName } }
|
||||
|
||||
fun mutedTest(testClass: Class<*>, methodKey: String): MutedTest? {
|
||||
val mutedTests = cache[methodKey]?.get(testClass.simpleName) ?: return null
|
||||
|
||||
return mutedTests.firstOrNull { mutedTest ->
|
||||
testClass.canonicalName.endsWith(mutedTest.classNameKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMutedSet(files: List<File>): MutedSet {
|
||||
return MutedSet(files.flatMap { file -> loadMutedTests(file) })
|
||||
}
|
||||
|
||||
val mutedSet by lazy {
|
||||
loadMutedSet(
|
||||
listOf(
|
||||
File("tests/mute-common.csv"),
|
||||
File("tests/mute-platform.csv")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 MutedTest(
|
||||
val key: String,
|
||||
@Suppress("unused") val issue: String?,
|
||||
val hasFailFile: Boolean,
|
||||
val isFlaky: Boolean
|
||||
) {
|
||||
val methodKey: String
|
||||
val classNameKey: String
|
||||
val simpleClassName: String
|
||||
|
||||
init {
|
||||
val noQuoteKey = key.replace("`", "")
|
||||
val beforeParamsKey = noQuoteKey.substringBefore("[")
|
||||
val params = noQuoteKey.substringAfterWithDelimiter("[", "")
|
||||
|
||||
methodKey = (beforeParamsKey.substringAfterLast(".", "") + params)
|
||||
.also {
|
||||
if (it.isEmpty()) throw IllegalArgumentException("Can't get method name: '$key'")
|
||||
}
|
||||
|
||||
classNameKey = beforeParamsKey.substringBeforeLast(".", "").also {
|
||||
if (it.isEmpty()) throw IllegalArgumentException("Can't get class name: '$key'")
|
||||
}
|
||||
|
||||
simpleClassName = classNameKey.substringAfterLast(".")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun String.substringAfterWithDelimiter(delimiter: String, missingDelimiterValue: String = this): String {
|
||||
val index = indexOf(delimiter)
|
||||
return if (index == -1) missingDelimiterValue else (delimiter + substring(index + 1, length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMutedTest(testClass: Class<*>, methodKey: String): MutedTest? {
|
||||
return mutedSet.mutedTest(testClass, methodKey)
|
||||
}
|
||||
|
||||
internal fun loadMutedTests(file: File): List<MutedTest> {
|
||||
if (!file.exists()) {
|
||||
System.err.println("Can't find mute file: ${file.absolutePath}")
|
||||
return listOf()
|
||||
}
|
||||
|
||||
try {
|
||||
val testLines = file.readLines()
|
||||
.asSequence()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toList()
|
||||
|
||||
return testLines.drop(1).map { parseMutedTest(it) }
|
||||
} catch (ex: Throwable) {
|
||||
throw ParseError("Couldn't parse file with muted tests: $file", cause = ex)
|
||||
}
|
||||
}
|
||||
|
||||
private val COLUMN_PARSE_REGEXP = Regex("\\s*(?:(?:\"((?:[^\"]|\"\")*)\")|([^,]*))\\s*")
|
||||
private val MUTE_LINE_PARSE_REGEXP = Regex("$COLUMN_PARSE_REGEXP,$COLUMN_PARSE_REGEXP,$COLUMN_PARSE_REGEXP,$COLUMN_PARSE_REGEXP")
|
||||
private fun parseMutedTest(str: String): MutedTest {
|
||||
val matchResult = MUTE_LINE_PARSE_REGEXP.matchEntire(str) ?: throw ParseError("Can't parse the line: $str")
|
||||
val resultValues = matchResult.groups.filterNotNull()
|
||||
|
||||
val testKey = resultValues[1].value
|
||||
val issue = resultValues[2].value
|
||||
val stateStr = resultValues[3].value
|
||||
val statusStr = resultValues[4].value
|
||||
|
||||
val hasFailFile = when (stateStr) {
|
||||
"MUTE", "" -> false
|
||||
"FAIL" -> true
|
||||
else -> throw ParseError("Invalid state (`$stateStr`), MUTE, FAIL or empty are expected: $str")
|
||||
}
|
||||
val isFlaky = when (statusStr) {
|
||||
"FLAKY" -> true
|
||||
"" -> false
|
||||
else -> throw ParseError("Invalid status (`$statusStr`), FLAKY or empty are expected: $str")
|
||||
}
|
||||
|
||||
return MutedTest(testKey, issue, hasFailFile, isFlaky)
|
||||
}
|
||||
|
||||
private class ParseError(message: String, override val cause: Throwable? = null) : IllegalArgumentException(message)
|
||||
Reference in New Issue
Block a user