diff --git a/compiler/tests-spec/testData/codegen/box/helpers/reflect.kt b/compiler/tests-spec/testData/codegen/box/helpers/reflect.kt new file mode 100644 index 00000000000..5369d9a07a7 --- /dev/null +++ b/compiler/tests-spec/testData/codegen/box/helpers/reflect.kt @@ -0,0 +1,119 @@ +// WITH_RUNTIME +// WITH_REFLECT +// FULL_JDK + + + +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) = + typeParameters.all { checkClassTypeParameter(classRef, it) } + +fun checkCallableTypeParameter(callableRef: KCallable<*>, typeParameter: String) = + getCallableTypeParameter(callableRef, typeParameter) != null + +fun checkCallableTypeParameters(callableRef: KCallable<*>, typeParameters: List) = + typeParameters.all { checkCallableTypeParameter(callableRef, it) } + +fun checkTypeUpperBounds(typeParameter: KTypeParameter, typeParameters: List) = + typeParameters.all { typeParameterName: String -> + typeParameter.upperBounds.find { it.toString() == typeParameterName } != null + } + +fun checkClassTypeParametersWithUpperBounds(classRef: KClass<*>, typeParameters: List>>) = + typeParameters.all { (parameterName, parameterUpperBounds) -> + getClassTypeParameter(classRef, parameterName).let { typeParameter: KTypeParameter? -> + typeParameter != null && checkTypeUpperBounds(typeParameter, parameterUpperBounds) + } + } + +fun checkCallableTypeParametersWithUpperBounds(callableRef: KCallable<*>, typeParameters: List>>) = + 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) = + expectedNames.all { checkFileAnnotation(fileClass, it) } + +fun checkProperties(classRef: KClass<*>, properties: List) = + properties.all { property: String -> + classRef.members.find { it.name == property } != null + } + +fun checkTypeProperties(classRef: KClass<*>, properties: List>) = + properties.all { (propertyName, propertyType) -> + classRef.members.find { it.name == propertyName }?.returnType?.toString() == propertyType + } + +fun checkPropertiesWithAnnotation(classRef: KClass<*>, properties: List>>) = + 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) = + parameterNames.all { checkParameter(functionRef, it) } + +fun checkCallableName(property: KCallable<*>, propertyName: String) = property.name == propertyName diff --git a/compiler/tests-spec/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxCodegenTestSpec.kt b/compiler/tests-spec/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxCodegenTestSpec.kt new file mode 100644 index 00000000000..298512741fa --- /dev/null +++ b/compiler/tests-spec/tests/org/jetbrains/kotlin/codegen/AbstractBlackBoxCodegenTestSpec.kt @@ -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 = "" + 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 (?.*?)(?:;|\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) { + 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, 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) + } +} diff --git a/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/validators/AbstractSpecTestValidator.kt b/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/validators/AbstractSpecTestValidator.kt index d65d48b3b30..1c5d30e47fb 100644 --- a/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/validators/AbstractSpecTestValidator.kt +++ b/compiler/tests-spec/tests/org/jetbrains/kotlin/spec/validators/AbstractSpecTestValidator.kt @@ -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(private val testD val pathSeparator: String = Pattern.quote(File.separator) val lineSeparator: String = System.lineSeparator() - val testAreaRegex = """(?${TestArea.values().joinToString("|")})""" + val testAreaRegex = """(?${TestArea.values().joinToString("|").replace("_", " ")})""" val testTypeRegex = """(?${TestType.values().joinToString("|")})""" - val dirsByLinkedType = mapOf( - SpecTestLinkedType.LINKED to "linked", - SpecTestLinkedType.NOT_LINKED to "notLinked" - ) private val testInfoElementPattern: Pattern = Pattern.compile("""\s*(?[A-Z ]+?)(?::\s*(?.*?))?$lineSeparator""") private val testCaseInfoRegex = """(?CASE DESCRIPTION:[\s\S]*?$lineSeparator)$lineSeparator*""" - private val testPathBaseRegexTemplate = """^.*?$pathSeparator(?diagnostics|psi|codegen)$pathSeparator%s""" + private val testPathBaseRegexTemplate = + """^.*?$pathSeparator(?diagnostics|psi|(?:codegen${pathSeparator}box))$pathSeparator%s""" val testPathRegexTemplate = """$testPathBaseRegexTemplate$pathSeparator(?pos|neg)/%s$""" val testCaseInfoSingleLinePattern: Pattern = Pattern.compile(SINGLELINE_COMMENT_REGEX.format(testCaseInfoRegex)) val testCaseInfoMultilinePattern: Pattern = Pattern.compile(MULTILINE_COMMENT_REGEX.format(testCaseInfoRegex))