ART: Implement next-line assertions in Checker
Some tests require verifying an exact sequence of lines in the graph
dump. This was already possible by inserting 'CHECK-NOT: {{.*}}'
between the individual lines, but hardly a convenient way of doing so.
This patch introduces a new 'CHECK-NEXT' kind of assertions that
replaces the old method and will become useful for testing assembly.
Change-Id: I1bb951707bda44320166dc7ef828866a6957a113
diff --git a/test/476-checker-ctor-memory-barrier/src/Main.java b/test/476-checker-ctor-memory-barrier/src/Main.java
index 75cb1d7..f24dc4a 100644
--- a/test/476-checker-ctor-memory-barrier/src/Main.java
+++ b/test/476-checker-ctor-memory-barrier/src/Main.java
@@ -27,9 +27,8 @@
public ClassWithFinals obj;
// CHECK-START: void ClassWithFinals.<init>(boolean) register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
public ClassWithFinals(boolean cond) {
x = 0;
if (cond) {
@@ -39,18 +38,16 @@
}
// CHECK-START: void ClassWithFinals.<init>() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
public ClassWithFinals() {
x = 0;
}
// CHECK-START: void ClassWithFinals.<init>(int) register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
public ClassWithFinals(int x) {
// This should have two barriers:
// - one for the constructor
@@ -62,33 +59,32 @@
class InheritFromClassWithFinals extends ClassWithFinals {
// CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public InheritFromClassWithFinals() {
// Should inline the super constructor.
}
// CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
- // CHECK: InvokeStaticOrDirect
+ // CHECK: InvokeStaticOrDirect
// CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
- // CHECK-NOT: MemoryBarrier kind:StoreStore
+ // CHECK-NOT: MemoryBarrier kind:StoreStore
public InheritFromClassWithFinals(boolean cond) {
super(cond);
// should not inline the super constructor
}
// CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: ReturnVoid
// CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public InheritFromClassWithFinals(int unused) {
// Should inline the super constructor and insert a memory barrier.
@@ -101,9 +97,8 @@
final int y;
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
// CHECK-NOT: InvokeStaticOrDirect
@@ -113,10 +108,9 @@
}
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(boolean) register (after)
- // CHECK: InvokeStaticOrDirect
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: InvokeStaticOrDirect
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
public HaveFinalsAndInheritFromClassWithFinals(boolean cond) {
super(cond);
// should not inline the super constructor
@@ -124,14 +118,13 @@
}
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public HaveFinalsAndInheritFromClassWithFinals(int unused) {
// Should inline the super constructor and keep just one memory barrier.
y = 0;
@@ -146,55 +139,51 @@
public class Main {
// CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
- // CHECK: InvokeStaticOrDirect
+ // CHECK: InvokeStaticOrDirect
// CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
- // CHECK-NOT: MemoryBarrier kind:StoreStore
+ // CHECK-NOT: MemoryBarrier kind:StoreStore
public static ClassWithFinals noInlineNoConstructorBarrier() {
return new ClassWithFinals(false);
}
// CHECK-START: void Main.inlineNew() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void Main.inlineNew() register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public static void inlineNew() {
new ClassWithFinals();
}
// CHECK-START: void Main.inlineNew1() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void Main.inlineNew1() register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public static void inlineNew1() {
new InheritFromClassWithFinals();
}
// CHECK-START: void Main.inlineNew2() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void Main.inlineNew2() register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public static void inlineNew2() {
new HaveFinalsAndInheritFromClassWithFinals();
}
// CHECK-START: void Main.inlineNew3() register (after)
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK: MemoryBarrier kind:StoreStore
- // CHECK-NOT: {{.*}}
- // CHECK: ReturnVoid
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NEXT: ReturnVoid
// CHECK-START: void Main.inlineNew3() register (after)
- // CHECK-NOT: InvokeStaticOrDirect
+ // CHECK-NOT: InvokeStaticOrDirect
public static void inlineNew3() {
new HaveFinalsAndInheritFromClassWithFinals();
new HaveFinalsAndInheritFromClassWithFinals();
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
index d7a38da..4eed391 100644
--- a/tools/checker/file_format/checker/parser.py
+++ b/tools/checker/file_format/checker/parser.py
@@ -54,6 +54,11 @@
if plainLine is not None:
return (plainLine, TestAssertion.Variant.InOrder, lineNo), None
+ # 'CHECK-NEXT' lines are in-order but must match the very next line.
+ nextLine = __extractLine(prefix + "-NEXT", line)
+ if nextLine is not None:
+ return (nextLine, TestAssertion.Variant.NextLine, lineNo), None
+
# 'CHECK-DAG' lines are no-order assertions.
dagLine = __extractLine(prefix + "-DAG", line)
if dagLine is not None:
diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py
index 381c92b..6a54142 100644
--- a/tools/checker/file_format/checker/struct.py
+++ b/tools/checker/file_format/checker/struct.py
@@ -42,7 +42,7 @@
self.startLineNo = startLineNo
if not self.name:
- Logger.fail("Test case does not have a name", self.parent.fileName, self.startLineNo)
+ Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
self.parent.addTestCase(self)
@@ -51,6 +51,13 @@
return self.parent.fileName
def addAssertion(self, new_assertion):
+ if new_assertion.variant == TestAssertion.Variant.NextLine:
+ if not self.assertions or \
+ (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
+ self.assertions[-1].variant != TestAssertion.Variant.NextLine):
+ Logger.fail("A next-line assertion can only be placed after an "
+ "in-order assertion or another next-line assertion.",
+ new_assertion.fileName, new_assertion.lineNo)
self.assertions.append(new_assertion)
def __eq__(self, other):
@@ -63,7 +70,7 @@
class Variant(object):
"""Supported types of assertions."""
- InOrder, DAG, Not = range(3)
+ InOrder, NextLine, DAG, Not = range(4)
def __init__(self, parent, variant, originalText, lineNo):
assert isinstance(parent, TestCase)
diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py
index 475e8c3..453deed 100644
--- a/tools/checker/file_format/checker/test.py
+++ b/tools/checker/file_format/checker/test.py
@@ -192,9 +192,12 @@
def assertParsesTo(self, checkerText, expectedData):
expectedFile = self.createFile(expectedData)
- actualFile = ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
+ actualFile = self.parse(checkerText)
return self.assertEqual(expectedFile, actualFile)
+ def parse(self, checkerText):
+ return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
+
def test_EmptyFile(self):
self.assertParsesTo("", [])
@@ -227,12 +230,40 @@
self.assertParsesTo(
"""
// CHECK-START: Example Group
- // CHECK: foo
- // CHECK-NOT: bar
- // CHECK-DAG: abc
- // CHECK-DAG: def
+ // CHECK: foo1
+ // CHECK: foo2
+ // CHECK-NEXT: foo3
+ // CHECK-NEXT: foo4
+ // CHECK-NOT: bar
+ // CHECK-DAG: abc
+ // CHECK-DAG: def
""",
- [ ( "Example Group", [ ("foo", TestAssertion.Variant.InOrder),
+ [ ( "Example Group", [ ("foo1", TestAssertion.Variant.InOrder),
+ ("foo2", TestAssertion.Variant.InOrder),
+ ("foo3", TestAssertion.Variant.NextLine),
+ ("foo4", TestAssertion.Variant.NextLine),
("bar", TestAssertion.Variant.Not),
("abc", TestAssertion.Variant.DAG),
("def", TestAssertion.Variant.DAG) ] ) ])
+
+ def test_MisplacedNext(self):
+ with self.assertRaises(CheckerException):
+ self.parse(
+ """
+ // CHECK-START: Example Group
+ // CHECK-DAG: foo
+ // CHECK-NEXT: bar
+ """)
+ with self.assertRaises(CheckerException):
+ self.parse(
+ """
+ // CHECK-START: Example Group
+ // CHECK-NOT: foo
+ // CHECK-NEXT: bar
+ """)
+ with self.assertRaises(CheckerException):
+ self.parse(
+ """
+ // CHECK-START: Example Group
+ // CHECK-NEXT: bar
+ """)
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
index 6cff2bf..b22211a 100644
--- a/tools/checker/match/file.py
+++ b/tools/checker/match/file.py
@@ -127,6 +127,11 @@
assert len(assertionGroup) == 1
scope = MatchScope(matchFrom, c1Length)
match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
+ elif assertionGroup[0].variant == TestAssertion.Variant.NextLine:
+ # Single next-line assertion. Test if the current line matches.
+ assert len(assertionGroup) == 1
+ scope = MatchScope(matchFrom, matchFrom + 1)
+ match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
else:
# A group of DAG assertions. Match them all starting from the same point.
assert assertionGroup[0].variant == TestAssertion.Variant.DAG
diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py
index e4dd784..348c1d2 100644
--- a/tools/checker/match/test.py
+++ b/tools/checker/match/test.py
@@ -195,6 +195,54 @@
foo
""")
+ def test_NextLineAssertions(self):
+ self.assertMatches(
+ """
+ // CHECK: foo
+ // CHECK-NEXT: bar
+ // CHECK-NEXT: abc
+ // CHECK: def
+ """,
+ """
+ foo
+ bar
+ abc
+ def
+ """)
+ self.assertMatches(
+ """
+ // CHECK: foo
+ // CHECK-NEXT: bar
+ // CHECK: def
+ """,
+ """
+ foo
+ bar
+ abc
+ def
+ """)
+ self.assertDoesNotMatch(
+ """
+ // CHECK: foo
+ // CHECK-NEXT: bar
+ """,
+ """
+ foo
+ abc
+ bar
+ """)
+
+ self.assertDoesNotMatch(
+ """
+ // CHECK: foo
+ // CHECK-NEXT: bar
+ """,
+ """
+ bar
+ foo
+ abc
+ """)
+
def test_DagAssertions(self):
self.assertMatches(
"""