Add codegen box spec tests support

This commit is contained in:
victor.petukhov
2018-09-25 12:45:17 +03:00
parent 8538866778
commit 6f95e4ae3b
3 changed files with 194 additions and 13 deletions
@@ -0,0 +1,119 @@
// WITH_RUNTIME
// WITH_REFLECT
// FULL_JDK
<!PACKAGE!>
import kotlin.reflect.*
import kotlin.reflect.full.*
fun checkAnnotation(className: String, annotationName: String) =
Class.forName(className).annotations.find { it.annotationClass.qualifiedName == annotationName } != null
fun checkSuperClass(classRef: KClass<*>, superClassName: String) =
classRef.superclasses.find { it.qualifiedName == superClassName } != null
private fun getClassTypeParameter(classRef: KClass<*>, typeParameter: String) =
classRef.typeParameters.find { it.name == typeParameter }
private fun getCallableTypeParameter(callableRef: KCallable<*>, typeParameter: String) =
callableRef.typeParameters.find { it.name == typeParameter }
private fun getParameter(functionRef: KFunction<*>, parameterName: String) =
functionRef.parameters.find { it.name == parameterName }
fun checkClassTypeParameter(classRef: KClass<*>, typeParameter: String) = getClassTypeParameter(classRef, typeParameter) != null
fun checkClassTypeParameters(classRef: KClass<*>, typeParameters: List<String>) =
typeParameters.all { checkClassTypeParameter(classRef, it) }
fun checkCallableTypeParameter(callableRef: KCallable<*>, typeParameter: String) =
getCallableTypeParameter(callableRef, typeParameter) != null
fun checkCallableTypeParameters(callableRef: KCallable<*>, typeParameters: List<String>) =
typeParameters.all { checkCallableTypeParameter(callableRef, it) }
fun checkTypeUpperBounds(typeParameter: KTypeParameter, typeParameters: List<String>) =
typeParameters.all { typeParameterName: String ->
typeParameter.upperBounds.find { it.toString() == typeParameterName } != null
}
fun checkClassTypeParametersWithUpperBounds(classRef: KClass<*>, typeParameters: List<Pair<String, List<String>>>) =
typeParameters.all { (parameterName, parameterUpperBounds) ->
getClassTypeParameter(classRef, parameterName).let { typeParameter: KTypeParameter? ->
typeParameter != null && checkTypeUpperBounds(typeParameter, parameterUpperBounds)
}
}
fun checkCallableTypeParametersWithUpperBounds(callableRef: KCallable<*>, typeParameters: List<Pair<String, List<String>>>) =
typeParameters.all { (parameterName, parameterUpperBounds) ->
getCallableTypeParameter(callableRef, parameterName).let { typeParameter: KTypeParameter? ->
typeParameter != null && checkTypeUpperBounds(typeParameter, parameterUpperBounds)
}
}
fun checkSuperTypeAnnotation(classRef: KClass<*>, superClassName: String, annotationName: String): Boolean {
val superType = classRef.supertypes.find { it.classifier.toString() == superClassName }
return superType?.annotations?.find { it.annotationClass.qualifiedName == annotationName } != null ?: false
}
fun checkClassName(ref: KClass<*>, expectedQualifiedName: String) = ref.qualifiedName == expectedQualifiedName
fun checkPackageName(fileClass: String, expectedName: String) =
Class.forName(fileClass).`package`.name == expectedName
fun checkFileAnnotation(fileClass: String, expectedName: String) =
Class.forName(fileClass)?.annotations?.find { it.annotationClass.qualifiedName == expectedName } != null ?: false
fun checkFileAnnotations(fileClass: String, expectedNames: List<String>) =
expectedNames.all { checkFileAnnotation(fileClass, it) }
fun checkProperties(classRef: KClass<*>, properties: List<String>) =
properties.all { property: String ->
classRef.members.find { it.name == property } != null
}
fun checkTypeProperties(classRef: KClass<*>, properties: List<Pair<String, String>>) =
properties.all { (propertyName, propertyType) ->
classRef.members.find { it.name == propertyName }?.returnType?.toString() == propertyType
}
fun checkPropertiesWithAnnotation(classRef: KClass<*>, properties: List<Pair<String, List<String>>>) =
properties.all { (propertyName, propertyAnnotations) ->
val foundProperty = classRef.members.find { it.name == propertyName }
foundProperty.let {
it != null && propertyAnnotations.all { expectedAnnotationName: String ->
it.annotations.find { it.annotationClass.qualifiedName == expectedAnnotationName } != null
}
}
}
fun checkPropertyAnnotation(propertyRef: KProperty<*>, expectedQualifiedName: String) =
propertyRef.annotations.find { it.annotationClass.qualifiedName == expectedQualifiedName } != null
fun checkPropertyType(propertyRef: KProperty<*>, expectedType: String) =
propertyRef.returnType.toString() == expectedType
fun checkFunctionAnnotation(functionRef: KFunction<*>, expectedQualifiedName: String) =
functionRef.annotations.find { it.annotationClass.qualifiedName == expectedQualifiedName } != null
fun checkCompanionObjectName(classRef: KClass<*>, expectedQualifiedName: String) =
classRef.companionObject?.qualifiedName == expectedQualifiedName
fun checkFunctionName(functionRef: KFunction<*>, expectedQualifiedName: String) = functionRef.name == expectedQualifiedName
fun checkSetterParameterName(propertyRef: KMutableProperty<*>, expectedName: String) =
propertyRef.setter.parameters.find { it.name == expectedName } != null
fun checkParameterType(functionRef: KFunction<*>, parameterName: String, expectedType: String) =
getParameter(functionRef, parameterName)?.type.toString() == expectedType ?: false
fun checkParameter(functionRef: KFunction<*>, parameterName: String) =
getParameter(functionRef, parameterName) != null
fun checkParameters(functionRef: KFunction<*>, parameterNames: List<String>) =
parameterNames.all { checkParameter(functionRef, it) }
fun checkCallableName(property: KCallable<*>, propertyName: String) = property.name == propertyName
@@ -0,0 +1,65 @@
/*
* 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.codegen
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
abstract class AbstractBlackBoxCodegenTestSpec : AbstractBlackBoxCodegenTest() {
companion object {
private const val CODEGEN_BOX_TESTDATA_PATH = "$TESTDATA_PATH/codegen/box"
private const val HELPERS_PATH = "$CODEGEN_BOX_TESTDATA_PATH/helpers"
private const val HELPERS_PACKAGE_VARIABLE = "<!PACKAGE!>"
private const val HELPERS_DIRECTIVE = "// HELPERS:"
// map of pairs: source helper filename - target helper filename
private val helperDirectives = mapOf(
"REFLECT" to "reflect.kt"
)
private val packagePattern = Pattern.compile("""(?:^|\n)package (?<packageName>.*?)(?:;|\n)""")
}
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 helpersSpecified = InTextDirectivesUtils.findListWithPrefixes(fileContent, HELPERS_DIRECTIVE)
val packageName = packagePattern.matcher(fileContent).let {
if (it.find()) it.group("packageName") else null
}
helpersSpecified.forEach {
if (helperDirectives.contains(it)) {
val helperContent = File("$HELPERS_PATH/${helperDirectives[it]}").readText()
files.add(
TestFile(helperDirectives[it]!!, addPackageDirectiveToHelperFile(helperContent, packageName))
)
}
}
}
override fun doMultiFileTest(wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?) {
val testValidator = AbstractSpecTestValidator.getInstanceByType(wholeFile)
try {
testValidator.parseTestInfo()
} catch (e: SpecTestValidationException) {
Assert.fail(e.description)
}
testValidator.printTestInfo()
includeHelpers(wholeFile, files)
super.doMultiFileTest(wholeFile, files, javaFilesDir)
}
}
@@ -19,15 +19,15 @@ enum class TestType(val type: String) {
}
}
enum class TestArea {
PSI,
DIAGNOSTICS,
CODEGEN
enum class TestArea(val testDataPath: String) {
PSI("psi"),
DIAGNOSTICS("diagnostics"),
CODEGEN_BOX("codegen/box")
}
enum class SpecTestLinkedType {
LINKED,
NOT_LINKED
enum class SpecTestLinkedType(val testDataPath: String) {
LINKED("linked"),
NOT_LINKED("notLinked")
}
interface SpecTestInfoElementType {
@@ -108,15 +108,12 @@ abstract class AbstractSpecTestValidator<T : AbstractSpecTest>(private val testD
val pathSeparator: String = Pattern.quote(File.separator)
val lineSeparator: String = System.lineSeparator()
val testAreaRegex = """(?<testArea>${TestArea.values().joinToString("|")})"""
val testAreaRegex = """(?<testArea>${TestArea.values().joinToString("|").replace("_", " ")})"""
val testTypeRegex = """(?<testType>${TestType.values().joinToString("|")})"""
val dirsByLinkedType = mapOf(
SpecTestLinkedType.LINKED to "linked",
SpecTestLinkedType.NOT_LINKED to "notLinked"
)
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%s"""
private val testPathBaseRegexTemplate =
"""^.*?$pathSeparator(?<testArea>diagnostics|psi|(?:codegen${pathSeparator}box))$pathSeparator%s"""
val testPathRegexTemplate = """$testPathBaseRegexTemplate$pathSeparator(?<testType>pos|neg)/%s$"""
val testCaseInfoSingleLinePattern: Pattern = Pattern.compile(SINGLELINE_COMMENT_REGEX.format(testCaseInfoRegex))
val testCaseInfoMultilinePattern: Pattern = Pattern.compile(MULTILINE_COMMENT_REGEX.format(testCaseInfoRegex))