Extended version of AbstractWriteSignatureTest:
- support multiple expectations in file - support field signature expectations - report failures in a more usable format
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
public val list: List<String> = throw Exception()
|
||||||
|
public val mutList: MutableList<String> = throw Exception()
|
||||||
|
|
||||||
|
// field: _DefaultPackage::list
|
||||||
|
// jvm signature: Ljava/util/List;
|
||||||
|
// generic signature: Ljava/util/List<+Ljava/lang/String;>;
|
||||||
|
|
||||||
|
// field: _DefaultPackage::mutList
|
||||||
|
// jvm signature: Ljava/util/List;
|
||||||
|
// generic signature: Ljava/util/List<Ljava/lang/String;>;
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.jvm.compiler;
|
|
||||||
|
|
||||||
import com.google.common.io.Closeables;
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.intellij.openapi.util.Disposer;
|
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
|
|
||||||
import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsPackage;
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
|
|
||||||
import org.jetbrains.kotlin.codegen.GenerationUtils;
|
|
||||||
import org.jetbrains.kotlin.psi.JetFile;
|
|
||||||
import org.jetbrains.kotlin.test.JetTestUtils;
|
|
||||||
import org.jetbrains.kotlin.test.TestCaseWithTmpdir;
|
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader;
|
|
||||||
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
|
||||||
import org.junit.Assert;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test correctness of written JVM signature
|
|
||||||
*
|
|
||||||
* @see CompileJavaAgainstKotlinTestGenerated
|
|
||||||
*/
|
|
||||||
public abstract class AbstractWriteSignatureTest extends TestCaseWithTmpdir {
|
|
||||||
|
|
||||||
private KotlinCoreEnvironment jetCoreEnvironment;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
jetCoreEnvironment = JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(myTestRootDisposable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void tearDown() throws Exception {
|
|
||||||
jetCoreEnvironment = null;
|
|
||||||
super.tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doTest(String ktFileName) throws Exception {
|
|
||||||
File ktFile = new File(ktFileName);
|
|
||||||
String text = FileUtil.loadFile(ktFile, true);
|
|
||||||
|
|
||||||
JetFile psiFile = JetTestUtils.createFile(ktFile.getName(), text, jetCoreEnvironment.getProject());
|
|
||||||
|
|
||||||
OutputFileCollection outputFiles = GenerationUtils.compileFileGetClassFileFactoryForTest(psiFile);
|
|
||||||
|
|
||||||
OutputUtilsPackage.writeAllTo(outputFiles, tmpdir);
|
|
||||||
|
|
||||||
Disposer.dispose(myTestRootDisposable);
|
|
||||||
|
|
||||||
Expectation expectation = parseExpectations(ktFile);
|
|
||||||
|
|
||||||
ActualSignature actualSignature = readSignature(expectation.className, expectation.methodName);
|
|
||||||
|
|
||||||
String template =
|
|
||||||
"jvm signature: %s\n" +
|
|
||||||
"generic signature: %s\n" +
|
|
||||||
"";
|
|
||||||
|
|
||||||
String expected = String.format(template, expectation.jvmSignature, expectation.genericSignature);
|
|
||||||
String actual = String.format(template, actualSignature.jvmSignature, actualSignature.genericSignature);
|
|
||||||
|
|
||||||
Assert.assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ActualSignature {
|
|
||||||
private final String jvmSignature;
|
|
||||||
private final String genericSignature;
|
|
||||||
|
|
||||||
private ActualSignature(@NotNull String jvmSignature, @Nullable String genericSignature) {
|
|
||||||
this.jvmSignature = jvmSignature;
|
|
||||||
this.genericSignature = genericSignature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private ActualSignature readSignature(@NotNull String className, @Nullable final String methodName) throws Exception {
|
|
||||||
// ugly unreadable code begin
|
|
||||||
FileInputStream classInputStream = new FileInputStream(tmpdir + "/" + className.replace('.', '/') + ".class");
|
|
||||||
try {
|
|
||||||
class Visitor extends ClassVisitor {
|
|
||||||
ActualSignature readSignature;
|
|
||||||
|
|
||||||
public Visitor() {
|
|
||||||
super(Opcodes.ASM5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
|
||||||
if (methodName == null) {
|
|
||||||
Assert.assertNull(readSignature);
|
|
||||||
readSignature = new ActualSignature(name, signature);
|
|
||||||
}
|
|
||||||
super.visit(version, access, name, signature, superName, interfaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MethodVisitor visitMethod(int access, String name, final String desc, final String signature, String[] exceptions) {
|
|
||||||
if (name.equals(methodName)) {
|
|
||||||
|
|
||||||
return new MethodVisitor(Opcodes.ASM5) {
|
|
||||||
@Override
|
|
||||||
public void visitEnd() {
|
|
||||||
Assert.assertNull(readSignature);
|
|
||||||
readSignature = new ActualSignature(desc, signature);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Visitor visitor = new Visitor();
|
|
||||||
|
|
||||||
new ClassReader(classInputStream).accept(visitor,
|
|
||||||
ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
|
||||||
|
|
||||||
Assert.assertNotNull("method not found: " + className + "::" + methodName, visitor.readSignature);
|
|
||||||
|
|
||||||
return visitor.readSignature;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Closeables.closeQuietly(classInputStream);
|
|
||||||
}
|
|
||||||
// ugly unreadable code end
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Expectation {
|
|
||||||
private final String className;
|
|
||||||
@Nullable
|
|
||||||
private final String methodName;
|
|
||||||
private final String jvmSignature;
|
|
||||||
private final String genericSignature;
|
|
||||||
|
|
||||||
private Expectation(
|
|
||||||
@NotNull String className, @Nullable String methodName,
|
|
||||||
@NotNull String jvmSignature, @Nullable String genericSignature
|
|
||||||
) {
|
|
||||||
this.className = className;
|
|
||||||
this.methodName = methodName;
|
|
||||||
this.jvmSignature = jvmSignature;
|
|
||||||
this.genericSignature = genericSignature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Pattern classPattern = Pattern.compile("^// class: *(.*)");
|
|
||||||
private static final Pattern methodPattern = Pattern.compile("^// method: *(.*)::(.*?) *(//.*)?");
|
|
||||||
private static final Pattern jvmSignaturePattern = Pattern.compile("^// jvm signature: *(.+?) *(//.*)?");
|
|
||||||
private static final Pattern genericSignaturePattern = Pattern.compile("^// generic signature: *(.+?) *(//.*)?");
|
|
||||||
|
|
||||||
private Expectation parseExpectations(File ktFile) throws IOException {
|
|
||||||
List<String> lines = Files.readLines(ktFile, Charset.forName("utf-8"));
|
|
||||||
for (int i = 0; i < lines.size() - 2; ++i) {
|
|
||||||
String line = lines.get(i);
|
|
||||||
Matcher methodMatcher = methodPattern.matcher(line);
|
|
||||||
Matcher classMatcher = classPattern.matcher(line);
|
|
||||||
boolean isMethod = methodMatcher.matches();
|
|
||||||
boolean isClass = classMatcher.matches();
|
|
||||||
Matcher matcher = isMethod ? methodMatcher : classMatcher;
|
|
||||||
if (isMethod || isClass) {
|
|
||||||
Matcher jvmSignatureMatcher = jvmSignaturePattern.matcher(lines.get(i + 1));
|
|
||||||
Matcher genericSignatureMatcher = genericSignaturePattern.matcher(lines.get(i + 2));
|
|
||||||
if (!jvmSignatureMatcher.matches() || !genericSignatureMatcher.matches()) {
|
|
||||||
throw new AssertionError("'method:' must be followed ... bla bla ... use the source luke");
|
|
||||||
}
|
|
||||||
|
|
||||||
String className = matcher.group(1);
|
|
||||||
String methodName = isMethod ? matcher.group(2) : null;
|
|
||||||
|
|
||||||
String jvmSignature = jvmSignatureMatcher.group(1);
|
|
||||||
String genericSignature = genericSignatureMatcher.group(1);
|
|
||||||
if (genericSignature.equals("null")) {
|
|
||||||
genericSignature = null;
|
|
||||||
}
|
|
||||||
return new Expectation(className, methodName, jvmSignature, genericSignature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new AssertionError("test instructions not found in " + ktFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.jvm.compiler
|
||||||
|
|
||||||
|
import com.google.common.io.Closeables
|
||||||
|
import com.google.common.io.Files
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAllTo
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.codegen.GenerationUtils
|
||||||
|
import org.jetbrains.kotlin.test.JetTestUtils
|
||||||
|
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
|
||||||
|
import org.jetbrains.kotlin.utils.join
|
||||||
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
|
import org.junit.Assert
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.*
|
||||||
|
import java.util.regex.MatchResult
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
import kotlin.text.Regex
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class AbstractWriteSignatureTest : TestCaseWithTmpdir() {
|
||||||
|
private var jetCoreEnvironment: KotlinCoreEnvironment? = null
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
jetCoreEnvironment = JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(myTestRootDisposable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
jetCoreEnvironment = null
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun doTest(ktFileName: String) {
|
||||||
|
val ktFile = File(ktFileName)
|
||||||
|
val text = FileUtil.loadFile(ktFile, true)
|
||||||
|
|
||||||
|
val psiFile = JetTestUtils.createFile(ktFile.getName(), text, jetCoreEnvironment!!.project)
|
||||||
|
|
||||||
|
val outputFiles = GenerationUtils.compileFileGetClassFileFactoryForTest(psiFile)
|
||||||
|
|
||||||
|
outputFiles.writeAllTo(tmpdir)
|
||||||
|
|
||||||
|
Disposer.dispose(myTestRootDisposable)
|
||||||
|
|
||||||
|
val expectations = parseExpectations(ktFile)
|
||||||
|
expectations.check()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SignatureExpectation(val header: String, val name: String, expectedJvmSignature: String, expectedGenericSignature: String) {
|
||||||
|
private var checked = false
|
||||||
|
private val expectedSignature = formatSignature(header, expectedJvmSignature, expectedGenericSignature)
|
||||||
|
|
||||||
|
fun isChecked(): Boolean = checked
|
||||||
|
|
||||||
|
fun check(name: String, actualJvmSignature: String, actualGenericSignature: String) {
|
||||||
|
if (this.name == name) {
|
||||||
|
checked = true
|
||||||
|
val actualSignature = formatSignature(header, actualJvmSignature, actualGenericSignature)
|
||||||
|
Assert.assertEquals(expectedSignature, actualSignature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class PackageExpectationsSuite() {
|
||||||
|
private val classSuitesByClassName = LinkedHashMap<String, ClassExpectationsSuite>()
|
||||||
|
|
||||||
|
fun getOrCreateClassSuite(className: String): ClassExpectationsSuite =
|
||||||
|
classSuitesByClassName.getOrPut(className) { ClassExpectationsSuite(className) }
|
||||||
|
|
||||||
|
fun check() {
|
||||||
|
classSuitesByClassName.values().forEach { it.check() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ClassExpectationsSuite(val className: String) {
|
||||||
|
val classExpectations = ArrayList<SignatureExpectation>()
|
||||||
|
val methodExpectations = ArrayList<SignatureExpectation>()
|
||||||
|
val fieldExpectations = ArrayList<SignatureExpectation>()
|
||||||
|
|
||||||
|
fun check() {
|
||||||
|
val checker = Checker()
|
||||||
|
val classFileName = "$tmpdir/${className.replace('.', '/')}.class"
|
||||||
|
val classFile = File(classFileName)
|
||||||
|
|
||||||
|
checkClassFile(checker, classFile)
|
||||||
|
|
||||||
|
if (className.endsWith("Package")) {
|
||||||
|
// This class is a package facade. We should also check package parts.
|
||||||
|
checkPackageParts(checker, classFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertAllChecked()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPackageParts(checker: Checker, classFile: File) {
|
||||||
|
// Look for package parts in the same directory.
|
||||||
|
// Package part file names for package SomePackage look like SomePackage$<hash>.class.
|
||||||
|
val classDir = classFile.getParentFile()
|
||||||
|
val classLastName = classFile.getName()
|
||||||
|
val packageFacadePrefix = classLastName.replace(".class", "\$")
|
||||||
|
classDir.listFiles { dir, lastName ->
|
||||||
|
lastName.startsWith(packageFacadePrefix) && lastName.endsWith(".class")
|
||||||
|
} forEach { packageFacadeFile ->
|
||||||
|
checkClassFile(checker, packageFacadeFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertAllChecked() {
|
||||||
|
val uncheckedExpectations = ArrayList<SignatureExpectation>()
|
||||||
|
classExpectations.filterNotTo(uncheckedExpectations) { it.isChecked() }
|
||||||
|
methodExpectations.filterNotTo(uncheckedExpectations) { it.isChecked() }
|
||||||
|
fieldExpectations.filterNotTo(uncheckedExpectations) { it.isChecked() }
|
||||||
|
Assert.assertTrue(
|
||||||
|
"Unchecked expectations (${uncheckedExpectations.size()} total):\n " + uncheckedExpectations.join("\n "),
|
||||||
|
uncheckedExpectations.isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkClassFile(checker: Checker, classFile: File) {
|
||||||
|
val classInputStream = FileInputStream(classFile)
|
||||||
|
try {
|
||||||
|
ClassReader(classInputStream).accept(checker,
|
||||||
|
ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Closeables.closeQuietly(classInputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class Checker : ClassVisitor(Opcodes.ASM5) {
|
||||||
|
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<out String>?) {
|
||||||
|
classExpectations forEach { it.check(name, name, signature?:"null") }
|
||||||
|
super.visit(version, access, name, signature, superName, interfaces)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||||
|
methodExpectations forEach { it.check(name, desc, signature?:"null") }
|
||||||
|
return super.visitMethod(access, name, desc, signature, exceptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
||||||
|
fieldExpectations forEach { it.check(name, desc, signature?:"null") }
|
||||||
|
return super.visitField(access, name, desc, signature, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addClassExpectation(name: String, jvmSignature: String, genericSignature: String) {
|
||||||
|
classExpectations.add(SignatureExpectation("class: $name", name, jvmSignature, genericSignature))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addFieldExpectation(className: String, memberName: String, jvmSignature: String, genericSignature: String) {
|
||||||
|
fieldExpectations.add(SignatureExpectation("field: $className::$memberName", memberName, jvmSignature, genericSignature))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addMethodExpectation(className: String, memberName: String, jvmSignature: String, genericSignature: String) {
|
||||||
|
methodExpectations.add(SignatureExpectation("method: $className::$memberName", memberName, jvmSignature, genericSignature))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseExpectations(ktFile: File): PackageExpectationsSuite {
|
||||||
|
val expectations = PackageExpectationsSuite()
|
||||||
|
|
||||||
|
val lines = Files.readLines(ktFile, Charset.forName("utf-8"))
|
||||||
|
var lineNo = 0
|
||||||
|
while (lineNo < lines.size()) {
|
||||||
|
val line = lines[lineNo]
|
||||||
|
val expectationMatch = expectationRegex.matchExact(line)
|
||||||
|
|
||||||
|
if (expectationMatch != null) {
|
||||||
|
val kind = expectationMatch.group(1)!!
|
||||||
|
val className = expectationMatch.group(2)!!
|
||||||
|
val memberName = expectationMatch.group(4)
|
||||||
|
|
||||||
|
if (kind == "class" && memberName != null) {
|
||||||
|
throw AssertionError("$ktFile:${lineNo+1}: use $className\$$memberName to denote inner class")
|
||||||
|
}
|
||||||
|
else if (memberName == null) {
|
||||||
|
throw AssertionError("$ktFile:${lineNo+1}: '$kind' requires member name (after $className::)")
|
||||||
|
}
|
||||||
|
|
||||||
|
val jvmSignatureMatch = jvmSignatureRegex.matchExact(lines[lineNo+1])
|
||||||
|
val genericSignatureMatch = genericSignatureRegex.matchExact(lines[lineNo+2])
|
||||||
|
|
||||||
|
if (jvmSignatureMatch != null && genericSignatureMatch != null) {
|
||||||
|
val jvmSignature = jvmSignatureMatch.group(1)
|
||||||
|
val genericSignature = genericSignatureMatch.group(1)
|
||||||
|
|
||||||
|
val classSuite = expectations.getOrCreateClassSuite(className)
|
||||||
|
|
||||||
|
when (kind) {
|
||||||
|
"class" -> classSuite.addClassExpectation(className, jvmSignature, genericSignature)
|
||||||
|
"field" -> classSuite.addFieldExpectation(className, memberName, jvmSignature, genericSignature)
|
||||||
|
"method" -> classSuite.addMethodExpectation(className, memberName, jvmSignature, genericSignature)
|
||||||
|
else -> throw AssertionError("$ktFile:${lineNo+1}: unsupported expectation kind: $kind")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expectation, skip the following 'jvm signature' and 'generic signature' lines
|
||||||
|
lineNo += 3
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw AssertionError("$ktFile:${lineNo+1}: '$kind' should be followed by 'jvm signature' and 'generic signature'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++lineNo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expectations
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun formatSignature(header: String, jvmSignature: String, genericSignature: String): String =
|
||||||
|
"""// $header
|
||||||
|
// jvm signature: $jvmSignature
|
||||||
|
// generic signature: $genericSignature"""
|
||||||
|
|
||||||
|
val expectationRegex = Regex("^// (class|method|field): *([^:]+)(::(.+)) *(//.*)?")
|
||||||
|
val jvmSignatureRegex = Regex("^// jvm signature: *(.+) *(//.*)?")
|
||||||
|
val genericSignatureRegex = Regex("^// generic signature: *(.+) *(//.*)?")
|
||||||
|
|
||||||
|
fun Regex.matchExact(input: String): MatchResult? {
|
||||||
|
val matcher = this.toPattern().matcher(input)
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return matcher.toMatchResult()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -259,6 +259,12 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("OutInField.kt")
|
||||||
|
public void testOutInField() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/writeSignature/declarationSiteVariance/OutInField.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("OutInInPosition.kt")
|
@TestMetadata("OutInInPosition.kt")
|
||||||
public void testOutInInPosition() throws Exception {
|
public void testOutInInPosition() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/writeSignature/declarationSiteVariance/OutInInPosition.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/writeSignature/declarationSiteVariance/OutInInPosition.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user