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/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(
"""