[Spec tests] Make main link nullable for case if implementation tests don't have this one

This commit is contained in:
anastasiia.spaseeva
2020-04-16 13:43:31 +03:00
parent 3a46b5a45a
commit 270972ca1c
23 changed files with 379 additions and 370 deletions
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.spec.utils.spec.SpecSentencesStorage
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
import kotlin.io.walkTopDown
@TestDataPath("\$PROJECT_ROOT/compiler/tests-spec/testData/")
@RunWith(com.intellij.testFramework.Parameterized::class)
@@ -55,8 +54,9 @@ class SpecTestsConsistencyTest : TestCase() {
val file = File("${GeneralConfiguration.SPEC_TESTDATA_PATH}/${testFilePath.replace("$", "/")}")
val specSentences = specSentencesStorage.getLatest() ?: return
val test = parseLinkedSpecTest(file.canonicalPath, mapOf("main" to file.readText()))
val sectionsPath = setOf(*test.place.sections.toTypedArray(), test.place.paragraphNumber).joinToString()
val sentenceNumber = test.place.sentenceNumber
if (test.mainLink == null) return //todo add check for relevant links also
val sectionsPath = setOf(*test.mainLink.sections.toTypedArray(), test.mainLink.paragraphNumber).joinToString()
val sentenceNumber = test.mainLink.sentenceNumber
val paragraphSentences = specSentences[sectionsPath]
if (paragraphSentences != null && paragraphSentences.size >= sentenceNumber) {
@@ -76,5 +76,6 @@ class SpecTestsConsistencyTest : TestCase() {
assertEquals(expectedSentence, actualSentence)
}
}
}
@@ -35,7 +35,7 @@ object TestsJsonMapGenerator {
return testsByType.getOrCreate(specPlace.sentenceNumber.toString())
}
enum class LinkType{
enum class LinkType {
MAIN,
PRIMARY,
SECONDARY;
@@ -44,6 +44,7 @@ object TestsJsonMapGenerator {
return name.toLowerCase()
}
}
private fun getTestInfo(test: LinkedSpecTest, testFile: File? = null, linkType: LinkType = LinkType.MAIN) =
JsonObject().apply {
addProperty("specVersion", test.specVersion)
@@ -57,6 +58,29 @@ object TestsJsonMapGenerator {
addProperty("linkType", linkType.toString())
}
private fun collectInfoFromTests(
testsMap: JsonObject,
testDataPath: String,
linkedTestsPath: String = ""
) {
TestArea.values().forEach { testArea ->
val filePath = buildString {
append("${testDataPath}/${testArea.testDataPath}")
if (linkedTestsPath.isNotEmpty())
append("/${linkedTestsPath}")
}
File(filePath).walkTopDown()
.forEach testFiles@{ file ->
if (!file.isFile || file.extension != "kt" || file.name.endsWith(".fir.kt")) return@testFiles
val (specTest, _) = CommonParser.parseSpecTest(file.canonicalPath, mapOf("main.kt" to file.readText()))
if (specTest is LinkedSpecTest) {
collectInfoFromTests(testsMap = testsMap, specTest = specTest, file = file)
}
}
}
}
private fun collectInfoFromSpecTests(testsMap: JsonObject) {
TestArea.values().forEach { testArea ->
File("${GeneralConfiguration.SPEC_TESTDATA_PATH}/${testArea.testDataPath}/$LINKED_TESTS_PATH").walkTopDown()
@@ -64,13 +88,7 @@ object TestsJsonMapGenerator {
if (!file.isFile || file.extension != "kt" || file.name.endsWith(".fir.kt")) return@testFiles
val (specTest, _) = CommonParser.parseSpecTest(file.canonicalPath, mapOf("main.kt" to file.readText()))
if (specTest is LinkedSpecTest) {
collectInfoFromTestsTemp(
testsMap = testsMap,
specTest = specTest,
testInfoForMainLink = getTestInfo(specTest, file, LinkType.MAIN),
testInfoForPrimaryLink = getTestInfo(specTest, file, LinkType.PRIMARY),
testInfoForSecondaryLink = getTestInfo(specTest, file, LinkType.SECONDARY)
)
collectInfoFromTests(testsMap = testsMap, specTest = specTest, file = file)
}
}
}
@@ -83,46 +101,34 @@ object TestsJsonMapGenerator {
if (!file.isFile || file.extension != "kt") return@testFiles
if (!LinkedSpecTestPatterns.testInfoPattern.matcher(file.readText()).find())
return@testFiles
val (specTest, _) = CommonParser.parseImplTest(file.canonicalPath, mapOf("main.kt" to file.readText()))
collectInfoFromTests(testsMap, specTest, getTestInfo(specTest, file))
val (specTest, _) = CommonParser.parseSpecTest(file.canonicalPath, mapOf("main.kt" to file.readText()), true)
if (specTest is LinkedSpecTest) {
collectInfoFromTests(testsMap = testsMap, specTest = specTest, file = file)
}
}
}
}
private fun collectInfoFromTests(
testsMap: JsonObject,
specTest: LinkedSpecTest,
testInfoForMainLink: JsonObject,
testInfoForRelevantLink: JsonObject = testInfoForMainLink
) {
testsMap.getOrCreateSpecTestObject(specTest.place, specTest.testArea, specTest.testType).add(testInfoForMainLink)
specTest.primaryLinks?.forEach {
testsMap.getOrCreateSpecTestObject(it, specTest.testArea, specTest.testType).add(testInfoForRelevantLink)
}
specTest.secondaryLinks?.forEach {
testsMap.getOrCreateSpecTestObject(it, specTest.testArea, specTest.testType).add(testInfoForRelevantLink)
}
}
private fun collectInfoFromTestsTemp( //todo add same for implementation tests
testsMap: JsonObject,
specTest: LinkedSpecTest,
testInfoForMainLink: JsonObject,
testInfoForPrimaryLink: JsonObject = testInfoForMainLink,
testInfoForSecondaryLink: JsonObject = testInfoForMainLink
private fun collectInfoFromTests(
testsMap: JsonObject, specTest: LinkedSpecTest, file: File
) {
testsMap.getOrCreateSpecTestObject(specTest.place, specTest.testArea, specTest.testType).add(testInfoForMainLink)
if (specTest.mainLink != null)
testsMap.getOrCreateSpecTestObject(specTest.mainLink, specTest.testArea, specTest.testType)
.add(getTestInfo(specTest, file, LinkType.MAIN))
specTest.primaryLinks?.forEach {
testsMap.getOrCreateSpecTestObject(it, specTest.testArea, specTest.testType).add(testInfoForPrimaryLink)
testsMap.getOrCreateSpecTestObject(it, specTest.testArea, specTest.testType).add(getTestInfo(specTest, file, LinkType.PRIMARY))
}
specTest.secondaryLinks?.forEach {
testsMap.getOrCreateSpecTestObject(it, specTest.testArea, specTest.testType).add(testInfoForSecondaryLink)
testsMap.getOrCreateSpecTestObject(it, specTest.testArea, specTest.testType)
.add(getTestInfo(specTest, file, LinkType.SECONDARY))
}
}
fun buildTestsMapPerSection() {
val testsMap = JsonObject().apply {
collectInfoFromSpecTests(this)
collectInfoFromTests(this, GeneralConfiguration.SPEC_TESTDATA_PATH, LINKED_TESTS_PATH)
collectInfoFromImplementationTests(this)
}
@@ -10,12 +10,12 @@ import org.jetbrains.kotlin.spec.utils.SpecTestCasesSet
import org.jetbrains.kotlin.spec.utils.SpecTestInfoElementType
import org.jetbrains.kotlin.spec.utils.TestArea
import org.jetbrains.kotlin.spec.utils.TestType
import org.jetbrains.kotlin.spec.utils.parsers.LinkedSpecTestPatterns.mainLinkPattern
import org.jetbrains.kotlin.spec.utils.parsers.LinkedSpecTestPatterns.relevantLinksPattern
import org.jetbrains.kotlin.spec.utils.parsers.CommonParser.splitByPathSeparator
import org.jetbrains.kotlin.spec.utils.parsers.CommonParser.withSpaces
import org.jetbrains.kotlin.spec.utils.parsers.CommonParser.withUnderscores
import org.jetbrains.kotlin.spec.utils.parsers.CommonParser.splitByPathSeparator
import org.jetbrains.kotlin.spec.utils.parsers.CommonPatterns.ls
import org.jetbrains.kotlin.spec.utils.parsers.LinkedSpecTestPatterns.mainLinkPattern
import org.jetbrains.kotlin.spec.utils.parsers.LinkedSpecTestPatterns.relevantLinksPattern
import java.util.regex.Matcher
import java.util.regex.Pattern
@@ -40,7 +40,7 @@ class LinkedSpecTest(
val specVersion: String,
testArea: TestArea,
testType: TestType,
val place: SpecPlace,
val mainLink: SpecPlace?,
val primaryLinks: Set<SpecPlace>?,
val secondaryLinks: Set<SpecPlace>?,
testNumber: Int,
@@ -51,14 +51,25 @@ class LinkedSpecTest(
issues: Set<String>,
helpers: Set<String>?,
exception: TestsExceptionType?
) : AbstractSpecTest(testArea, testType, place.sections, testNumber, description, cases, unexpectedBehavior, issues, helpers, exception) {
) : AbstractSpecTest(
testArea,
testType,
mainLink?.sections ?: listOf(),
testNumber,
description,
cases,
unexpectedBehavior,
issues,
helpers,
exception
) {
override fun checkPathConsistency(pathMatcher: Matcher) =
testArea == TestArea.valueOf(pathMatcher.group("testArea").withUnderscores())
&& testType == TestType.fromValue(pathMatcher.group("testType"))!!
&& sections == pathMatcher.group("sections").splitByPathSeparator()
&& place.paragraphNumber == pathMatcher.group("paragraphNumber").toInt()
&& place.sentenceNumber == pathMatcher.group("sentenceNumber").toInt()
&& mainLink?.paragraphNumber == pathMatcher.group("paragraphNumber").toInt()
&& mainLink.sentenceNumber == pathMatcher.group("sentenceNumber").toInt()
&& testNumber == pathMatcher.group("testNumber").toInt()
private fun getUnspecifiedBehaviourText(): String? {
@@ -80,12 +91,19 @@ class LinkedSpecTest(
super.getUnexpectedBehaviourText()?.let { append(it + ls) }
append("${testArea.name.withSpaces()} $testType SPEC TEST (${testType.toString().withSpaces()})$ls")
append("SPEC VERSION: $specVersion$ls")
append("SPEC PLACE: ${sections.joinToString()} -> paragraph: ${place.paragraphNumber} -> sentence: ${place.sentenceNumber}$ls")
primaryLinks?.let { append("PRIMARY LINKS:${it.joinToString { "$ls\t${sections.joinToString()} -> paragraph: ${place.paragraphNumber} -> sentence: ${place.sentenceNumber}" }}$ls") }
secondaryLinks?.let { append("SECONDARY LINKS:${it.joinToString { "$ls\t${sections.joinToString()} -> paragraph: ${place.paragraphNumber} -> sentence: ${place.sentenceNumber}" }}$ls") }
mainLink?.let { append("MAIN LINK: ${sections.joinToString()} -> paragraph: ${mainLink.paragraphNumber} -> sentence: ${mainLink.sentenceNumber}$ls") }
primaryLinks?.let { append("PRIMARY LINKS: ${primaryLinks.buildToString()}$ls") }
secondaryLinks?.let { append("SECONDARY LINKS: ${secondaryLinks.buildToString()}$ls") }
append("NUMBER: $testNumber$ls")
append("TEST CASES: ${cases.byNumbers.size.coerceAtLeast(1)}$ls")
append("DESCRIPTION: $description$ls")
super.getIssuesText()?.let { append(it + ls) }
}
private fun Set<SpecPlace>.buildToString(): String = buildString {
this@buildToString.forEach {
append("${sections.joinToString()} -> paragraph: ${it.paragraphNumber} -> sentence: ${it.sentenceNumber}$ls")
}
}
}
@@ -35,14 +35,13 @@ object CommonParser {
private fun parseBasePath(pathPartRegex: String, testFilePath: String) =
Pattern.compile(testPathBaseRegexTemplate.format(pathPartRegex)).matcher(testFilePath)
fun parseImplTest(testFilePath: String, files: TestFiles): Pair<LinkedSpecTest, SpecTestLinkedType> =
Pair(parseLinkedSpecTest(testFilePath, files, isImplementationTest = true), SpecTestLinkedType.LINKED)
fun parseSpecTest(testFilePath: String, files: TestFiles) = when {
fun parseSpecTest(testFilePath: String, files: TestFiles, isImplementationTest: Boolean = false) = when {
isPathMatched(LinkedSpecTestPatterns.pathPartRegex, testFilePath) ->
Pair(parseLinkedSpecTest(testFilePath, files), SpecTestLinkedType.LINKED)
isPathMatched(NotLinkedSpecTestPatterns.pathPartRegex, testFilePath) ->
Pair(parseNotLinkedSpecTest(testFilePath, files), SpecTestLinkedType.NOT_LINKED)
isImplementationTest ->
Pair(parseLinkedSpecTest(testFilePath, files, true), SpecTestLinkedType.LINKED)
else ->
throw SpecTestValidationException(SpecTestValidationFailedReason.FILENAME_NOT_VALID)
}
@@ -54,51 +53,38 @@ object CommonParser {
placeMatcher.group("sentenceNumber").toInt()
)
private fun parseRelevantPlaces(
placesMatcher: Matcher?,
relevantPlaces: MutableSet<SpecPlace>
) {
if (placesMatcher == null)
return
placesMatcher?.let {
relevantPlaces.add(createSpecPlace(it, placesMatcher))
while (it.find()) {
relevantPlaces.add(createSpecPlace(it, placesMatcher))
class RelevantLinks(linksMatcher: Matcher?) {
val linksSet: MutableSet<SpecPlace> = mutableSetOf()
init {
if (linksMatcher != null) {
linksSet.add(createSpecPlace(linksMatcher))
while (linksMatcher.find()) {
linksSet.add(createSpecPlace(linksMatcher))
}
}
}
}
fun parseLinkedSpecTest(testFilePath: String, testFiles: TestFiles, isImplementationTest: Boolean = false): LinkedSpecTest {
val primaryLinks = mutableSetOf<SpecPlace>()
val secondaryLinks = mutableSetOf<SpecPlace>()
val parsedTestFile = tryParseTestInfo(testFilePath, testFiles, SpecTestLinkedType.LINKED, isImplementationTest)
val testInfoElements = parsedTestFile.testInfoElements
parseRelevantPlaces(
testInfoElements[LinkedSpecTestFileInfoElementType.PRIMARY_LINKS]?.additionalMatcher,
primaryLinks
)
parseRelevantPlaces(
testInfoElements[LinkedSpecTestFileInfoElementType.SECONDARY_LINKS]?.additionalMatcher,
secondaryLinks
)
val primaryLinks =
RelevantLinks(testInfoElements[LinkedSpecTestFileInfoElementType.PRIMARY_LINKS]?.additionalMatcher).linksSet
val secondaryLinks =
RelevantLinks(testInfoElements[LinkedSpecTestFileInfoElementType.SECONDARY_LINKS]?.additionalMatcher).linksSet
val placeMatcher = testInfoElements[LinkedSpecTestFileInfoElementType.MAIN_LINK]?.additionalMatcher
val mainPlace: SpecPlace
if (placeMatcher != null) {
mainPlace = createSpecPlace(placeMatcher)
} else {
mainPlace = primaryLinks.first()
primaryLinks.remove(mainPlace)
}
return LinkedSpecTest(
testInfoElements[LinkedSpecTestFileInfoElementType.SPEC_VERSION]!!.content,
parsedTestFile.testArea,
parsedTestFile.testType,
mainPlace,
placeMatcher?.let { createSpecPlace(placeMatcher) },
primaryLinks,
secondaryLinks,
parsedTestFile.testNumber,
@@ -157,9 +143,9 @@ object CommonParser {
rawElements: String,
) = when (testInfoOriginalElementName) {
LinkedSpecTestPatterns.PRIMARY_LINKS ->
groupRelevantAndAlternativePlaces(LinkedSpecTestPatterns.primaryLinks, rawElements, testInfoOriginalElementName)
groupRelevantLinks(LinkedSpecTestPatterns.primaryLinks, rawElements, testInfoOriginalElementName)
LinkedSpecTestPatterns.SECONDARY_LINKS ->
groupRelevantAndAlternativePlaces(LinkedSpecTestPatterns.secondaryLinks, rawElements, testInfoOriginalElementName)
groupRelevantLinks(LinkedSpecTestPatterns.secondaryLinks, rawElements, testInfoOriginalElementName)
else ->
testInfoElementMatcher.group("value")
}
@@ -204,14 +190,14 @@ object CommonParser {
}
private fun groupRelevantAndAlternativePlaces(placesPattern: Pattern, rawElements: String, linkType: String): String {
val placesMatcher = placesPattern.matcher(rawElements)
private fun groupRelevantLinks(linksPattern: Pattern, rawElements: String, linkType: String): String {
val placesMatcher = linksPattern.matcher(rawElements)
if (placesMatcher.find()) {
return placesMatcher.group("places")
} else throw Exception("$linkType link is incorrect")
}
fun testInfoFilter(fileContent: String) =
fun testInfoFilter(fileContent: String): String =
testInfoPattern.matcher(fileContent).replaceAll("").let {
testCaseInfoPattern.matcher(it).replaceAll("")
}
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.spec.utils.parsers.CommonPatterns.sectionsInPathRege
import org.jetbrains.kotlin.spec.utils.parsers.CommonPatterns.testAreaRegex
import org.jetbrains.kotlin.spec.utils.parsers.CommonPatterns.testPathRegexTemplate
import org.jetbrains.kotlin.spec.utils.parsers.CommonPatterns.testTypeRegex
import org.jetbrains.kotlin.spec.utils.parsers.CommonPatterns.ws
import java.io.File
import java.util.regex.Pattern
@@ -35,7 +34,6 @@ object CommonPatterns {
val ls: String = System.lineSeparator()
val ps: String = Pattern.quote(File.separator)
val ws = """\s*"""
val directiveRegex =
"""${SINGLE_LINE_COMMENT_REGEX.format("""[\w\s]+:""")}|${MULTILINE_COMMENT_REGEX.format(""" $ASTERISK_REGEX [\w\s]+:[\s\S]*?""")}"""
@@ -88,8 +86,8 @@ object LinkedSpecTestPatterns : BasePatterns {
private val linkRegex =
Regex("""(( $ASTERISK_REGEX )?\s*($SECTIONS_IN_FILE_REGEX -> )?(paragraph $INTEGER_REGEX -> )?sentence $INTEGER_REGEX)""")
val primaryLinks: Pattern = Pattern.compile("""$PRIMARY_LINKS$ws:$ws(?<places>(${linkRegex}(\s)*\n)+)""")
val secondaryLinks: Pattern = Pattern.compile("""$SECONDARY_LINKS$ws:$ws(?<places>(${linkRegex}(\s)*\n)+)""")
val primaryLinks: Pattern = Pattern.compile("""$PRIMARY_LINKS\s*:\s*(?<places>(${linkRegex}(\s)*\n)+)""")
val secondaryLinks: Pattern = Pattern.compile("""$SECONDARY_LINKS\s*:\s*(?<places>(${linkRegex}(\s)*\n)+)""")
}
object TestCasePatterns {