Reorganize spec tests infrastructure code
- Add the tests mute system for the diagnostic tests - Move the code for the test info parsing to the separate package `parsers` - Unification of the `linked` and `not linked` spec tests - Package structure is refactored - Change the multiline comment format with a test information - Actualize `PrintSpecTestsStatistic` - Other different code improvements
This commit is contained in:
+47
-14
@@ -9,10 +9,16 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.spec.models.AbstractSpecTest
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.ls
|
||||
import org.jetbrains.kotlin.spec.validators.*
|
||||
import org.jetbrains.kotlin.test.*
|
||||
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
abstract class AbstractDiagnosticsTestSpec : AbstractDiagnosticsTest() {
|
||||
companion object {
|
||||
@@ -35,18 +41,22 @@ abstract class AbstractDiagnosticsTestSpec : AbstractDiagnosticsTest() {
|
||||
private const val MODULE_PATH = "compiler/tests-spec"
|
||||
private const val DIAGNOSTICS_TESTDATA_PATH = "$MODULE_PATH/testData/diagnostics"
|
||||
private const val HELPERS_PATH = "$DIAGNOSTICS_TESTDATA_PATH/helpers"
|
||||
private val exceptionPattern =
|
||||
Pattern.compile("""Exception while analyzing expression at \((?<lineNumber>\d+),(?<symbolNumber>\d+)\) in /(?<filename>.*?)$""")
|
||||
}
|
||||
|
||||
private lateinit var testValidator: AbstractSpecTestValidator<out AbstractSpecTest>
|
||||
lateinit var specTest: AbstractSpecTest
|
||||
lateinit var testLinkedType: SpecTestLinkedType
|
||||
|
||||
private var skipDescriptors = true
|
||||
|
||||
private fun checkDirective(directive: String, testFiles: List<TestFile>) =
|
||||
testFiles.any { it.directives.contains(directive) }
|
||||
|
||||
private fun enableDescriptorsGenerationIfNeeded(testDataFile: File) {
|
||||
private fun enableDescriptorsGenerationIfNeeded(testFilePath: String) {
|
||||
skipDescriptors = withoutDescriptorsTestGroups.any {
|
||||
val testGroupAbsolutePath = File("$DIAGNOSTICS_TESTDATA_PATH/$it").absolutePath
|
||||
testDataFile.absolutePath.startsWith(testGroupAbsolutePath)
|
||||
testFilePath.startsWith(testGroupAbsolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,19 +80,37 @@ abstract class AbstractDiagnosticsTestSpec : AbstractDiagnosticsTest() {
|
||||
}
|
||||
|
||||
override fun analyzeAndCheck(testDataFile: File, files: List<TestFile>) {
|
||||
enableDescriptorsGenerationIfNeeded(testDataFile)
|
||||
val testFilePath = testDataFile.canonicalPath
|
||||
|
||||
testValidator = AbstractSpecTestValidator.getInstanceByType(testDataFile)
|
||||
enableDescriptorsGenerationIfNeeded(testFilePath)
|
||||
|
||||
try {
|
||||
testValidator.parseTestInfo()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
Assert.fail(e.description)
|
||||
CommonParser.parseSpecTest(testFilePath, files.associate { Pair(it.ktFile!!.name, it.clearText) }).apply {
|
||||
specTest = first
|
||||
testLinkedType = second
|
||||
}
|
||||
|
||||
testValidator.printTestInfo()
|
||||
println(specTest)
|
||||
|
||||
super.analyzeAndCheck(testDataFile, files)
|
||||
try {
|
||||
super.analyzeAndCheck(testDataFile, files)
|
||||
} catch (e: KotlinExceptionWithAttachments) {
|
||||
val matches = exceptionPattern.matcher(e.message)
|
||||
|
||||
if (!matches.find())
|
||||
Assert.fail(SpecTestValidationFailedReason.UNKNOWN_FRONTEND_EXCEPTION.description)
|
||||
|
||||
val lineNumber = matches.group("lineNumber").toInt()
|
||||
val symbolNumber = matches.group("symbolNumber").toInt()
|
||||
val filename = matches.group("filename")
|
||||
val fileContent = files.find { it.ktFile?.name == filename }!!.clearText
|
||||
val exceptionPosition =
|
||||
fileContent.lines().subList(0, lineNumber).joinToString("\n").length + symbolNumber
|
||||
val testCases = specTest.cases.byRanges[filename]
|
||||
val isExpectedException = testCases!!.floorEntry(exceptionPosition).value.all { it.value.unexpectedBehavior }
|
||||
|
||||
if (!isExpectedException)
|
||||
Assert.fail()
|
||||
}
|
||||
}
|
||||
|
||||
override fun performAdditionalChecksAfterDiagnostics(
|
||||
@@ -93,11 +121,16 @@ abstract class AbstractDiagnosticsTestSpec : AbstractDiagnosticsTest() {
|
||||
moduleBindings: Map<TestModule?, BindingContext>,
|
||||
languageVersionSettingsByModule: Map<TestModule?, LanguageVersionSettings>
|
||||
) {
|
||||
if (testValidator.testInfo.unexpectedBehavior!!) return
|
||||
val diagnosticValidator = try {
|
||||
DiagnosticTestTypeValidator(testFiles, testDataFile, specTest)
|
||||
} catch (e: SpecTestValidationException) {
|
||||
Assert.fail(e.description)
|
||||
return
|
||||
}
|
||||
|
||||
val diagnosticValidator = DiagnosticTestTypeValidator(testFiles)
|
||||
try {
|
||||
testValidator.validateTestType(computedTestType = diagnosticValidator.computeTestType())
|
||||
diagnosticValidator.validatePathConsistency(testLinkedType)
|
||||
diagnosticValidator.validateTestType()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
Assert.fail(e.description)
|
||||
} finally {
|
||||
|
||||
+10
-15
@@ -1226,6 +1226,11 @@ public class DiagnosticsTestSpecGenerated extends AbstractDiagnosticsTestSpec {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/13.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("14.kt")
|
||||
public void test14() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/14.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("15.kt")
|
||||
public void test15() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/neg/15.kt");
|
||||
@@ -1450,6 +1455,11 @@ public class DiagnosticsTestSpecGenerated extends AbstractDiagnosticsTestSpec {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/17.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("19.kt")
|
||||
public void test19() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/19.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("2.kt")
|
||||
public void test2() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/neg/2.kt");
|
||||
@@ -1513,16 +1523,6 @@ public class DiagnosticsTestSpecGenerated extends AbstractDiagnosticsTestSpec {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/pos/2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("3.kt")
|
||||
public void test3() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/pos/3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("4.kt")
|
||||
public void test4() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/pos/4.kt");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInPos() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractBuilder/common/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
@@ -1785,11 +1785,6 @@ public class DiagnosticsTestSpecGenerated extends AbstractDiagnosticsTestSpec {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/pos/1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("2.kt")
|
||||
public void test2() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/pos/2.kt");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInPos() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/pos"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
+11
-17
@@ -5,13 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.packagePattern
|
||||
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration.TESTDATA_PATH
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.spec.validators.AbstractSpecTestValidator
|
||||
import org.jetbrains.kotlin.spec.validators.SpecTestValidationException
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.junit.Assert
|
||||
import java.util.regex.Pattern
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractBlackBoxCodegenTestSpec : AbstractBlackBoxCodegenTest() {
|
||||
companion object {
|
||||
@@ -24,15 +23,13 @@ abstract class AbstractBlackBoxCodegenTestSpec : AbstractBlackBoxCodegenTest() {
|
||||
private val helperDirectives = mapOf(
|
||||
"REFLECT" to "reflect.kt"
|
||||
)
|
||||
private val packagePattern =
|
||||
Pattern.compile("""(?:^|${AbstractSpecTestValidator.lineSeparator})package (?<packageName>.*?)(?:;|${AbstractSpecTestValidator.lineSeparator})""")
|
||||
}
|
||||
|
||||
private fun addPackageDirectiveToHelperFile(helperContent: String, packageName: String?) =
|
||||
helperContent.replace(HELPERS_PACKAGE_VARIABLE, if (packageName == null) "" else "package $packageName")
|
||||
|
||||
private fun includeHelpers(wholeFile: File, files: MutableList<TestFile>) {
|
||||
val fileContent = wholeFile.readText()
|
||||
val fileContent = FileUtil.loadFile(wholeFile, true)
|
||||
val helpersSpecified = InTextDirectivesUtils.findListWithPrefixes(fileContent, HELPERS_DIRECTIVE)
|
||||
val packageName = packagePattern.matcher(fileContent).let {
|
||||
if (it.find()) it.group("packageName") else null
|
||||
@@ -40,7 +37,7 @@ abstract class AbstractBlackBoxCodegenTestSpec : AbstractBlackBoxCodegenTest() {
|
||||
|
||||
helpersSpecified.forEach {
|
||||
if (helperDirectives.contains(it)) {
|
||||
val helperContent = File("$HELPERS_PATH/${helperDirectives[it]}").readText()
|
||||
val helperContent = FileUtil.loadFile(File("$HELPERS_PATH/${helperDirectives[it]}"), true)
|
||||
files.add(
|
||||
TestFile(helperDirectives[it]!!, addPackageDirectiveToHelperFile(helperContent, packageName))
|
||||
)
|
||||
@@ -49,15 +46,12 @@ abstract class AbstractBlackBoxCodegenTestSpec : AbstractBlackBoxCodegenTest() {
|
||||
}
|
||||
|
||||
override fun doMultiFileTest(wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?) {
|
||||
val testValidator = AbstractSpecTestValidator.getInstanceByType(wholeFile)
|
||||
val (specTest, _) = CommonParser.parseSpecTest(
|
||||
wholeFile.canonicalPath,
|
||||
mapOf("main.kt" to FileUtil.loadFile(wholeFile, true))
|
||||
)
|
||||
|
||||
try {
|
||||
testValidator.parseTestInfo()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
Assert.fail(e.description)
|
||||
}
|
||||
|
||||
testValidator.printTestInfo()
|
||||
println(specTest)
|
||||
|
||||
includeHelpers(wholeFile, files)
|
||||
|
||||
|
||||
@@ -5,29 +5,28 @@
|
||||
|
||||
package org.jetbrains.kotlin.parsing
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser
|
||||
import org.jetbrains.kotlin.spec.validators.*
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractParsingTestSpec : AbstractParsingTest() {
|
||||
private lateinit var testValidator: AbstractSpecTestValidator<out AbstractSpecTest>
|
||||
|
||||
override fun doParsingTest(filePath: String) {
|
||||
testValidator = AbstractSpecTestValidator.getInstanceByType(filePath)
|
||||
val (specTest, testLinkedType) = CommonParser.parseSpecTest(
|
||||
filePath,
|
||||
mapOf("main.kt" to FileUtil.loadFile(File(filePath), true))
|
||||
)
|
||||
|
||||
println(specTest)
|
||||
|
||||
super.doParsingTest(filePath, CommonParser::testInfoFilter)
|
||||
|
||||
val psiTestValidator = ParsingTestTypeValidator(myFile, File(filePath), specTest)
|
||||
|
||||
try {
|
||||
testValidator.parseTestInfo()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
Assert.fail(e.description)
|
||||
}
|
||||
|
||||
testValidator.printTestInfo()
|
||||
|
||||
super.doParsingTest(filePath, testValidator::testInfoFilter)
|
||||
|
||||
if (testValidator.testInfo.unexpectedBehavior!!) return
|
||||
|
||||
try {
|
||||
testValidator.validateTestType(computedTestType = ParsingTestTypeValidator.computeTestType(myFile))
|
||||
psiTestValidator.validatePathConsistency(testLinkedType)
|
||||
psiTestValidator.validateTestType()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
Assert.fail(e.description)
|
||||
}
|
||||
|
||||
+10
@@ -228,6 +228,16 @@ public class ParsingTestSpecGenerated extends AbstractParsingTestSpec {
|
||||
KotlinTestUtils.runTest(this::doParsingTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("1.1.kt")
|
||||
public void test1_1() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/psi/linked/constant-literals/boolean-literals/p-1/pos/1.1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("1.2.kt")
|
||||
public void test1_2() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/psi/linked/constant-literals/boolean-literals/p-1/pos/1.2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("2.1.kt")
|
||||
public void test2_1() throws Exception {
|
||||
runTest("compiler/tests-spec/testData/psi/linked/constant-literals/boolean-literals/p-1/pos/2.1.kt");
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec
|
||||
|
||||
import org.jetbrains.kotlin.spec.models.LinkedSpecTestFileInfoElementType
|
||||
import org.jetbrains.kotlin.spec.models.NotLinkedSpecTestFileInfoElementType
|
||||
import org.jetbrains.kotlin.spec.parsers.BasePatterns
|
||||
import org.jetbrains.kotlin.spec.parsers.LinkedSpecTestPatterns
|
||||
import org.jetbrains.kotlin.spec.parsers.NotLinkedSpecTestPatterns
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withSpaces
|
||||
import java.util.*
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
typealias TestFiles = Map<String, String>
|
||||
typealias TestCasesByNumbers = MutableMap<Int, SpecTestCase>
|
||||
typealias TestCasesByFiles = MutableMap<String, TestCasesByNumbers>
|
||||
typealias TestCasesByRanges = MutableMap<String, NavigableMap<Int, TestCasesByNumbers>>
|
||||
|
||||
enum class TestType(val type: String) {
|
||||
POSITIVE("pos"),
|
||||
NEGATIVE("neg");
|
||||
|
||||
companion object {
|
||||
private val map = values().associateBy(TestType::type)
|
||||
val joinedValues = values().joinToString("|").withSpaces()
|
||||
|
||||
fun fromValue(type: String) = map[type]
|
||||
}
|
||||
}
|
||||
|
||||
enum class TestArea(val testDataPath: String) {
|
||||
PSI("psi"),
|
||||
DIAGNOSTICS("diagnostics"),
|
||||
CODEGEN_BOX("codegen/box");
|
||||
|
||||
companion object {
|
||||
val joinedValues = values().joinToString("|").withSpaces()
|
||||
}
|
||||
}
|
||||
|
||||
enum class SpecTestLinkedType(
|
||||
val testDataPath: String,
|
||||
val patterns: Lazy<BasePatterns>,
|
||||
val infoElements: Lazy<Array<out SpecTestInfoElementType>>
|
||||
) {
|
||||
LINKED(
|
||||
"linked",
|
||||
lazy { LinkedSpecTestPatterns },
|
||||
lazy { LinkedSpecTestFileInfoElementType.values() }
|
||||
),
|
||||
NOT_LINKED(
|
||||
"notLinked",
|
||||
lazy { NotLinkedSpecTestPatterns },
|
||||
lazy { NotLinkedSpecTestFileInfoElementType.values() }
|
||||
)
|
||||
}
|
||||
|
||||
interface SpecTestInfoElementType {
|
||||
val valuePattern: Pattern?
|
||||
val required: Boolean
|
||||
}
|
||||
|
||||
data class SpecTestInfoElementContent(
|
||||
val content: String,
|
||||
val additionalMatcher: Matcher? = null
|
||||
)
|
||||
|
||||
data class SpecTestCase(
|
||||
var code: String,
|
||||
var ranges: MutableList<IntRange>,
|
||||
var unexpectedBehavior: Boolean,
|
||||
val issues: MutableList<String>?
|
||||
)
|
||||
|
||||
data class SpecTestCasesSet(
|
||||
val byFiles: TestCasesByFiles,
|
||||
val byRanges: TestCasesByRanges,
|
||||
val byNumbers: TestCasesByNumbers
|
||||
)
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.spec.generators.featureinteraction
|
||||
package org.jetbrains.kotlin.spec.generators.templates
|
||||
|
||||
enum class Feature(val config: FeatureTemplatesConfig) {
|
||||
IDENTIFIERS(
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.spec.generators.featureinteraction
|
||||
package org.jetbrains.kotlin.spec.generators.templates
|
||||
|
||||
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration.TESTDATA_PATH
|
||||
import java.io.File
|
||||
+2
-2
@@ -3,10 +3,10 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.spec.generators.featureinteraction
|
||||
package org.jetbrains.kotlin.spec.generators.templates
|
||||
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration.TESTDATA_PATH
|
||||
import org.jetbrains.kotlin.spec.validators.TestArea
|
||||
import java.io.File
|
||||
|
||||
enum class FeatureTemplatesType {
|
||||
+4
-4
@@ -3,11 +3,11 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.spec.generators.featureinteraction
|
||||
package org.jetbrains.kotlin.spec.generators.templates
|
||||
|
||||
import org.jetbrains.kotlin.spec.validators.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.validators.TestArea
|
||||
import org.jetbrains.kotlin.spec.validators.TestType
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
|
||||
enum class SubstitutionTag(val passType: SubstitutionPassType = SubstitutionPassType.FIRST) {
|
||||
DIRECTIVES,
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.spec.generators.featureinteraction
|
||||
package org.jetbrains.kotlin.spec.generators.templates
|
||||
|
||||
import org.jetbrains.kotlin.spec.tasks.generateTests
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.spec.generators.featureinteraction
|
||||
package org.jetbrains.kotlin.spec.generators.templates
|
||||
|
||||
enum class TemplateValidationTransformerType {
|
||||
TRIM_BACKTICKS
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.models
|
||||
|
||||
import org.jetbrains.kotlin.spec.*
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.issuesPattern
|
||||
import org.jetbrains.kotlin.spec.parsers.TestCasePatterns.testCaseNumberPattern
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
typealias SpecTestInfoElements<T> = Map<T, SpecTestInfoElementContent>
|
||||
|
||||
enum class CommonInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
UNEXPECTED_BEHAVIOUR,
|
||||
ISSUES(valuePattern = issuesPattern),
|
||||
DISCUSSION,
|
||||
NOTE
|
||||
}
|
||||
|
||||
enum class CommonSpecTestFileInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
SECTIONS(valuePattern = CommonPatterns.sectionsInFilePattern, required = true),
|
||||
NUMBER(required = true),
|
||||
DESCRIPTION(required = true)
|
||||
}
|
||||
|
||||
enum class SpecTestCaseInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
TESTCASE_NUMBER(valuePattern = testCaseNumberPattern, required = true)
|
||||
}
|
||||
|
||||
abstract class AbstractSpecTest(
|
||||
val testArea: TestArea,
|
||||
val testType: TestType,
|
||||
val sections: List<String>,
|
||||
val testNumber: Int,
|
||||
val description: String,
|
||||
val cases: SpecTestCasesSet,
|
||||
val unexpectedBehavior: Boolean,
|
||||
val issues: Set<String>
|
||||
) {
|
||||
companion object {
|
||||
private fun issuesToString(issues: Set<String>) = issues.joinToString(", ") { CommonPatterns.ISSUE_TRACKER + it }
|
||||
}
|
||||
|
||||
abstract fun checkPathConsistency(pathMatcher: Matcher): Boolean
|
||||
|
||||
protected fun getIssuesText(): String? {
|
||||
val testCaseIssues = cases.byNumbers.flatMap { it.value.issues!! }
|
||||
|
||||
return if (issues.isNotEmpty() || testCaseIssues.isNotEmpty()) {
|
||||
"LINKED ISSUES: ${issuesToString(issues + testCaseIssues)}"
|
||||
} else null
|
||||
}
|
||||
|
||||
protected fun getUnexpectedBehaviourText(): String? {
|
||||
val separatedTestCasesUnexpectedBehaviorNumber = cases.byNumbers.count { it.value.unexpectedBehavior }
|
||||
val testCasesUnexpectedBehaviorNumber = when {
|
||||
unexpectedBehavior -> cases.byNumbers.size
|
||||
separatedTestCasesUnexpectedBehaviorNumber != 0 -> separatedTestCasesUnexpectedBehaviorNumber
|
||||
else -> 0
|
||||
}
|
||||
|
||||
return if (testCasesUnexpectedBehaviorNumber != 0) {
|
||||
"!!! HAS UNEXPECTED BEHAVIOUR (in $testCasesUnexpectedBehaviorNumber cases) !!!"
|
||||
} else null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.models
|
||||
|
||||
import org.jetbrains.kotlin.spec.SpecTestCasesSet
|
||||
import org.jetbrains.kotlin.spec.SpecTestInfoElementType
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.ls
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withUnderscores
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.splitByPathSeparator
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withSpaces
|
||||
import org.jetbrains.kotlin.spec.parsers.LinkedSpecTestPatterns.sentencePattern
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
enum class LinkedSpecTestFileInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
PARAGRAPH(required = true),
|
||||
SENTENCE(valuePattern = sentencePattern, required = true)
|
||||
}
|
||||
|
||||
class LinkedSpecTest(
|
||||
testArea: TestArea,
|
||||
testType: TestType,
|
||||
sections: List<String>,
|
||||
val paragraphNumber: Int,
|
||||
val sentenceNumber: Int,
|
||||
private val sentence: String,
|
||||
testNumber: Int,
|
||||
description: String,
|
||||
cases: SpecTestCasesSet,
|
||||
unexpectedBehavior: Boolean,
|
||||
issues: Set<String>
|
||||
) : AbstractSpecTest(testArea, testType, sections, testNumber, description, cases, unexpectedBehavior, issues) {
|
||||
override fun checkPathConsistency(pathMatcher: Matcher) =
|
||||
testArea == TestArea.valueOf(pathMatcher.group("testArea").withUnderscores())
|
||||
&& testType == TestType.fromValue(pathMatcher.group("testType"))!!
|
||||
&& sections == pathMatcher.group("sections").splitByPathSeparator()
|
||||
&& paragraphNumber == pathMatcher.group("paragraphNumber").toInt()
|
||||
&& sentenceNumber == pathMatcher.group("sentenceNumber").toInt()
|
||||
&& testNumber == pathMatcher.group("testNumber").toInt()
|
||||
|
||||
override fun toString() = buildString {
|
||||
append("--------------------------------------------------$ls")
|
||||
super.getUnexpectedBehaviourText()?.let { append(it + ls) }
|
||||
append("${testArea.name.withSpaces()} $testType SPEC TEST (${testType.toString().withSpaces()})$ls")
|
||||
append("SECTIONS: ${sections.joinToString()} (paragraph: $paragraphNumber)$ls")
|
||||
append("SENTENCE $sentenceNumber: $sentence$ls")
|
||||
append("NUMBER: $testNumber$ls")
|
||||
append("TEST CASES: ${cases.byNumbers.size.coerceAtLeast(1)}$ls")
|
||||
append("DESCRIPTION: $description$ls")
|
||||
super.getIssuesText()?.let { append(it + ls) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.models
|
||||
|
||||
import org.jetbrains.kotlin.spec.SpecTestCasesSet
|
||||
import org.jetbrains.kotlin.spec.SpecTestInfoElementType
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.splitByPathSeparator
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withUnderscores
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withSpaces
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.ls
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
enum class NotLinkedSpecTestFileInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType
|
||||
|
||||
class NotLinkedSpecTest(
|
||||
testArea: TestArea,
|
||||
testType: TestType,
|
||||
sections: List<String>,
|
||||
testNumber: Int,
|
||||
description: String,
|
||||
cases: SpecTestCasesSet,
|
||||
unexpectedBehavior: Boolean,
|
||||
issues: Set<String>
|
||||
) : AbstractSpecTest(testArea, testType, sections, testNumber, description, cases, unexpectedBehavior, issues) {
|
||||
override fun checkPathConsistency(pathMatcher: Matcher) =
|
||||
testArea == TestArea.valueOf(pathMatcher.group("testArea").withUnderscores())
|
||||
&& testType == TestType.fromValue(pathMatcher.group("testType"))!!
|
||||
&& sections == pathMatcher.group("sections").splitByPathSeparator()
|
||||
&& testNumber == pathMatcher.group("testNumber").toInt()
|
||||
|
||||
override fun toString() = buildString {
|
||||
append("--------------------------------------------------$ls")
|
||||
super.getUnexpectedBehaviourText()?.let { append(it + ls) }
|
||||
append("${testArea.name.withSpaces()} $testType SPEC TEST (${testType.type.withSpaces()})$ls")
|
||||
append("SECTIONS: ${sections.joinToString()}$ls")
|
||||
append("NUMBER: $testNumber$ls")
|
||||
append("TEST CASES: ${cases.byNumbers.size.coerceAtLeast(1)}$ls")
|
||||
append("DESCRIPTION: $description$ls")
|
||||
super.getIssuesText()?.let { append(it + ls) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.parsers
|
||||
|
||||
import org.jetbrains.kotlin.spec.*
|
||||
import org.jetbrains.kotlin.spec.SpecTestInfoElementContent
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.models.LinkedSpecTest
|
||||
import org.jetbrains.kotlin.spec.models.LinkedSpecTestFileInfoElementType
|
||||
import org.jetbrains.kotlin.spec.models.NotLinkedSpecTest
|
||||
import org.jetbrains.kotlin.spec.models.SpecTestInfoElements
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.testInfoElementPattern
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.testPathBaseRegexTemplate
|
||||
import org.jetbrains.kotlin.spec.parsers.LinkedSpecTestPatterns.testInfoPattern
|
||||
import org.jetbrains.kotlin.spec.parsers.TestCasePatterns.testCaseInfoPattern
|
||||
import org.jetbrains.kotlin.spec.validators.*
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object CommonParser {
|
||||
fun String.withUnderscores() = replace(" ", "_").toUpperCase()
|
||||
fun String.splitByComma() = split(Regex(""",\s*"""))
|
||||
fun String.splitByPathSeparator() = split(File.separator)
|
||||
fun String.withSpaces() = replace("_", " ")
|
||||
|
||||
private fun isPathMatched(pathPartRegex: String, testFilePath: String) =
|
||||
Pattern.compile(testPathBaseRegexTemplate.format(pathPartRegex)).matcher(testFilePath).find()
|
||||
|
||||
fun parseSpecTest(testFilePath: String, files: TestFiles) = when {
|
||||
isPathMatched(LinkedSpecTestPatterns.pathPartRegex, testFilePath) ->
|
||||
Pair(parseLinkedSpecTest(testFilePath, files), SpecTestLinkedType.LINKED)
|
||||
isPathMatched(NotLinkedSpecTestPatterns.pathPartRegex, testFilePath) ->
|
||||
Pair(parseNotLinkedSpecTest(testFilePath, files), SpecTestLinkedType.NOT_LINKED)
|
||||
else ->
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.FILENAME_NOT_VALID)
|
||||
}
|
||||
|
||||
private fun parseLinkedSpecTest(testFilePath: String, testFiles: TestFiles): LinkedSpecTest {
|
||||
val parsedTestFile = parseTestInfo(testFilePath, testFiles, SpecTestLinkedType.LINKED)
|
||||
val testInfoElements = parsedTestFile.testInfoElements
|
||||
val sentenceMatcher = testInfoElements[LinkedSpecTestFileInfoElementType.SENTENCE]!!.additionalMatcher!!
|
||||
|
||||
return LinkedSpecTest(
|
||||
parsedTestFile.testArea,
|
||||
parsedTestFile.testType,
|
||||
parsedTestFile.sections,
|
||||
testInfoElements[LinkedSpecTestFileInfoElementType.PARAGRAPH]!!.content.toInt(),
|
||||
sentenceMatcher.group("number").toInt(),
|
||||
sentenceMatcher.group("text"),
|
||||
parsedTestFile.testNumber,
|
||||
parsedTestFile.testDescription,
|
||||
parsedTestFile.testCasesSet,
|
||||
parsedTestFile.unexpectedBehavior,
|
||||
parsedTestFile.issues
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseNotLinkedSpecTest(testFilePath: String, testFiles: TestFiles): NotLinkedSpecTest {
|
||||
val parsedTestFile = parseTestInfo(testFilePath, testFiles, SpecTestLinkedType.NOT_LINKED)
|
||||
|
||||
return NotLinkedSpecTest(
|
||||
parsedTestFile.testArea,
|
||||
parsedTestFile.testType,
|
||||
parsedTestFile.sections,
|
||||
parsedTestFile.testNumber,
|
||||
parsedTestFile.testDescription,
|
||||
parsedTestFile.testCasesSet,
|
||||
parsedTestFile.unexpectedBehavior,
|
||||
parsedTestFile.issues
|
||||
)
|
||||
}
|
||||
|
||||
fun parseIssues(issues: SpecTestInfoElementContent?) = issues?.content?.splitByComma()?.toSet().orEmpty()
|
||||
|
||||
fun parseTestInfoElements(rules: Array<SpecTestInfoElementType>, rawElements: String):
|
||||
SpecTestInfoElements<SpecTestInfoElementType> {
|
||||
val testInfoElementsMap = mutableMapOf<SpecTestInfoElementType, SpecTestInfoElementContent>()
|
||||
val testInfoElementMatcher = testInfoElementPattern.matcher(rawElements)
|
||||
|
||||
while (testInfoElementMatcher.find()) {
|
||||
val testInfoOriginalElementName = testInfoElementMatcher.group("name")
|
||||
val testInfoElementName = rules.find {
|
||||
it as Enum<*>
|
||||
it.name == testInfoOriginalElementName.withUnderscores()
|
||||
} ?: throw SpecTestValidationException(
|
||||
SpecTestValidationFailedReason.TESTINFO_NOT_VALID,
|
||||
"Unknown '$testInfoOriginalElementName' test info element name."
|
||||
)
|
||||
val testInfoElementValue = testInfoElementMatcher.group("value")
|
||||
val testInfoElementValueMatcher = testInfoElementName.valuePattern?.matcher(testInfoElementValue)
|
||||
|
||||
if (testInfoElementValueMatcher != null && !testInfoElementValueMatcher.find())
|
||||
throw SpecTestValidationException(
|
||||
SpecTestValidationFailedReason.TESTINFO_NOT_VALID,
|
||||
"'$testInfoElementValue' in '$testInfoElementName' is not parsed."
|
||||
)
|
||||
|
||||
testInfoElementsMap[testInfoElementName] =
|
||||
SpecTestInfoElementContent(testInfoElementValue ?: "", testInfoElementValueMatcher)
|
||||
}
|
||||
|
||||
rules.forEach {
|
||||
if (it.required && !testInfoElementsMap.contains(it)) {
|
||||
throw SpecTestValidationException(
|
||||
SpecTestValidationFailedReason.TESTINFO_NOT_VALID,
|
||||
"$it in case or test info is required."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return testInfoElementsMap
|
||||
}
|
||||
|
||||
fun testInfoFilter(fileContent: String) =
|
||||
testInfoPattern.matcher(fileContent).replaceAll("").let {
|
||||
testCaseInfoPattern.matcher(it).replaceAll("")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.parsers
|
||||
|
||||
import org.jetbrains.kotlin.spec.models.SpecTestCaseInfoElementType
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.INTEGER_REGEX
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.SINGLE_LINE_COMMENT_REGEX
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.ASTERISK_REGEX
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.directiveRegex
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.multilineCommentRegex
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.ps
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.testAreaRegex
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.testPathRegexTemplate
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.testTypeRegex
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withSpaces
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.sectionsInPathRegex
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object CommonPatterns {
|
||||
const val ISSUE_TRACKER = "https://youtrack.jetbrains.com/issue/"
|
||||
const val INTEGER_REGEX = """[1-9]\d*"""
|
||||
const val SINGLE_LINE_COMMENT_REGEX = """\/\/\s*%s"""
|
||||
const val ASTERISK_REGEX = """\*"""
|
||||
|
||||
val ls: String = System.lineSeparator()
|
||||
val ps: String = Pattern.quote(File.separator)
|
||||
|
||||
val multilineCommentRegex = """\/\*\s+?%s\s+\*\/(?:\n)*"""
|
||||
val directiveRegex =
|
||||
"""${SINGLE_LINE_COMMENT_REGEX.format("""[\w\s]+:""")}|${multilineCommentRegex.format(""" $ASTERISK_REGEX [\w\s]+:[\s\S]*?""")}"""
|
||||
val testAreaRegex = """(?<testArea>${TestArea.joinedValues})"""
|
||||
val testTypeRegex = """(?<testType>${TestType.joinedValues})"""
|
||||
val testInfoElementPattern: Pattern = Pattern.compile("""(?: \* )?(?<name>[A-Z ]+?)(?::\s*(?<value>.*?))?\n""")
|
||||
val testPathBaseRegexTemplate = """^.*?$ps(?<testArea>diagnostics|psi|(?:codegen${ps}box))$ps%s"""
|
||||
val testPathRegexTemplate = """$testPathBaseRegexTemplate$ps(?<testType>pos|neg)$ps%s$"""
|
||||
val issuesPattern: Pattern = Pattern.compile("""(KT-[1-9]\d*)(,\s*KT-[1-9]\d*)*""")
|
||||
val sectionsInFilePattern: Pattern = Pattern.compile("""\w+(,\s+\w+)*""")
|
||||
val sectionsInPathRegex = """(?<sections>(?:[\w-]+)(?:$ps[\w-]+)*?)"""
|
||||
val packagePattern: Pattern = Pattern.compile("""(?:^|\n)package (?<packageName>.*?)(?:;|\ns)""")
|
||||
}
|
||||
|
||||
interface BasePatterns {
|
||||
val pathPartRegex: String
|
||||
val testPathPattern: Pattern
|
||||
val testInfoPattern: Pattern
|
||||
}
|
||||
|
||||
object NotLinkedSpecTestPatterns : BasePatterns {
|
||||
private const val FILENAME_REGEX = """(?<testNumber>$INTEGER_REGEX)\.kt"""
|
||||
|
||||
override val pathPartRegex = SpecTestLinkedType.NOT_LINKED.testDataPath + ps + sectionsInPathRegex
|
||||
override val testPathPattern: Pattern =
|
||||
Pattern.compile(testPathRegexTemplate.format(pathPartRegex, FILENAME_REGEX))
|
||||
override val testInfoPattern: Pattern =
|
||||
Pattern.compile(multilineCommentRegex.format(""" $ASTERISK_REGEX KOTLIN $testAreaRegex NOT LINKED SPEC TEST \($testTypeRegex\)\n(?<infoElements>[\s\S]*?\n)"""))
|
||||
}
|
||||
|
||||
object LinkedSpecTestPatterns : BasePatterns {
|
||||
private const val FILENAME_REGEX = """(?<sentenceNumber>$INTEGER_REGEX)\.(?<testNumber>$INTEGER_REGEX)\.kt"""
|
||||
|
||||
override val pathPartRegex =
|
||||
"""${SpecTestLinkedType.LINKED.testDataPath}$ps$sectionsInPathRegex${ps}p-(?<paragraphNumber>$INTEGER_REGEX)"""
|
||||
override val testPathPattern: Pattern =
|
||||
Pattern.compile(testPathRegexTemplate.format(pathPartRegex, FILENAME_REGEX))
|
||||
override val testInfoPattern: Pattern =
|
||||
Pattern.compile(multilineCommentRegex.format(""" $ASTERISK_REGEX KOTLIN $testAreaRegex SPEC TEST \($testTypeRegex\)\n(?<infoElements>[\s\S]*?\n)"""))
|
||||
|
||||
val sentencePattern: Pattern = Pattern.compile("""^\[(?<number>$INTEGER_REGEX)\]\s*(?<text>.*?)$""")
|
||||
}
|
||||
|
||||
object TestCasePatterns {
|
||||
private const val TEST_CASE_CODE_REGEX = """(?<%s>[\s\S]*?)"""
|
||||
|
||||
private val testCaseInfoElementsRegex = """(?<%s>%s${SpecTestCaseInfoElementType.TESTCASE_NUMBER.name.withSpaces()}:%s*?\n)"""
|
||||
private val testCaseInfoRegex = """$TEST_CASE_CODE_REGEX(?<%s>(?:$directiveRegex)|$)"""
|
||||
private val testCaseInfoSingleLineRegex =
|
||||
SINGLE_LINE_COMMENT_REGEX.format(
|
||||
testCaseInfoElementsRegex.format("infoElementsSL", "", """\s*.""")
|
||||
) + testCaseInfoRegex.format("codeSL", "nextDirectiveSL")
|
||||
private val testCaseInfoMultilineRegex =
|
||||
multilineCommentRegex.format(
|
||||
testCaseInfoElementsRegex.format("infoElementsML", """ $ASTERISK_REGEX """, """[\s\S]""")
|
||||
) + testCaseInfoRegex.format("codeML", "nextDirectiveML")
|
||||
|
||||
val testCaseInfoPattern: Pattern = Pattern.compile("(?:$testCaseInfoSingleLineRegex)|(?:$testCaseInfoMultilineRegex)")
|
||||
val testCaseNumberPattern: Pattern = Pattern.compile("""([1-9]\d*)(,\s*[1-9]\d*)*""")
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.parsers
|
||||
|
||||
import org.jetbrains.kotlin.spec.*
|
||||
import org.jetbrains.kotlin.spec.models.CommonInfoElementType
|
||||
import org.jetbrains.kotlin.spec.models.SpecTestCaseInfoElementType
|
||||
import org.jetbrains.kotlin.spec.models.SpecTestInfoElements
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.splitByComma
|
||||
import org.jetbrains.kotlin.spec.parsers.TestCasePatterns.testCaseInfoPattern
|
||||
import java.util.*
|
||||
|
||||
private operator fun SpecTestCase.plusAssign(addTestCase: SpecTestCase) {
|
||||
this.code += addTestCase.code
|
||||
this.unexpectedBehavior = this.unexpectedBehavior or addTestCase.unexpectedBehavior
|
||||
this.issues?.addAll(addTestCase.issues!!)
|
||||
this.ranges.addAll(addTestCase.ranges)
|
||||
}
|
||||
|
||||
private fun SpecTestCase.save(
|
||||
testCasesByNumbers: TestCasesByNumbers,
|
||||
testCasesOfFile: TestCasesByNumbers,
|
||||
testCasesByRangesOfFile: NavigableMap<Int, TestCasesByNumbers>,
|
||||
caseInfoElements: SpecTestInfoElements<SpecTestInfoElementType>
|
||||
) {
|
||||
val testCaseNumbers =
|
||||
caseInfoElements[SpecTestCaseInfoElementType.TESTCASE_NUMBER]!!.content.splitByComma().map { it.trim().toInt() }
|
||||
val startPosition = this.ranges[0].first
|
||||
|
||||
testCaseNumbers.forEach { testCaseNumber ->
|
||||
if (testCasesOfFile[testCaseNumber] != null) {
|
||||
testCasesOfFile[testCaseNumber]!! += this
|
||||
testCasesByNumbers[testCaseNumber]!! += this
|
||||
} else {
|
||||
testCasesOfFile[testCaseNumber] = this
|
||||
testCasesByNumbers[testCaseNumber] = this
|
||||
}
|
||||
testCasesByRangesOfFile.putIfAbsent(startPosition, mutableMapOf())
|
||||
testCasesByRangesOfFile[startPosition]!![testCaseNumber] = this
|
||||
}
|
||||
}
|
||||
|
||||
fun parseTestCases(testFiles: TestFiles): SpecTestCasesSet {
|
||||
val testCasesSet = SpecTestCasesSet(mutableMapOf(), mutableMapOf(), mutableMapOf())
|
||||
var rangeOffset = 0
|
||||
|
||||
for ((filename, fileContent) in testFiles) {
|
||||
val matcher = testCaseInfoPattern.matcher(fileContent)
|
||||
var startFind = 0
|
||||
|
||||
if (!testCasesSet.byFiles.contains(filename)) {
|
||||
testCasesSet.byFiles[filename] = mutableMapOf()
|
||||
testCasesSet.byRanges[filename] = TreeMap()
|
||||
}
|
||||
|
||||
val testCasesOfFile = testCasesSet.byFiles[filename]!!
|
||||
val testCasesByRangesOfFile = testCasesSet.byRanges[filename]!!
|
||||
|
||||
while (matcher.find(startFind)) {
|
||||
val caseInfoElements = CommonParser.parseTestInfoElements(
|
||||
arrayOf(*CommonInfoElementType.values(), *SpecTestCaseInfoElementType.values()),
|
||||
matcher.group("infoElementsSL") ?: matcher.group("infoElementsML")
|
||||
)
|
||||
val nextDirective = matcher.group("nextDirectiveSL") ?: matcher.group("nextDirectiveML")
|
||||
val range = matcher.start()..matcher.end() - nextDirective.length
|
||||
|
||||
SpecTestCase(
|
||||
code = matcher.group("codeSL") ?: matcher.group("codeML"),
|
||||
ranges = mutableListOf(range),
|
||||
unexpectedBehavior = caseInfoElements.contains(CommonInfoElementType.UNEXPECTED_BEHAVIOUR),
|
||||
issues = CommonParser.parseIssues(caseInfoElements[CommonInfoElementType.ISSUES]).toMutableList()
|
||||
).save(testCasesSet.byNumbers, testCasesOfFile, testCasesByRangesOfFile, caseInfoElements)
|
||||
|
||||
startFind = matcher.end() - nextDirective.length
|
||||
}
|
||||
rangeOffset += fileContent.length
|
||||
}
|
||||
|
||||
return testCasesSet
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.parsers
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.spec.*
|
||||
import org.jetbrains.kotlin.spec.models.CommonInfoElementType
|
||||
import org.jetbrains.kotlin.spec.models.CommonSpecTestFileInfoElementType
|
||||
import org.jetbrains.kotlin.spec.models.SpecTestInfoElements
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.withUnderscores
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser.splitByComma
|
||||
import org.jetbrains.kotlin.spec.validators.*
|
||||
import java.io.File
|
||||
|
||||
data class ParsedTestFile(
|
||||
val testArea: TestArea,
|
||||
val testType: TestType,
|
||||
val sections: List<String>,
|
||||
val testNumber: Int,
|
||||
val testDescription: String,
|
||||
val testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>,
|
||||
val testCasesSet: SpecTestCasesSet,
|
||||
val unexpectedBehavior: Boolean,
|
||||
val issues: Set<String>
|
||||
)
|
||||
|
||||
fun parseTestInfo(testFilePath: String, testFiles: TestFiles, linkedTestType: SpecTestLinkedType): ParsedTestFile {
|
||||
val patterns = linkedTestType.patterns.value
|
||||
val testInfoByFilenameMatcher = patterns.testPathPattern.matcher(testFilePath)
|
||||
|
||||
if (!testInfoByFilenameMatcher.find())
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.FILENAME_NOT_VALID)
|
||||
|
||||
val testInfoByContentMatcher = patterns.testInfoPattern.matcher(FileUtil.loadFile(File(testFilePath), true))
|
||||
|
||||
if (!testInfoByContentMatcher.find())
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.TESTINFO_NOT_VALID)
|
||||
|
||||
val testInfoElements = CommonParser.parseTestInfoElements(
|
||||
arrayOf(*CommonInfoElementType.values(), *CommonSpecTestFileInfoElementType.values(), *linkedTestType.infoElements.value),
|
||||
testInfoByContentMatcher.group("infoElements")
|
||||
)
|
||||
|
||||
return ParsedTestFile(
|
||||
testArea = TestArea.valueOf(testInfoByContentMatcher.group("testArea").withUnderscores()),
|
||||
testType = TestType.valueOf(testInfoByContentMatcher.group("testType")),
|
||||
sections = testInfoElements[CommonSpecTestFileInfoElementType.SECTIONS]!!.content.splitByComma(),
|
||||
testNumber = testInfoElements[CommonSpecTestFileInfoElementType.NUMBER]!!.content.toInt(),
|
||||
testDescription = testInfoElements[CommonSpecTestFileInfoElementType.DESCRIPTION]!!.content,
|
||||
testInfoElements = testInfoElements,
|
||||
testCasesSet = parseTestCases(testFiles),
|
||||
unexpectedBehavior = testInfoElements.contains(CommonInfoElementType.UNEXPECTED_BEHAVIOUR),
|
||||
issues = CommonParser.parseIssues(testInfoElements[CommonInfoElementType.ISSUES])
|
||||
)
|
||||
}
|
||||
+5
-5
@@ -5,11 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.spec.tasks
|
||||
|
||||
import org.jetbrains.kotlin.spec.generators.featureinteraction.Feature
|
||||
import org.jetbrains.kotlin.spec.generators.featureinteraction.generationLinkedSpecTestDataConfig
|
||||
import org.jetbrains.kotlin.spec.generators.featureinteraction.generationSpecTestDataConfigGroup
|
||||
import org.jetbrains.kotlin.spec.validators.TestArea
|
||||
import org.jetbrains.kotlin.spec.validators.TestType
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import org.jetbrains.kotlin.spec.generators.templates.Feature
|
||||
import org.jetbrains.kotlin.spec.generators.templates.generationLinkedSpecTestDataConfig
|
||||
import org.jetbrains.kotlin.spec.generators.templates.generationSpecTestDataConfigGroup
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
generationSpecTestDataConfigGroup(regenerateTests = true) {
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
package org.jetbrains.kotlin.spec.tasks
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import org.jetbrains.kotlin.spec.models.LinkedSpecTest
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser
|
||||
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration.MODULE_PATH
|
||||
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration.TESTDATA_PATH
|
||||
import org.jetbrains.kotlin.spec.utils.TestsJsonMapBuilder
|
||||
import org.jetbrains.kotlin.spec.validators.LinkedSpecTestValidator
|
||||
import org.jetbrains.kotlin.spec.validators.SpecTestValidationException
|
||||
import java.io.File
|
||||
|
||||
private const val OUT_DIR = "out"
|
||||
@@ -20,15 +20,10 @@ fun main(args: Array<String>) {
|
||||
val testsMap = JsonObject()
|
||||
|
||||
File(TESTDATA_PATH).walkTopDown().forEach {
|
||||
val specTestValidator = LinkedSpecTestValidator(it)
|
||||
val (specTest, _) = CommonParser.parseSpecTest(it.canonicalPath, mapOf("main.kt" to it.readText()))
|
||||
|
||||
try {
|
||||
specTestValidator.parseTestInfo()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
TestsJsonMapBuilder.buildJsonElement(specTestValidator.testInfo, testsMap)
|
||||
if (specTest is LinkedSpecTest)
|
||||
TestsJsonMapBuilder.buildJsonElement(specTest, testsMap)
|
||||
}
|
||||
|
||||
val outDir = "$MODULE_PATH/$OUT_DIR"
|
||||
|
||||
+5
-10
@@ -5,15 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.spec.tasks
|
||||
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.utils.SpecTestsStatElement
|
||||
import org.jetbrains.kotlin.spec.utils.SpecTestsStatElementType
|
||||
import org.jetbrains.kotlin.spec.utils.TestsStatisticCollector
|
||||
import org.jetbrains.kotlin.spec.validators.SpecTestLinkedType
|
||||
|
||||
const val PRINT_BASE_INDENT = " "
|
||||
|
||||
fun linkedSpecTestsPrint() {
|
||||
println("SPEC TESTS STATISTIC")
|
||||
println("LINKED SPEC TESTS STATISTIC")
|
||||
println("--------------------------------------------------")
|
||||
|
||||
val statistic = TestsStatisticCollector.collect(SpecTestLinkedType.LINKED)
|
||||
@@ -21,14 +21,9 @@ fun linkedSpecTestsPrint() {
|
||||
for ((areaName, areaElement) in statistic) {
|
||||
println("$areaName: ${areaElement.number} tests")
|
||||
for ((sectionName, sectionElement) in areaElement.elements) {
|
||||
println(" $sectionName: ${sectionElement.number} tests")
|
||||
for ((paragraphName, paragraphElement) in sectionElement.elements) {
|
||||
val testsStatByType = mutableListOf<String>()
|
||||
for ((typeName, typeElement) in paragraphElement.elements)
|
||||
testsStatByType.add(" [ $typeName: ${typeElement.number} ]")
|
||||
print(PRINT_BASE_INDENT.repeat(2))
|
||||
println("PARAGRAPH $paragraphName: ${paragraphElement.number} tests${testsStatByType.joinToString("")}")
|
||||
}
|
||||
print(" $sectionName: ${sectionElement.number} tests")
|
||||
notLinkedSpecTestsCategoriesPrint(sectionElement.elements)
|
||||
println()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.spec.utils
|
||||
|
||||
import com.google.gson.*
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import org.jetbrains.kotlin.spec.validators.*
|
||||
import org.jetbrains.kotlin.spec.models.LinkedSpecTest
|
||||
|
||||
object TestsJsonMapBuilder {
|
||||
private val stringListType = object : TypeToken<List<String>>() {}.type
|
||||
@@ -19,7 +19,7 @@ object TestsJsonMapBuilder {
|
||||
}
|
||||
|
||||
fun buildJsonElement(testInfo: LinkedSpecTest, testsMap: JsonObject) {
|
||||
val sectionElement = addJsonIfNotExist(testsMap, testInfo.section)
|
||||
val sectionElement = addJsonIfNotExist(testsMap, testInfo.sections[0])
|
||||
val paragraphElement = addJsonIfNotExist(sectionElement, testInfo.paragraphNumber)
|
||||
val sentenceElement = addJsonIfNotExist(paragraphElement, testInfo.sentenceNumber)
|
||||
val testAreaElement = addJsonIfNotExist(sentenceElement, testInfo.testArea.name.toLowerCase())
|
||||
@@ -27,12 +27,12 @@ object TestsJsonMapBuilder {
|
||||
val testNumberElement = addJsonIfNotExist(testTypeElement, testInfo.testNumber)
|
||||
|
||||
testNumberElement.addProperty("description", testInfo.description)
|
||||
testNumberElement.addProperty("caseNumber", testInfo.cases!!.size)
|
||||
testNumberElement.addProperty("caseNumber", testInfo.cases.byFiles.size)
|
||||
|
||||
if (testInfo.unexpectedBehavior!!)
|
||||
if (testInfo.unexpectedBehavior)
|
||||
testNumberElement.addProperty("unexpectedBehavior", testInfo.unexpectedBehavior)
|
||||
|
||||
if (testInfo.issues!!.isNotEmpty())
|
||||
if (testInfo.issues.isNotEmpty())
|
||||
testNumberElement.add("issues", Gson().toJsonTree(testInfo.issues, stringListType))
|
||||
}
|
||||
}
|
||||
+10
-22
@@ -5,8 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.spec.utils
|
||||
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.TestArea
|
||||
import org.jetbrains.kotlin.spec.models.AbstractSpecTest
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonParser
|
||||
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration.TESTDATA_PATH
|
||||
import org.jetbrains.kotlin.spec.validators.*
|
||||
import java.io.File
|
||||
|
||||
open class SpecTestsStatElement(val type: SpecTestsStatElementType) {
|
||||
@@ -42,27 +45,18 @@ object TestsStatisticCollector {
|
||||
val statistic = mutableMapOf<TestArea, SpecTestsStatElement>()
|
||||
|
||||
for (specTestArea in TestArea.values()) {
|
||||
val specTestsPath = "$TESTDATA_PATH/${specTestArea.name.toLowerCase()}/${testLinkedType.testDataPath}"
|
||||
val specTestsPath = "$TESTDATA_PATH/${specTestArea.name.toLowerCase().replace("_", "/")}/${testLinkedType.testDataPath}"
|
||||
|
||||
statistic[specTestArea] = SpecTestsStatElement(SpecTestsStatElementType.AREA)
|
||||
|
||||
File(specTestsPath).walkTopDown().forEach areaTests@{
|
||||
if (!it.isFile || it.extension != "kt") return@areaTests
|
||||
|
||||
val specTestsValidator = AbstractSpecTestValidator.getInstanceByType(it)
|
||||
|
||||
try {
|
||||
specTestsValidator.parseTestInfo()
|
||||
} catch (e: SpecTestValidationException) {
|
||||
return@areaTests
|
||||
}
|
||||
val (specTest, _) = CommonParser.parseSpecTest(it.canonicalPath, mapOf("main.kt" to it.readText()))
|
||||
|
||||
incrementStatCounters(
|
||||
statistic[specTestArea]!!,
|
||||
when (testLinkedType) {
|
||||
SpecTestLinkedType.LINKED -> getStatElementsByLinkedTests(specTestsValidator.testInfo as LinkedSpecTest)
|
||||
SpecTestLinkedType.NOT_LINKED -> getStatElementsByNotLinkedTests(specTestsValidator.testInfo as NotLinkedSpecTest)
|
||||
}
|
||||
getStatElements(specTest)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -70,15 +64,9 @@ object TestsStatisticCollector {
|
||||
return statistic
|
||||
}
|
||||
|
||||
private fun getStatElementsByLinkedTests(testInfo: LinkedSpecTest) = listOf(
|
||||
SpecTestsStatElementType.SECTION to testInfo.section,
|
||||
SpecTestsStatElementType.PARAGRAPH to testInfo.paragraphNumber,
|
||||
SpecTestsStatElementType.TYPE to testInfo.testType.type
|
||||
)
|
||||
|
||||
private fun getStatElementsByNotLinkedTests(testInfo: NotLinkedSpecTest) =
|
||||
mutableListOf(SpecTestsStatElementType.SECTION to testInfo.section).apply {
|
||||
addAll(testInfo.categories.map { SpecTestsStatElementType.CATEGORY to it })
|
||||
private fun getStatElements(testInfo: AbstractSpecTest) =
|
||||
mutableListOf(SpecTestsStatElementType.SECTION to testInfo.sections[0]).apply {
|
||||
addAll(testInfo.sections.map { SpecTestsStatElementType.CATEGORY to it })
|
||||
add(SpecTestsStatElementType.TYPE to testInfo.testType.type)
|
||||
}
|
||||
}
|
||||
-288
@@ -1,288 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.validators
|
||||
|
||||
import java.io.File
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
enum class TestType(val type: String) {
|
||||
POSITIVE("pos"),
|
||||
NEGATIVE("neg");
|
||||
|
||||
companion object {
|
||||
private val map = TestType.values().associateBy(TestType::type)
|
||||
fun fromValue(type: String) = map[type]
|
||||
}
|
||||
}
|
||||
|
||||
enum class TestArea(val testDataPath: String) {
|
||||
PSI("psi"),
|
||||
DIAGNOSTICS("diagnostics"),
|
||||
CODEGEN_BOX("codegen/box")
|
||||
}
|
||||
|
||||
enum class SpecTestLinkedType(val testDataPath: String) {
|
||||
LINKED("linked"),
|
||||
NOT_LINKED("notLinked")
|
||||
}
|
||||
|
||||
interface SpecTestInfoElementType {
|
||||
val valuePattern: Pattern?
|
||||
val required: Boolean
|
||||
}
|
||||
|
||||
enum class SpecTestCaseInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
CASE_DESCRIPTION(required = true),
|
||||
ISSUES(valuePattern = LinkedSpecTestFileInfoElementType.ISSUES.valuePattern),
|
||||
UNEXPECTED_BEHAVIOUR,
|
||||
DISCUSSION,
|
||||
NOTE
|
||||
}
|
||||
|
||||
data class SpecTestInfoElementContent(
|
||||
val content: String,
|
||||
val additionalMatcher: Matcher? = null
|
||||
)
|
||||
|
||||
data class SpecTestCase(
|
||||
val number: Int,
|
||||
val description: String,
|
||||
val unexpectedBehavior: Boolean,
|
||||
val issues: List<String>?
|
||||
)
|
||||
|
||||
enum class SpecTestValidationFailedReason(val description: String) {
|
||||
FILENAME_NOT_VALID("Incorrect test filename or folder name."),
|
||||
TESTINFO_NOT_VALID("Test info is incorrect."),
|
||||
FILEPATH_AND_TESTINFO_IN_FILE_NOT_CONSISTENCY("Test info from filepath and file content is not consistency"),
|
||||
TEST_IS_NOT_POSITIVE("Test is not positive because it contains error elements (PsiErrorElement or diagnostic with error severity)."),
|
||||
TEST_IS_NOT_NEGATIVE("Test is not negative because it not contains error type elements (PsiErrorElement or diagnostic with error severity)."),
|
||||
UNKNOWN("Unknown validation error.")
|
||||
}
|
||||
|
||||
class SpecTestValidationException(reason: SpecTestValidationFailedReason, details: String = "") : Exception() {
|
||||
val description = "${reason.description} $details"
|
||||
}
|
||||
|
||||
typealias SpecTestInfoElements<T> = Map<T, SpecTestInfoElementContent>
|
||||
|
||||
interface SpecTestValidatorHelperObject {
|
||||
val pathPartRegex: String
|
||||
val filenameRegex: String
|
||||
fun getPathPattern(): Pattern
|
||||
}
|
||||
|
||||
abstract class AbstractSpecTest(
|
||||
val testArea: TestArea,
|
||||
val testType: TestType,
|
||||
val section: String,
|
||||
val testNumber: Int,
|
||||
val description: String? = null,
|
||||
val cases: List<SpecTestCase>? = null,
|
||||
val unexpectedBehavior: Boolean? = null,
|
||||
val issues: Set<String>? = null
|
||||
) {
|
||||
abstract fun checkConsistency(other: AbstractSpecTest): Boolean
|
||||
}
|
||||
|
||||
abstract class AbstractSpecTestValidator<T : AbstractSpecTest>(private val testDataFile: File) {
|
||||
val testInfo by lazy { testInfoByContent }
|
||||
|
||||
protected lateinit var testInfoByFilename: T
|
||||
protected lateinit var testInfoByContent: T
|
||||
abstract val testPathPattern: Pattern
|
||||
abstract val testInfoPattern: Pattern
|
||||
|
||||
companion object {
|
||||
const val ISSUE_TRACKER = "https://youtrack.jetbrains.com/issue/"
|
||||
const val INTEGER_REGEX = """[1-9]\d*"""
|
||||
|
||||
val pathSeparator: String = Pattern.quote(File.separator)
|
||||
val lineSeparator: String = System.lineSeparator()
|
||||
val testAreaRegex = """(?<testArea>${TestArea.values().joinToString("|").replace("_", " ")})"""
|
||||
val testTypeRegex = """(?<testType>${TestType.values().joinToString("|")})"""
|
||||
val multilineCommentRegex = """\/\*\s*%s\s+\*\/(?:$lineSeparator)*"""
|
||||
private val singlelineCommentRegex = """\/\/\s*%s(?:$lineSeparator)*"""
|
||||
private val testInfoElementPattern: Pattern = Pattern.compile("""\s*(?<name>[A-Z ]+?)(?::\s*(?<value>.*?))?$lineSeparator""")
|
||||
private val testCaseInfoRegex = """(?<infoElements>CASE DESCRIPTION:[\s\S]*?$lineSeparator)(?:$lineSeparator)*"""
|
||||
private val testPathBaseRegexTemplate =
|
||||
"""^.*?$pathSeparator(?<testArea>diagnostics|psi|(?:codegen${pathSeparator}box))$pathSeparator%s"""
|
||||
val testPathRegexTemplate = """$testPathBaseRegexTemplate$pathSeparator(?<testType>pos|neg)$pathSeparator%s$"""
|
||||
val testCaseInfoSingleLinePattern: Pattern = Pattern.compile(singlelineCommentRegex.format(testCaseInfoRegex))
|
||||
val testCaseInfoMultilinePattern: Pattern = Pattern.compile(multilineCommentRegex.format(testCaseInfoRegex))
|
||||
|
||||
fun getInstanceByType(testFile: File) = when {
|
||||
Pattern.compile(testPathBaseRegexTemplate.format(LinkedSpecTestValidator.pathPartRegex)).matcher(testFile.canonicalPath).find() ->
|
||||
LinkedSpecTestValidator(testFile)
|
||||
Pattern.compile(testPathBaseRegexTemplate.format(NotLinkedSpecTestValidator.pathPartRegex)).matcher(testFile.canonicalPath).find() ->
|
||||
NotLinkedSpecTestValidator(testFile)
|
||||
else -> throw SpecTestValidationException(SpecTestValidationFailedReason.FILENAME_NOT_VALID)
|
||||
}
|
||||
|
||||
fun getInstanceByType(testPath: String) = getInstanceByType(File(testPath))
|
||||
|
||||
private fun getTestInfoElements(
|
||||
testInfoElementRules: Array<out SpecTestInfoElementType>,
|
||||
testInfoElements: String
|
||||
): SpecTestInfoElements<SpecTestInfoElementType> {
|
||||
val testInfoElementsMap = mutableMapOf<SpecTestInfoElementType, SpecTestInfoElementContent>()
|
||||
val testInfoElementMatcher = testInfoElementPattern.matcher(testInfoElements)
|
||||
|
||||
while (testInfoElementMatcher.find()) {
|
||||
val testInfoOriginalElementName = testInfoElementMatcher.group("name")
|
||||
val testInfoElementName = testInfoElementRules.find {
|
||||
it as Enum<*>
|
||||
it.name == testInfoOriginalElementName.replace(" ", "_")
|
||||
} ?: throw SpecTestValidationException(
|
||||
SpecTestValidationFailedReason.TESTINFO_NOT_VALID,
|
||||
"Unknown '$testInfoOriginalElementName' test info element name."
|
||||
)
|
||||
val testInfoElementValue = testInfoElementMatcher.group("value")
|
||||
val testInfoElementValueMatcher = testInfoElementName.valuePattern?.matcher(testInfoElementValue)
|
||||
|
||||
if (testInfoElementValueMatcher != null && !testInfoElementValueMatcher.find())
|
||||
throw SpecTestValidationException(
|
||||
SpecTestValidationFailedReason.TESTINFO_NOT_VALID,
|
||||
"'$testInfoElementValue' in '$testInfoElementName' is not parsed."
|
||||
)
|
||||
|
||||
testInfoElementsMap[testInfoElementName] =
|
||||
SpecTestInfoElementContent(testInfoElementValue ?: "", testInfoElementValueMatcher)
|
||||
}
|
||||
|
||||
testInfoElementRules.forEach {
|
||||
if (it.required && !testInfoElementsMap.contains(it)) {
|
||||
throw SpecTestValidationException(
|
||||
SpecTestValidationFailedReason.TESTINFO_NOT_VALID,
|
||||
"$it in case or test info is required."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return testInfoElementsMap
|
||||
}
|
||||
|
||||
private fun getIssues(testCases: List<SpecTestCase>, testIssues: List<String>?): Set<String> {
|
||||
val issues = mutableSetOf<String>()
|
||||
|
||||
testCases.forEach {
|
||||
if (it.issues != null) issues.addAll(it.issues)
|
||||
}
|
||||
|
||||
if (testIssues != null) issues.addAll(testIssues)
|
||||
|
||||
return issues
|
||||
}
|
||||
|
||||
fun parseIssues(issues: SpecTestInfoElementContent?) = issues?.content?.split(",")
|
||||
}
|
||||
|
||||
private fun getTestCasesInfo(
|
||||
testCaseInfoMatcher: Matcher,
|
||||
infoElements: SpecTestInfoElements<SpecTestInfoElementType>
|
||||
): List<SpecTestCase> {
|
||||
val testCases = mutableListOf<SpecTestCase>()
|
||||
var testCasesCounter = 1
|
||||
|
||||
while (testCaseInfoMatcher.find()) {
|
||||
val caseInfoElements = getTestInfoElements(
|
||||
SpecTestCaseInfoElementType.values(),
|
||||
testCaseInfoMatcher.group("infoElements")
|
||||
)
|
||||
|
||||
testCases.add(
|
||||
SpecTestCase(
|
||||
testCasesCounter++,
|
||||
caseInfoElements[SpecTestCaseInfoElementType.CASE_DESCRIPTION]!!.content,
|
||||
caseInfoElements.contains(SpecTestCaseInfoElementType.UNEXPECTED_BEHAVIOUR),
|
||||
parseIssues(caseInfoElements[SpecTestCaseInfoElementType.ISSUES])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (testCases.isEmpty())
|
||||
testCases.add(getSingleTestCase(infoElements))
|
||||
|
||||
return testCases
|
||||
}
|
||||
|
||||
abstract fun getSingleTestCase(testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>) : SpecTestCase
|
||||
|
||||
fun testInfoFilter(fileContent: String): String =
|
||||
testInfoPattern.matcher(fileContent).replaceAll("").let {
|
||||
testCaseInfoSingleLinePattern.matcher(it).replaceAll("").let {
|
||||
testCaseInfoMultilinePattern.matcher(it).replaceAll("")
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun getTestInfo(
|
||||
testInfoMatcher: Matcher,
|
||||
testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>,
|
||||
testCases: List<SpecTestCase>,
|
||||
unexpectedBehavior: Boolean = false,
|
||||
issues: Set<String>? = null
|
||||
): T
|
||||
|
||||
abstract fun getTestInfo(testInfoMatcher: Matcher): T
|
||||
|
||||
abstract fun parseTestInfo()
|
||||
|
||||
abstract fun printTestInfo()
|
||||
|
||||
fun parseTestInfo(testInfoElementsRules: Array<out SpecTestInfoElementType>) {
|
||||
val testInfoByFilenameMatcher = testPathPattern.matcher(testDataFile.canonicalPath)
|
||||
|
||||
if (!testInfoByFilenameMatcher.find())
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.FILENAME_NOT_VALID)
|
||||
|
||||
val fileContent = testDataFile.readText()
|
||||
val testInfoByContentMatcher = testInfoPattern.matcher(fileContent)
|
||||
|
||||
if (!testInfoByContentMatcher.find())
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.TESTINFO_NOT_VALID)
|
||||
|
||||
val testInfoElements = getTestInfoElements(
|
||||
testInfoElementsRules,
|
||||
testInfoByContentMatcher.group("infoElements")
|
||||
)
|
||||
val testCases = getTestCasesInfo(testCaseInfoSingleLinePattern.matcher(fileContent), testInfoElements) +
|
||||
getTestCasesInfo(testCaseInfoMultilinePattern.matcher(fileContent), testInfoElements)
|
||||
|
||||
testInfoByFilename = getTestInfo(testInfoByFilenameMatcher)
|
||||
testInfoByContent = getTestInfo(
|
||||
testInfoByContentMatcher,
|
||||
testInfoElements,
|
||||
testCases = testCases,
|
||||
unexpectedBehavior = testInfoElements.contains(LinkedSpecTestFileInfoElementType.UNEXPECTED_BEHAVIOUR) || testCases.any { it.unexpectedBehavior },
|
||||
issues = getIssues(
|
||||
testCases,
|
||||
parseIssues(
|
||||
testInfoElements[LinkedSpecTestFileInfoElementType.ISSUES]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if (!testInfoByFilename.checkConsistency(testInfoByContent))
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.FILEPATH_AND_TESTINFO_IN_FILE_NOT_CONSISTENCY)
|
||||
}
|
||||
|
||||
fun validateTestType(computedTestType: TestType) {
|
||||
if (computedTestType != testInfo.testType) {
|
||||
val isNotNegative = computedTestType == TestType.POSITIVE && testInfo.testType == TestType.NEGATIVE
|
||||
val isNotPositive = computedTestType == TestType.NEGATIVE && testInfo.testType == TestType.POSITIVE
|
||||
val reason = when {
|
||||
isNotNegative -> SpecTestValidationFailedReason.TEST_IS_NOT_NEGATIVE
|
||||
isNotPositive -> SpecTestValidationFailedReason.TEST_IS_NOT_POSITIVE
|
||||
else -> SpecTestValidationFailedReason.UNKNOWN
|
||||
}
|
||||
throw SpecTestValidationException(reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.validators
|
||||
|
||||
import org.jetbrains.kotlin.spec.models.AbstractSpecTest
|
||||
import org.jetbrains.kotlin.spec.SpecTestLinkedType
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import org.jetbrains.kotlin.spec.parsers.CommonPatterns
|
||||
import java.io.File
|
||||
|
||||
enum class SpecTestValidationFailedReason(val description: String) {
|
||||
FILENAME_NOT_VALID("Incorrect test filename or folder name."),
|
||||
TESTINFO_NOT_VALID("Test info is incorrect."),
|
||||
FILEPATH_AND_TESTINFO_IN_FILE_NOT_CONSISTENCY("Test info from filepath and file content is not consistency"),
|
||||
TEST_IS_NOT_POSITIVE("Test is not positive because it contains error elements (PsiErrorElement or diagnostic with error severity)."),
|
||||
TEST_IS_NOT_NEGATIVE("Test is not negative because it not contains error type elements (PsiErrorElement or diagnostic with error severity)."),
|
||||
INVALID_TEST_CASES_STRUCTURE(
|
||||
"All code in the test file must be divided and marked as a 'test case' label.${CommonPatterns.ls}Example:${CommonPatterns.ls.repeat(2)}// TESTCASE NUMBER: 1${CommonPatterns.ls}fun main() { println(\"Hello, Kotlin!\") }${CommonPatterns.ls.repeat(2)}"
|
||||
),
|
||||
UNKNOWN_FRONTEND_EXCEPTION("Unknown frontend exception. Manual analysis is required."),
|
||||
UNMATCHED_FRONTEND_EXCEPTION("Unmatched frontend exception. Manual analysis is required."),
|
||||
UNKNOWN("Unknown validation error.")
|
||||
}
|
||||
|
||||
class SpecTestValidationException(reason: SpecTestValidationFailedReason, details: String = "") : Exception() {
|
||||
val description = "${reason.description} $details"
|
||||
}
|
||||
|
||||
abstract class AbstractTestValidator(private val testInfo: AbstractSpecTest, private val testDataFile: File) {
|
||||
fun validatePathConsistency(testLinkedType: SpecTestLinkedType) {
|
||||
val matcher = testLinkedType.patterns.value.testPathPattern.matcher(testDataFile.canonicalPath).apply { find() }
|
||||
|
||||
if (!testInfo.checkPathConsistency(matcher))
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.FILEPATH_AND_TESTINFO_IN_FILE_NOT_CONSISTENCY)
|
||||
}
|
||||
|
||||
abstract fun computeTestTypes(): Map<Int, TestType>
|
||||
|
||||
fun validateTestType() {
|
||||
val computedTestTypes = computeTestTypes()
|
||||
|
||||
for ((caseNumber, case) in testInfo.cases.byNumbers) {
|
||||
val testType = computedTestTypes[caseNumber] ?: TestType.POSITIVE
|
||||
|
||||
if (testType != testInfo.testType && !testInfo.unexpectedBehavior && !case.unexpectedBehavior) {
|
||||
val isNotNegative = testType == TestType.POSITIVE && testInfo.testType == TestType.NEGATIVE
|
||||
val isNotPositive = testType == TestType.NEGATIVE && testInfo.testType == TestType.POSITIVE
|
||||
val reason = when {
|
||||
isNotNegative -> SpecTestValidationFailedReason.TEST_IS_NOT_NEGATIVE
|
||||
isNotPositive -> SpecTestValidationFailedReason.TEST_IS_NOT_POSITIVE
|
||||
else -> SpecTestValidationFailedReason.UNKNOWN
|
||||
}
|
||||
throw SpecTestValidationException(reason, details = "TESTCASE: $caseNumber")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-5
@@ -8,20 +8,44 @@ package org.jetbrains.kotlin.spec.validators
|
||||
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.spec.models.AbstractSpecTest
|
||||
import org.jetbrains.kotlin.spec.TestCasesByNumbers
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import java.io.File
|
||||
|
||||
class DiagnosticTestTypeValidator(testFiles: List<BaseDiagnosticsTest.TestFile>) {
|
||||
class DiagnosticTestTypeValidator(
|
||||
testFiles: List<BaseDiagnosticsTest.TestFile>,
|
||||
testDataFile: File,
|
||||
private val testInfo: AbstractSpecTest
|
||||
) : AbstractTestValidator(testInfo, testDataFile) {
|
||||
private val diagnostics = mutableListOf<Diagnostic>()
|
||||
private val diagnosticStats = mutableMapOf<String, Int>()
|
||||
private val diagnosticSeverityStats = mutableMapOf<Severity, Int>()
|
||||
private val diagnosticSeverityStats = mutableMapOf<Int, MutableMap<Severity, Int>>()
|
||||
|
||||
init {
|
||||
collectDiagnostics(testFiles)
|
||||
}
|
||||
|
||||
private fun findTestCases(diagnostic: Diagnostic): TestCasesByNumbers {
|
||||
val ranges = diagnostic.textRanges
|
||||
val filename = diagnostic.psiFile.name
|
||||
val foundTestCases = testInfo.cases.byRanges[filename]!!.floorEntry(ranges[0].startOffset)
|
||||
|
||||
if (foundTestCases != null)
|
||||
return foundTestCases.value
|
||||
|
||||
throw SpecTestValidationException(SpecTestValidationFailedReason.INVALID_TEST_CASES_STRUCTURE)
|
||||
}
|
||||
|
||||
private fun collectDiagnosticStatistic() {
|
||||
diagnostics.forEach {
|
||||
val testCases = findTestCases(it)
|
||||
val severity = it.factory.severity
|
||||
diagnosticSeverityStats.run { put(severity, getOrDefault(severity, 0) + 1) }
|
||||
|
||||
for ((caseNumber, _) in testCases) {
|
||||
diagnosticSeverityStats.putIfAbsent(caseNumber, mutableMapOf())
|
||||
diagnosticSeverityStats[caseNumber]!!.run { put(severity, getOrDefault(severity, 0) + 1) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +60,9 @@ class DiagnosticTestTypeValidator(testFiles: List<BaseDiagnosticsTest.TestFile>)
|
||||
collectDiagnosticStatistic()
|
||||
}
|
||||
|
||||
fun computeTestType() =
|
||||
if (Severity.ERROR in diagnosticSeverityStats) TestType.NEGATIVE else TestType.POSITIVE
|
||||
override fun computeTestTypes() = diagnosticSeverityStats.mapValues {
|
||||
if (Severity.ERROR in it.value) TestType.NEGATIVE else TestType.POSITIVE
|
||||
}
|
||||
|
||||
fun printDiagnosticStatistic() {
|
||||
val diagnostics = if (diagnosticStats.isNotEmpty()) "$diagnosticSeverityStats | $diagnosticStats" else "does not contain"
|
||||
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.validators
|
||||
|
||||
import java.io.File
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
enum class LinkedSpecTestFileInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
SECTIONS(
|
||||
Pattern.compile("""\w+(,\s+\w+)*"""),
|
||||
required = true
|
||||
),
|
||||
PARAGRAPH(required = true),
|
||||
SENTENCE(
|
||||
valuePattern = Pattern.compile("""\[(?<number>${AbstractSpecTestValidator.INTEGER_REGEX})\](?<text>.*?)"""),
|
||||
required = true
|
||||
),
|
||||
NUMBER(required = true),
|
||||
DESCRIPTION(required = true),
|
||||
ISSUES(valuePattern = Pattern.compile("""(KT-[1-9]\d*)(,\s*KT-[1-9]\d*)*""")),
|
||||
UNEXPECTED_BEHAVIOUR,
|
||||
DISCUSSION,
|
||||
NOTE
|
||||
}
|
||||
|
||||
class LinkedSpecTest(
|
||||
testArea: TestArea,
|
||||
testType: TestType,
|
||||
val sections: List<String>,
|
||||
val paragraphNumber: Int,
|
||||
val sentenceNumber: Int,
|
||||
val sentence: String? = null,
|
||||
testNumber: Int,
|
||||
description: String? = null,
|
||||
cases: List<SpecTestCase>? = null,
|
||||
unexpectedBehavior: Boolean? = null,
|
||||
issues: Set<String>? = null
|
||||
) : AbstractSpecTest(testArea, testType, sections[0], testNumber, description, cases, unexpectedBehavior, issues) {
|
||||
override fun checkConsistency(other: AbstractSpecTest) =
|
||||
other is LinkedSpecTest
|
||||
&& this.sections == other.sections
|
||||
&& this.testArea == other.testArea
|
||||
&& this.testType == other.testType
|
||||
&& this.testNumber == other.testNumber
|
||||
&& this.paragraphNumber == other.paragraphNumber
|
||||
&& this.sentenceNumber == other.sentenceNumber
|
||||
}
|
||||
|
||||
class LinkedSpecTestValidator(testDataFile: File) : AbstractSpecTestValidator<LinkedSpecTest>(testDataFile) {
|
||||
override val testPathPattern = getPathPattern()
|
||||
override val testInfoPattern: Pattern =
|
||||
Pattern.compile(multilineCommentRegex.format("""KOTLIN $testAreaRegex SPEC TEST \($testTypeRegex\)$lineSeparator(?<infoElements>[\s\S]*?$lineSeparator)"""))
|
||||
|
||||
companion object : SpecTestValidatorHelperObject {
|
||||
override val pathPartRegex =
|
||||
"""${SpecTestLinkedType.LINKED.testDataPath}$pathSeparator(?<sections>(?:[\w-]+)(?:$pathSeparator[\w-]+)*?)${pathSeparator}p-(?<paragraphNumber>$INTEGER_REGEX)"""
|
||||
override val filenameRegex = """(?<sentenceNumber>$INTEGER_REGEX)\.(?<testNumber>$INTEGER_REGEX)\.kt"""
|
||||
override fun getPathPattern(): Pattern = Pattern.compile(testPathRegexTemplate.format(pathPartRegex, filenameRegex))
|
||||
}
|
||||
|
||||
override fun getTestInfo(
|
||||
testInfoMatcher: Matcher,
|
||||
testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>,
|
||||
testCases: List<SpecTestCase>,
|
||||
unexpectedBehavior: Boolean,
|
||||
issues: Set<String>?
|
||||
): LinkedSpecTest {
|
||||
val sentenceMatcher = testInfoElements[LinkedSpecTestFileInfoElementType.SENTENCE]!!.additionalMatcher!!
|
||||
|
||||
return LinkedSpecTest(
|
||||
TestArea.valueOf(testInfoMatcher.group("testArea").replace(" ", "_").toUpperCase()),
|
||||
TestType.valueOf(testInfoMatcher.group("testType")),
|
||||
testInfoElements[LinkedSpecTestFileInfoElementType.SECTIONS]!!.content.split(Regex(""",\s*""")),
|
||||
testInfoElements[LinkedSpecTestFileInfoElementType.PARAGRAPH]!!.content.toInt(),
|
||||
sentenceMatcher.group("number").toInt(),
|
||||
sentenceMatcher.group("text"),
|
||||
testInfoElements[LinkedSpecTestFileInfoElementType.NUMBER]!!.content.toInt(),
|
||||
testInfoElements[LinkedSpecTestFileInfoElementType.DESCRIPTION]!!.content,
|
||||
testCases,
|
||||
unexpectedBehavior,
|
||||
issues
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTestInfo(testInfoMatcher: Matcher) =
|
||||
LinkedSpecTest(
|
||||
TestArea.valueOf(testInfoMatcher.group("testArea").replace(File.separator, "_").toUpperCase()),
|
||||
TestType.fromValue(testInfoMatcher.group("testType"))!!,
|
||||
testInfoMatcher.group("sections").split(File.separator),
|
||||
testInfoMatcher.group("paragraphNumber").toInt(),
|
||||
testInfoMatcher.group("sentenceNumber").toInt(),
|
||||
testNumber = testInfoMatcher.group("testNumber").toInt()
|
||||
)
|
||||
|
||||
override fun parseTestInfo() = parseTestInfo(LinkedSpecTestFileInfoElementType.values())
|
||||
|
||||
override fun printTestInfo() {
|
||||
println("--------------------------------------------------")
|
||||
if (testInfoByContent.unexpectedBehavior!!)
|
||||
println("(!!!) HAS UNEXPECTED BEHAVIOUR (!!!)")
|
||||
println("${testInfoByFilename.testArea.name.replace("_", " ")} ${testInfoByFilename.testType} SPEC TEST")
|
||||
println("SECTIONS: ${testInfoByContent.sections} (paragraph: ${testInfoByFilename.paragraphNumber})")
|
||||
println("SENTENCE ${testInfoByContent.sentenceNumber}: ${testInfoByContent.sentence}")
|
||||
println("TEST NUMBER: ${testInfoByContent.testNumber}")
|
||||
println("NUMBER OF TEST CASES: ${testInfoByContent.cases!!.size}")
|
||||
println("DESCRIPTION: ${testInfoByContent.description}")
|
||||
if (testInfoByContent.issues!!.isNotEmpty())
|
||||
println("LINKED ISSUES: ${testInfoByContent.issues!!.joinToString { "${ISSUE_TRACKER + it}," }}")
|
||||
}
|
||||
|
||||
override fun getSingleTestCase(testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>) =
|
||||
SpecTestCase(
|
||||
1,
|
||||
description = testInfoElements[LinkedSpecTestFileInfoElementType.DESCRIPTION]!!.content,
|
||||
unexpectedBehavior = testInfoElements.contains(LinkedSpecTestFileInfoElementType.UNEXPECTED_BEHAVIOUR),
|
||||
issues = parseIssues(testInfoElements[LinkedSpecTestFileInfoElementType.ISSUES])
|
||||
)
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.spec.validators
|
||||
|
||||
import java.io.File
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
enum class NotLinkedSpecTestFileInfoElementType(
|
||||
override val valuePattern: Pattern? = null,
|
||||
override val required: Boolean = false
|
||||
) : SpecTestInfoElementType {
|
||||
SECTION(required = true),
|
||||
CATEGORIES(
|
||||
valuePattern = Pattern.compile("""\w+(,\s+\w+)*"""),
|
||||
required = true
|
||||
),
|
||||
NUMBER(required = true),
|
||||
DESCRIPTION(required = true),
|
||||
ISSUES(valuePattern = LinkedSpecTestFileInfoElementType.ISSUES.valuePattern),
|
||||
UNEXPECTED_BEHAVIOUR,
|
||||
DISCUSSION,
|
||||
NOTE
|
||||
}
|
||||
|
||||
class NotLinkedSpecTest(
|
||||
testArea: TestArea,
|
||||
testType: TestType,
|
||||
section: String,
|
||||
val categories: List<String>,
|
||||
testNumber: Int,
|
||||
description: String? = null,
|
||||
cases: List<SpecTestCase>? = null,
|
||||
unexpectedBehavior: Boolean? = null,
|
||||
issues: Set<String>? = null
|
||||
) : AbstractSpecTest(testArea, testType, section, testNumber, description, cases, unexpectedBehavior, issues) {
|
||||
override fun checkConsistency(other: AbstractSpecTest) =
|
||||
other is NotLinkedSpecTest
|
||||
&& this.section == other.section
|
||||
&& this.testArea == other.testArea
|
||||
&& this.testType == other.testType
|
||||
&& this.categories.joinToString(",") == other.categories.joinToString(",")
|
||||
&& this.testNumber == other.testNumber
|
||||
}
|
||||
|
||||
class NotLinkedSpecTestValidator(testDataFile: File) : AbstractSpecTestValidator<NotLinkedSpecTest>(testDataFile) {
|
||||
override val testPathPattern = getPathPattern()
|
||||
override val testInfoPattern: Pattern =
|
||||
Pattern.compile(multilineCommentRegex.format("""KOTLIN $testAreaRegex NOT LINKED SPEC TEST \($testTypeRegex\)$lineSeparator(?<infoElements>[\s\S]*?$lineSeparator)"""))
|
||||
|
||||
companion object : SpecTestValidatorHelperObject {
|
||||
override val pathPartRegex =
|
||||
"""${SpecTestLinkedType.NOT_LINKED.testDataPath}$pathSeparator(?<sections>[\w-]+)$pathSeparator(?<categories>(?:[\w-]+)(?:$pathSeparator[\w-]+)*?)"""
|
||||
override val filenameRegex = """(?<testNumber>$INTEGER_REGEX)\.kt"""
|
||||
override fun getPathPattern(): Pattern = Pattern.compile(testPathRegexTemplate.format(pathPartRegex, filenameRegex))
|
||||
}
|
||||
|
||||
override fun getTestInfo(
|
||||
testInfoMatcher: Matcher,
|
||||
testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>,
|
||||
testCases: List<SpecTestCase>,
|
||||
unexpectedBehavior: Boolean,
|
||||
issues: Set<String>?
|
||||
) =
|
||||
NotLinkedSpecTest(
|
||||
TestArea.valueOf(testInfoMatcher.group("testArea").replace(" ", "_").toUpperCase()),
|
||||
TestType.valueOf(testInfoMatcher.group("testType")),
|
||||
testInfoElements[NotLinkedSpecTestFileInfoElementType.SECTION]!!.content,
|
||||
testInfoElements[NotLinkedSpecTestFileInfoElementType.CATEGORIES]!!.content.split(Regex(""",\s*""")),
|
||||
testInfoElements[NotLinkedSpecTestFileInfoElementType.NUMBER]!!.content.toInt(),
|
||||
testInfoElements[NotLinkedSpecTestFileInfoElementType.DESCRIPTION]!!.content,
|
||||
testCases,
|
||||
unexpectedBehavior,
|
||||
issues
|
||||
)
|
||||
|
||||
override fun getTestInfo(testInfoMatcher: Matcher) =
|
||||
NotLinkedSpecTest(
|
||||
TestArea.valueOf(testInfoMatcher.group("testArea").toUpperCase()),
|
||||
TestType.fromValue(testInfoMatcher.group("testType"))!!,
|
||||
testInfoMatcher.group("sections"),
|
||||
testInfoMatcher.group("categories").split(File.separator),
|
||||
testNumber = testInfoMatcher.group("testNumber").toInt()
|
||||
)
|
||||
|
||||
override fun parseTestInfo() = parseTestInfo(NotLinkedSpecTestFileInfoElementType.values())
|
||||
|
||||
override fun printTestInfo() {
|
||||
println("--------------------------------------------------")
|
||||
if (testInfoByContent.unexpectedBehavior!!)
|
||||
println("(!!!) HAS UNEXPECTED BEHAVIOUR (!!!)")
|
||||
println("${testInfoByFilename.testArea} ${testInfoByFilename.testType} NOT LINKED SPEC TEST")
|
||||
println("SECTIONS: ${testInfoByContent.section}")
|
||||
println("CATEGORIES: ${testInfoByContent.categories.joinToString(", ")}")
|
||||
println("TEST NUMBER: ${testInfoByContent.testNumber}")
|
||||
println("NUMBER OF TEST CASES: ${testInfoByContent.cases!!.size}")
|
||||
println("DESCRIPTION: ${testInfoByContent.description}")
|
||||
if (testInfoByContent.issues!!.isNotEmpty())
|
||||
println("LINKED ISSUES: ${testInfoByContent.issues!!.map { ISSUE_TRACKER + it }.joinToString(", ")}")
|
||||
}
|
||||
|
||||
override fun getSingleTestCase(testInfoElements: SpecTestInfoElements<SpecTestInfoElementType>) =
|
||||
SpecTestCase(
|
||||
1,
|
||||
description = testInfoElements[NotLinkedSpecTestFileInfoElementType.DESCRIPTION]!!.content,
|
||||
unexpectedBehavior = testInfoElements.contains(NotLinkedSpecTestFileInfoElementType.UNEXPECTED_BEHAVIOUR),
|
||||
issues = parseIssues(testInfoElements[NotLinkedSpecTestFileInfoElementType.ISSUES])
|
||||
)
|
||||
}
|
||||
+9
-3
@@ -8,11 +8,17 @@ package org.jetbrains.kotlin.spec.validators
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiErrorElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.spec.TestType
|
||||
import org.jetbrains.kotlin.spec.models.AbstractSpecTest
|
||||
import java.io.File
|
||||
|
||||
object ParsingTestTypeValidator {
|
||||
class ParsingTestTypeValidator(
|
||||
private val psiFile: PsiFile,
|
||||
testDataFile: File,
|
||||
testInfo: AbstractSpecTest
|
||||
) : AbstractTestValidator(testInfo, testDataFile) {
|
||||
private fun checkErrorElement(psi: PsiElement): Boolean =
|
||||
psi.children.any { it is PsiErrorElement || checkErrorElement(it) }
|
||||
|
||||
fun computeTestType(psiFile: PsiFile) =
|
||||
if (checkErrorElement(psiFile)) TestType.NEGATIVE else TestType.POSITIVE
|
||||
override fun computeTestTypes() = mapOf(1 to if (checkErrorElement(psiFile)) TestType.NEGATIVE else TestType.POSITIVE)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user