Support several spec places to which tests are linked and require specify spec version for each test

This commit is contained in:
victor.petukhov
2018-12-28 15:19:20 +03:00
parent cb5f497cbe
commit acd6d354dc
341 changed files with 736 additions and 1039 deletions
@@ -8,6 +8,7 @@ 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.LinkedSpecTestPatterns.relevantPlacesPattern
import org.jetbrains.kotlin.spec.parsers.TestCasePatterns.testCaseNumberPattern
import java.util.regex.Matcher
import java.util.regex.Pattern
@@ -28,7 +29,6 @@ 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)
}
@@ -37,7 +37,8 @@ enum class SpecTestCaseInfoElementType(
override val valuePattern: Pattern? = null,
override val required: Boolean = false
) : SpecTestInfoElementType {
TESTCASE_NUMBER(valuePattern = testCaseNumberPattern, required = true)
TESTCASE_NUMBER(valuePattern = testCaseNumberPattern, required = true),
RELEVANT_PLACES(valuePattern = relevantPlacesPattern),
}
abstract class AbstractSpecTest(
@@ -13,7 +13,8 @@ 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 org.jetbrains.kotlin.spec.parsers.LinkedSpecTestPatterns.placePattern
import org.jetbrains.kotlin.spec.parsers.LinkedSpecTestPatterns.relevantPlacesPattern
import java.util.regex.Matcher
import java.util.regex.Pattern
@@ -21,37 +22,44 @@ enum class LinkedSpecTestFileInfoElementType(
override val valuePattern: Pattern? = null,
override val required: Boolean = false
) : SpecTestInfoElementType {
PARAGRAPH(required = true),
SENTENCE(valuePattern = sentencePattern, required = true)
SPEC_VERSION(required = true),
PLACE(valuePattern = placePattern, required = true),
RELEVANT_PLACES(valuePattern = relevantPlacesPattern)
}
data class SpecPlace(
val sections: List<String>,
val paragraphNumber: Int,
val sentenceNumber: Int
)
class LinkedSpecTest(
private val specVersion: String,
testArea: TestArea,
testType: TestType,
sections: List<String>,
val paragraphNumber: Int,
val sentenceNumber: Int,
private val sentence: String,
val place: SpecPlace,
private val relevantPlaces: List<SpecPlace>?,
testNumber: Int,
description: String,
cases: SpecTestCasesSet,
unexpectedBehavior: Boolean,
issues: Set<String>
) : AbstractSpecTest(testArea, testType, sections, testNumber, description, cases, unexpectedBehavior, issues) {
) : AbstractSpecTest(testArea, testType, place.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()
&& place.paragraphNumber == pathMatcher.group("paragraphNumber").toInt()
&& place.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("SPEC VERSION: $specVersion$ls")
append("SPEC PLACE: ${sections.joinToString()} -> paragraph: ${place.paragraphNumber} -> sentence: ${place.sentenceNumber}$ls")
relevantPlaces?.let { append("OTHER RELEVANT SPEC PLACES:${it.joinToString { "$ls\t${sections.joinToString()} -> paragraph: ${place.paragraphNumber} -> sentence: ${place.sentenceNumber}" }}$ls") }
append("NUMBER: $testNumber$ls")
append("TEST CASES: ${cases.byNumbers.size.coerceAtLeast(1)}$ls")
append("DESCRIPTION: $description$ls")
@@ -13,13 +13,16 @@ 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 org.jetbrains.kotlin.spec.parsers.CommonPatterns.sectionsInFilePattern
import java.util.regex.Matcher
import java.util.regex.Pattern
enum class NotLinkedSpecTestFileInfoElementType(
override val valuePattern: Pattern? = null,
override val required: Boolean = false
) : SpecTestInfoElementType
) : SpecTestInfoElementType {
SECTIONS(valuePattern = sectionsInFilePattern, required = true)
}
class NotLinkedSpecTest(
testArea: TestArea,
@@ -8,16 +8,14 @@ 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.models.*
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.Matcher
import java.util.regex.Pattern
object CommonParser {
@@ -41,18 +39,33 @@ object CommonParser {
throw SpecTestValidationException(SpecTestValidationFailedReason.FILENAME_NOT_VALID)
}
private fun createSpecPlace(placeMatcher: Matcher, basePlaceMatcher: Matcher = placeMatcher) =
SpecPlace(
placeMatcher.group("sections")?.splitByComma() ?: basePlaceMatcher.group("sections").splitByComma(),
placeMatcher.group("paragraphNumber")?.toInt() ?: basePlaceMatcher.group("paragraphNumber").toInt(),
placeMatcher.group("sentenceNumber").toInt()
)
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!!
val placeMatcher = testInfoElements[LinkedSpecTestFileInfoElementType.PLACE]!!.additionalMatcher!!
val relevantPlacesMatcher = testInfoElements[LinkedSpecTestFileInfoElementType.RELEVANT_PLACES]?.additionalMatcher
val relevantPlaces = relevantPlacesMatcher?.let {
mutableListOf<SpecPlace>().apply {
add(createSpecPlace(it, placeMatcher))
while (it.find()) {
add(createSpecPlace(it, placeMatcher))
}
}
}
return LinkedSpecTest(
testInfoElements[LinkedSpecTestFileInfoElementType.SPEC_VERSION]!!.content,
parsedTestFile.testArea,
parsedTestFile.testType,
parsedTestFile.sections,
testInfoElements[LinkedSpecTestFileInfoElementType.PARAGRAPH]!!.content.toInt(),
sentenceMatcher.group("number").toInt(),
sentenceMatcher.group("text"),
createSpecPlace(placeMatcher),
relevantPlaces,
parsedTestFile.testNumber,
parsedTestFile.testDescription,
parsedTestFile.testCasesSet,
@@ -63,11 +76,13 @@ object CommonParser {
private fun parseNotLinkedSpecTest(testFilePath: String, testFiles: TestFiles): NotLinkedSpecTest {
val parsedTestFile = parseTestInfo(testFilePath, testFiles, SpecTestLinkedType.NOT_LINKED)
val testInfoElements = parsedTestFile.testInfoElements
val sectionsMatcher = testInfoElements[NotLinkedSpecTestFileInfoElementType.SECTIONS]!!.additionalMatcher!!
return NotLinkedSpecTest(
parsedTestFile.testArea,
parsedTestFile.testType,
parsedTestFile.sections,
sectionsMatcher.group("sections").splitByComma(),
parsedTestFile.testNumber,
parsedTestFile.testDescription,
parsedTestFile.testCasesSet,
@@ -13,12 +13,13 @@ 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.MULTILINE_COMMENT_REGEX
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.SECTIONS_IN_FILE_REGEX
import org.jetbrains.kotlin.spec.parsers.CommonPatterns.sectionsInPathRegex
import java.io.File
import java.util.regex.Pattern
@@ -28,20 +29,21 @@ object CommonPatterns {
const val INTEGER_REGEX = """[1-9]\d*"""
const val SINGLE_LINE_COMMENT_REGEX = """\/\/\s*%s"""
const val ASTERISK_REGEX = """\*"""
const val SECTIONS_IN_FILE_REGEX = """[\w-]+(,\s+[\w-]+)*"""
const val MULTILINE_COMMENT_REGEX = """\/\*\s+?%s\s+\*\/(?:\n)*"""
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]*?""")}"""
"""${SINGLE_LINE_COMMENT_REGEX.format("""[\w\s]+:""")}|${MULTILINE_COMMENT_REGEX.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 sectionsInFilePattern: Pattern = Pattern.compile("""(?<sections>$SECTIONS_IN_FILE_REGEX)""")
val sectionsInPathRegex = """(?<sections>(?:[\w-]+)(?:$ps[\w-]+)*?)"""
val packagePattern: Pattern = Pattern.compile("""(?:^|\n)package (?<packageName>.*?)(?:;|\n)""")
}
@@ -59,7 +61,7 @@ object NotLinkedSpecTestPatterns : BasePatterns {
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)"""))
Pattern.compile(MULTILINE_COMMENT_REGEX.format(""" $ASTERISK_REGEX KOTLIN $testAreaRegex NOT LINKED SPEC TEST \($testTypeRegex\)\n(?<infoElements>[\s\S]*?\n)"""))
}
object LinkedSpecTestPatterns : BasePatterns {
@@ -70,9 +72,13 @@ object LinkedSpecTestPatterns : BasePatterns {
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)"""))
Pattern.compile(MULTILINE_COMMENT_REGEX.format(""" $ASTERISK_REGEX KOTLIN $testAreaRegex SPEC TEST \($testTypeRegex\)\n(?<infoElements>[\s\S]*?\n)"""))
val sentencePattern: Pattern = Pattern.compile("""^\[(?<number>$INTEGER_REGEX)\]\s*(?<text>.*?)$""")
val placePattern: Pattern =
Pattern.compile("""(?<sections>$SECTIONS_IN_FILE_REGEX) -> paragraph (?<paragraphNumber>$INTEGER_REGEX) -> sentence (?<sentenceNumber>$INTEGER_REGEX)""")
val relevantPlacesPattern: Pattern =
Pattern.compile("""(( $ASTERISK_REGEX )?\s*((?<sections>$SECTIONS_IN_FILE_REGEX) -> )?(paragraph (?<paragraphNumber>$INTEGER_REGEX) -> )?sentence (?<sentenceNumber>$INTEGER_REGEX))+""")
}
object TestCasePatterns {
@@ -85,7 +91,7 @@ object TestCasePatterns {
testCaseInfoElementsRegex.format("infoElementsSL", "", """\s*.""")
) + testCaseInfoRegex.format("codeSL", "nextDirectiveSL")
private val testCaseInfoMultilineRegex =
multilineCommentRegex.format(
MULTILINE_COMMENT_REGEX.format(
testCaseInfoElementsRegex.format("infoElementsML", """ $ASTERISK_REGEX """, """[\s\S]""")
) + testCaseInfoRegex.format("codeML", "nextDirectiveML")
@@ -18,7 +18,6 @@ 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>,
@@ -47,7 +46,6 @@ fun parseTestInfo(testFilePath: String, testFiles: TestFiles, linkedTestType: Sp
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,
@@ -20,8 +20,8 @@ object TestsJsonMapBuilder {
fun buildJsonElement(testInfo: LinkedSpecTest, testsMap: JsonObject) {
val sectionElement = addJsonIfNotExist(testsMap, testInfo.sections[0])
val paragraphElement = addJsonIfNotExist(sectionElement, testInfo.paragraphNumber)
val sentenceElement = addJsonIfNotExist(paragraphElement, testInfo.sentenceNumber)
val paragraphElement = addJsonIfNotExist(sectionElement, testInfo.place.paragraphNumber)
val sentenceElement = addJsonIfNotExist(paragraphElement, testInfo.place.sentenceNumber)
val testAreaElement = addJsonIfNotExist(sentenceElement, testInfo.testArea.name.toLowerCase())
val testTypeElement = addJsonIfNotExist(testAreaElement, testInfo.testType.type)
val testNumberElement = addJsonIfNotExist(testTypeElement, testInfo.testNumber)