Add test on bytecode text

Test data should be a Kotlin source file with zero or more comments e.g. of
the form: '// 1 INVOKEVIRTUAL'. The test then checks that the generated
bytecode for this file contains exactly one occurrence of the string
'INVOKEVIRTUAL'
This commit is contained in:
Alexander Udalov
2013-02-09 21:44:33 +04:00
parent fe96a0172d
commit 620143ae5b
23 changed files with 259 additions and 169 deletions
@@ -14,4 +14,6 @@ class Tester() {
fun S.component4() = ((a + b) as java.lang.String).substring(2)
}
fun box() = Tester().box()
fun box() = Tester().box()
// 1 NEW S
@@ -0,0 +1,3 @@
fun foo() = 10!!.toString()
// 0 IFNONNULL
@@ -0,0 +1,5 @@
val a : Int? = 10
fun foo() = a!!.toString()
// 1 IFNONNULL
@@ -0,0 +1,5 @@
val a : Int? = 10
fun foo() = a?.toString()
// 1 IFNULL
@@ -0,0 +1,3 @@
fun foo() = 10?.toString()
// 0 IFNULL
@@ -15,4 +15,7 @@ class B {
fun foo() {
foo = 2
}
}
}
// 0 INVOKEVIRTUAL
// 4 INVOKESPECIAL
@@ -12,5 +12,6 @@ class Child: Base<String>() {
override fun bar() {
super.bar()
}
}
// 1 bridge
@@ -11,3 +11,6 @@ class B {
fun box(): String {
return "OK"
}
// 0 INVOKEVIRTUAL
// 3 INVOKESPECIAL
@@ -7,3 +7,5 @@ fun foo(b: Boolean) {
z(b)
}
}
// 0 GETSTATIC
@@ -3,3 +3,5 @@ fun foo(b: Boolean) {
} else {
}
}
// 0 GETSTATIC
@@ -7,3 +7,5 @@ fun foo(x: Int) {
else -> {}
}
}
// 0 GETSTATIC
@@ -7,3 +7,5 @@ fun foo(x: Int) {
else -> {}
}
}
// 0 GETSTATIC
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2013 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.jet.codegen;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.ConfigurationKind;
import org.jetbrains.jet.utils.ExceptionUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class AbstractBytecodeTextTest extends CodegenTestCase {
private static final Pattern EXPECTED_OCCURRENCES_PATTERN = Pattern.compile("^\\s*//\\s*(\\d+)\\s*(.*)$");
public void doTest(@NotNull String filename) throws Exception {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
loadFileByFullPath(filename);
List<OccurrenceInfo> expected = readExpectedOccurrences(filename);
countAndCompareActualOccurrences(expected);
}
private void countAndCompareActualOccurrences(@NotNull List<OccurrenceInfo> expectedOccurrences) {
StringBuilder expected = new StringBuilder();
StringBuilder actual = new StringBuilder();
String text = generateToText();
for (OccurrenceInfo info : expectedOccurrences) {
expected.append(info.numberOfOccurrences).append(" ").append(info.needle).append("\n");
int actualCount = StringUtil.getOccurrenceCount(text, info.needle);
actual.append(actualCount).append(" ").append(info.needle).append("\n");
}
try {
assertEquals(expected.toString(), actual.toString());
}
catch (Throwable e) {
System.out.println(text);
ExceptionUtils.rethrow(e);
}
}
@NotNull
private List<OccurrenceInfo> readExpectedOccurrences(@NotNull String filename) throws Exception {
List<OccurrenceInfo> result = new ArrayList<OccurrenceInfo>();
String[] lines = FileUtil.loadFile(new File(filename), true).split("\n");
for (String line : lines) {
Matcher matcher = EXPECTED_OCCURRENCES_PATTERN.matcher(line);
if (matcher.matches()) {
int numberOfOccurrences = Integer.parseInt(matcher.group(1));
String needle = matcher.group(2);
result.add(new OccurrenceInfo(numberOfOccurrences, needle));
}
}
return result;
}
private static class OccurrenceInfo {
private final int numberOfOccurrences;
private final String needle;
private OccurrenceInfo(int numberOfOccurrences, @NotNull String needle) {
this.numberOfOccurrences = numberOfOccurrences;
this.needle = needle;
}
}
}
@@ -0,0 +1,124 @@
/*
* Copyright 2010-2013 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.jet.codegen;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.codegen.AbstractBytecodeTextTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/bytecodeText")
@InnerTestClasses({BytecodeTextTestGenerated.Statements.class})
public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
public void testAllFilesPresentInBytecodeText() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/bytecodeText"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("componentEvaluatesOnlyOnce.kt")
public void testComponentEvaluatesOnlyOnce() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/componentEvaluatesOnlyOnce.kt");
}
@TestMetadata("intConstantNotNull.kt")
public void testIntConstantNotNull() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/intConstantNotNull.kt");
}
@TestMetadata("intConstantNullable.kt")
public void testIntConstantNullable() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/intConstantNullable.kt");
}
@TestMetadata("intConstantNullableSafeCall.kt")
public void testIntConstantNullableSafeCall() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/intConstantNullableSafeCall.kt");
}
@TestMetadata("intConstantSafeCall.kt")
public void testIntConstantSafeCall() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/intConstantSafeCall.kt");
}
@TestMetadata("kt2202.kt")
public void testKt2202() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/kt2202.kt");
}
@TestMetadata("kt2887.kt")
public void testKt2887() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/kt2887.kt");
}
@TestMetadata("privateDefaultArgs.kt")
public void testPrivateDefaultArgs() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt");
}
@TestMetadata("compiler/testData/codegen/bytecodeText/statements")
public static class Statements extends AbstractBytecodeTextTest {
public void testAllFilesPresentInStatements() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/bytecodeText/statements"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("ifSingleBranch.kt")
public void testIfSingleBranch() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/statements/ifSingleBranch.kt");
}
@TestMetadata("ifThenElse.kt")
public void testIfThenElse() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/statements/ifThenElse.kt");
}
@TestMetadata("ifThenElseEmpty.kt")
public void testIfThenElseEmpty() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/statements/ifThenElseEmpty.kt");
}
@TestMetadata("tryCatchFinally.kt")
public void testTryCatchFinally() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/statements/tryCatchFinally.kt");
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/statements/when.kt");
}
@TestMetadata("whenSubject.kt")
public void testWhenSubject() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/statements/whenSubject.kt");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("BytecodeTextTestGenerated");
suite.addTestSuite(BytecodeTextTestGenerated.class);
suite.addTestSuite(Statements.class);
return suite;
}
}
@@ -1,32 +0,0 @@
/*
* Copyright 2010-2013 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.jet.codegen;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.jet.ConfigurationKind;
/**
* This test is separate from MultiDeclTestGenerated because we specifically test generated bytecode
* that expression does not evaluated several time
*/
public class ComponentGenTest extends CodegenTestCase {
public void testComponent() {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
loadFile("componentEvaluatesOnlyOnce.kt");
assertEquals(1, StringUtils.countMatches(generateToText(), "NEW S\n"));
}
}
@@ -54,11 +54,4 @@ public class FunctionGenTest extends CodegenTestCase {
assertTrue((Boolean) foo.invoke(null, "lala"));
assertFalse((Boolean) foo.invoke(null, "mama"));
}
public void testPrivateDefaultArgs() throws Exception {
loadFile("functions/privateDefaultArgs.kt");
String text = generateToText();
assertFalse(text.contains("INVOKEVIRTUAL"));
assertTrue(text.contains("INVOKESPECIAL"));
}
}
@@ -271,24 +271,4 @@ public class PrimitiveTypesTest extends CodegenTestCase {
final Method main = generateFunction();
assertEquals(expected, main.invoke(null, arg1, arg2));
}
public void testSureNonnull () throws Exception {
loadText("fun box() = 10!!.toString()");
assertFalse(generateToText().contains("IFNONNULL"));
}
public void testSureNullable () throws Exception {
loadText("val a : Int? = 10; fun box() = a!!.toString()");
assertTrue(generateToText().contains("IFNONNULL"));
}
public void testSafeNonnull () throws Exception {
loadText("fun box() = 10?.toString()");
assertFalse(generateToText().contains("IFNULL"));
}
public void testSafeNullable () throws Exception {
loadText("val a : Int? = 10; fun box() = a?.toString()");
assertTrue(generateToText().contains("IFNULL"));
}
}
@@ -259,12 +259,4 @@ public class PropertyGenTest extends CodegenTestCase {
throw new RuntimeException(e);
}
}
public void testKt2202() {
loadFile("properties/kt2202.kt");
String text = generateToText();
assertFalse(text.contains("INVOKEVIRTUAL"));
assertTrue(text.contains("INVOKESPECIAL"));
}
}
@@ -1,63 +0,0 @@
/*
* Copyright 2010-2013 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.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.ConfigurationKind;
public class StatementGenTest extends CodegenTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
}
private void doTest() {
loadFile("statements/" + getTestName(true) + ".kt");
String text = generateToText();
// 'getstatic' means we refer to Unit.VALUE, which we shouldn't since these tests contain only statements
assertNoGetStatic(text);
}
private void assertNoGetStatic(@NotNull String text) {
assertFalse(text, text.toLowerCase().contains("getstatic"));
}
public void testIfSingleBranch() {
doTest();
}
public void testIfThenElse() {
doTest();
}
public void testIfThenElseEmpty() {
doTest();
}
public void testTryCatchFinally() {
doTest();
}
public void testWhen() {
doTest();
}
public void testWhenSubject() {
doTest();
}
}
@@ -1,36 +0,0 @@
/*
* Copyright 2010-2013 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.jet.codegen;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.jet.ConfigurationKind;
public class SuperGenTest extends CodegenTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
}
public void testKt2887() {
loadFile("super/kt2887.kt");
String text = generateToText();
// There should be exactly one bridge in this example
assertEquals(1, StringUtils.countMatches(text, "bridge"));
}
}
@@ -20,6 +20,7 @@ import junit.framework.TestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve;
import org.jetbrains.jet.checkers.AbstractJetPsiCheckerTest;
import org.jetbrains.jet.codegen.AbstractBytecodeTextTest;
import org.jetbrains.jet.codegen.AbstractCheckLocalVariablesTableTest;
import org.jetbrains.jet.codegen.defaultConstructor.AbstractDefaultConstructorCodegenTest;
import org.jetbrains.jet.codegen.flags.AbstractWriteFlagsTest;
@@ -96,6 +97,13 @@ public class GenerateTests {
testModel("compiler/testData/codegen/boxWithStdlib", "doTestWithStdlib")
);
generateTest(
"compiler/tests/",
"BytecodeTextTestGenerated",
AbstractBytecodeTextTest.class,
testModel("compiler/testData/codegen/bytecodeText")
);
generateTest(
"compiler/tests/",
"CheckLocalVariablesTableTestGenerated",