• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright (C) 2014 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#   http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from common.archs import archs_list
18from file_format.checker.parser import parse_checker_stream
19from file_format.checker.struct import CheckerFile, TestCase, TestStatement, TestExpression
20
21import io
22import unittest
23
24CheckerException = SystemExit
25
26
27class CheckerParser_PrefixTest(unittest.TestCase):
28
29  def try_parse(self, string):
30    checker_text = "/// CHECK-START: pass\n" + string
31    return parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_text))
32
33  def assertParses(self, string):
34    check_file = self.try_parse(string)
35    self.assertEqual(len(check_file.test_cases), 1)
36    self.assertNotEqual(len(check_file.test_cases[0].statements), 0)
37
38  def assertIgnored(self, string):
39    check_file = self.try_parse(string)
40    self.assertEqual(len(check_file.test_cases), 1)
41    self.assertEqual(len(check_file.test_cases[0].statements), 0)
42
43  def assertInvalid(self, string):
44    with self.assertRaises(CheckerException):
45      self.try_parse(string)
46
47  def test_ValidFormat(self):
48    self.assertParses("///CHECK:foo")
49    self.assertParses("##CHECK:bar")
50
51  def test_InvalidFormat(self):
52    self.assertIgnored("CHECK")
53    self.assertIgnored(":CHECK")
54    self.assertIgnored("CHECK:")
55    self.assertIgnored("//CHECK")
56    self.assertIgnored("#CHECK")
57    self.assertInvalid("///CHECK")
58    self.assertInvalid("##CHECK")
59
60  def test_InvalidPrefix(self):
61    self.assertInvalid("///ACHECK:foo")
62    self.assertInvalid("##ACHECK:foo")
63
64  def test_NotFirstOnTheLine(self):
65    self.assertIgnored("A/// CHECK: foo")
66    self.assertIgnored("A # CHECK: foo")
67    self.assertInvalid("/// /// CHECK: foo")
68    self.assertInvalid("## ## CHECK: foo")
69
70  def test_WhitespaceAgnostic(self):
71    self.assertParses("  ///CHECK: foo")
72    self.assertParses("///  CHECK: foo")
73    self.assertParses("    ///CHECK: foo")
74    self.assertParses("///    CHECK: foo")
75
76
77class CheckerParser_TestExpressionTest(unittest.TestCase):
78  def parse_statement(self, string, variant=""):
79    checker_text = ("/// CHECK-START: pass\n" +
80                    "/// CHECK" + variant + ": " + string)
81    checker_file = parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_text))
82    self.assertEqual(len(checker_file.test_cases), 1)
83    test_case = checker_file.test_cases[0]
84    self.assertEqual(len(test_case.statements), 1)
85    return test_case.statements[0]
86
87  def parse_expression(self, string):
88    line = self.parse_statement(string)
89    self.assertEqual(1, len(line.expressions))
90    return line.expressions[0]
91
92  def assertEqualsRegex(self, string, expected):
93    self.assertEqual(expected, self.parse_statement(string).to_regex())
94
95  def assertEqualsText(self, string, text):
96    self.assertEqual(self.parse_expression(string),
97                     TestExpression.create_pattern_from_plain_text(text))
98
99  def assertEqualsPattern(self, string, pattern):
100    self.assertEqual(self.parse_expression(string), TestExpression.create_pattern(pattern))
101
102  def assertEqualsVarRef(self, string, name):
103    self.assertEqual(self.parse_expression(string), TestExpression.create_variable_reference(name))
104
105  def assertEqualsVarDef(self, string, name, pattern):
106    self.assertEqual(self.parse_expression(string),
107                     TestExpression.create_variable_definition(name, pattern))
108
109  def assertVariantNotEqual(self, string, variant):
110    self.assertNotEqual(variant, self.parse_expression(string).variant)
111
112  # Test that individual parts of the line are recognized
113
114  def test_TextOnly(self):
115    self.assertEqualsText("foo", "foo")
116    self.assertEqualsText("  foo  ", "foo")
117    self.assertEqualsRegex("f$o^o", "(f\\$o\\^o)")
118
119  def test_PatternOnly(self):
120    self.assertEqualsPattern("{{a?b.c}}", "a?b.c")
121
122  def test_VarRefOnly(self):
123    self.assertEqualsVarRef("<<ABC>>", "ABC")
124
125  def test_VarDefOnly(self):
126    self.assertEqualsVarDef("<<ABC:a?b.c>>", "ABC", "a?b.c")
127
128  def test_TextWithWhitespace(self):
129    self.assertEqualsRegex("foo bar", "(foo), (bar)")
130    self.assertEqualsRegex("foo   bar", "(foo), (bar)")
131
132  def test_TextWithRegex(self):
133    self.assertEqualsRegex("foo{{abc}}bar", "(foo)(abc)(bar)")
134
135  def test_TextWithVar(self):
136    self.assertEqualsRegex("foo<<ABC:abc>>bar", "(foo)(abc)(bar)")
137
138  def test_PlainWithRegexAndWhitespaces(self):
139    self.assertEqualsRegex("foo {{abc}}bar", "(foo), (abc)(bar)")
140    self.assertEqualsRegex("foo{{abc}} bar", "(foo)(abc), (bar)")
141    self.assertEqualsRegex("foo {{abc}} bar", "(foo), (abc), (bar)")
142
143  def test_PlainWithVarAndWhitespaces(self):
144    self.assertEqualsRegex("foo <<ABC:abc>>bar", "(foo), (abc)(bar)")
145    self.assertEqualsRegex("foo<<ABC:abc>> bar", "(foo)(abc), (bar)")
146    self.assertEqualsRegex("foo <<ABC:abc>> bar", "(foo), (abc), (bar)")
147
148  def test_AllKinds(self):
149    self.assertEqualsRegex("foo <<ABC:abc>>{{def}}bar", "(foo), (abc)(def)(bar)")
150    self.assertEqualsRegex("foo<<ABC:abc>> {{def}}bar", "(foo)(abc), (def)(bar)")
151    self.assertEqualsRegex("foo <<ABC:abc>> {{def}} bar", "(foo), (abc), (def), (bar)")
152
153  # # Test that variables and patterns are parsed correctly
154
155  def test_ValidPattern(self):
156    self.assertEqualsPattern("{{abc}}", "abc")
157    self.assertEqualsPattern("{{a[b]c}}", "a[b]c")
158    self.assertEqualsPattern("{{(a{bc})}}", "(a{bc})")
159
160  def test_ValidRef(self):
161    self.assertEqualsVarRef("<<ABC>>", "ABC")
162    self.assertEqualsVarRef("<<A1BC2>>", "A1BC2")
163
164  def test_ValidDef(self):
165    self.assertEqualsVarDef("<<ABC:abc>>", "ABC", "abc")
166    self.assertEqualsVarDef("<<ABC:ab:c>>", "ABC", "ab:c")
167    self.assertEqualsVarDef("<<ABC:a[b]c>>", "ABC", "a[b]c")
168    self.assertEqualsVarDef("<<ABC:(a[bc])>>", "ABC", "(a[bc])")
169
170  def test_Empty(self):
171    self.assertEqualsText("{{}}", "{{}}")
172    self.assertVariantNotEqual("<<>>", TestExpression.Variant.VAR_REF)
173    self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VAR_DEF)
174
175  def test_InvalidVarName(self):
176    self.assertVariantNotEqual("<<0ABC>>", TestExpression.Variant.VAR_REF)
177    self.assertVariantNotEqual("<<AB=C>>", TestExpression.Variant.VAR_REF)
178    self.assertVariantNotEqual("<<ABC=>>", TestExpression.Variant.VAR_REF)
179    self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VAR_DEF)
180    self.assertVariantNotEqual("<<AB=C:abc>>", TestExpression.Variant.VAR_DEF)
181    self.assertVariantNotEqual("<<ABC=:abc>>", TestExpression.Variant.VAR_DEF)
182
183  def test_BodyMatchNotGreedy(self):
184    self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)")
185    self.assertEqualsRegex("<<ABC:abc>><<DEF:def>>", "(abc)(def)")
186
187  def test_NoVarDefsInNotChecks(self):
188    with self.assertRaises(CheckerException):
189      self.parse_statement("<<ABC:abc>>", "-NOT")
190
191
192class CheckerParser_FileLayoutTest(unittest.TestCase):
193
194  # Creates an instance of CheckerFile from provided info.
195  # Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
196  def create_file(self, case_list):
197    test_file = CheckerFile("<test_file>")
198    for caseEntry in case_list:
199      case_name = caseEntry[0]
200      test_case = TestCase(test_file, case_name, 0)
201      statement_list = caseEntry[1]
202      for statementEntry in statement_list:
203        content = statementEntry[0]
204        variant = statementEntry[1]
205        statement = TestStatement(test_case, variant, content, 0)
206        if statement.is_eval_content_statement():
207          statement.add_expression(TestExpression.create_plain_text(content))
208        elif statement.is_pattern_match_content_statement():
209          statement.add_expression(TestExpression.create_pattern_from_plain_text(content))
210    return test_file
211
212  def assertParsesTo(self, checker_text, expected_data):
213    expected_file = self.create_file(expected_data)
214    actual_file = self.parse(checker_text)
215    return self.assertEqual(expected_file, actual_file)
216
217  def parse(self, checker_text):
218    return parse_checker_stream("<test_file>", "CHECK", io.StringIO(checker_text))
219
220  def test_EmptyFile(self):
221    self.assertParsesTo("", [])
222
223  def test_SingleGroup(self):
224    self.assertParsesTo(
225      """
226        /// CHECK-START: Example Group
227        /// CHECK:  foo
228        /// CHECK:    bar
229      """,
230      [("Example Group", [("foo", TestStatement.Variant.IN_ORDER),
231                          ("bar", TestStatement.Variant.IN_ORDER)])])
232
233  def test_MultipleGroups(self):
234    self.assertParsesTo(
235      """
236        /// CHECK-START: Example Group1
237        /// CHECK: foo
238        /// CHECK: bar
239        /// CHECK-START: Example Group2
240        /// CHECK: abc
241        /// CHECK: def
242      """,
243      [("Example Group1", [("foo", TestStatement.Variant.IN_ORDER),
244                           ("bar", TestStatement.Variant.IN_ORDER)]),
245       ("Example Group2", [("abc", TestStatement.Variant.IN_ORDER),
246                           ("def", TestStatement.Variant.IN_ORDER)])])
247
248  def test_StatementVariants(self):
249    self.assertParsesTo(
250      """
251        /// CHECK-START: Example Group
252        /// CHECK:      foo1
253        /// CHECK:      foo2
254        /// CHECK-NEXT: foo3
255        /// CHECK-NEXT: foo4
256        /// CHECK-NOT:  bar
257        /// CHECK-DAG:  abc
258        /// CHECK-DAG:  def
259        /// CHECK-EVAL: x > y
260        /// CHECK-IF:   x < y
261        /// CHECK-ELIF: x == y
262        /// CHECK-ELSE:
263        /// CHECK-FI:
264      """,
265      [("Example Group", [("foo1", TestStatement.Variant.IN_ORDER),
266                          ("foo2", TestStatement.Variant.IN_ORDER),
267                          ("foo3", TestStatement.Variant.NEXT_LINE),
268                          ("foo4", TestStatement.Variant.NEXT_LINE),
269                          ("bar", TestStatement.Variant.NOT),
270                          ("abc", TestStatement.Variant.DAG),
271                          ("def", TestStatement.Variant.DAG),
272                          ("x > y", TestStatement.Variant.EVAL),
273                          ("x < y", TestStatement.Variant.IF),
274                          ("x == y", TestStatement.Variant.ELIF),
275                          (None, TestStatement.Variant.ELSE),
276                          (None, TestStatement.Variant.FI)])])
277
278  def test_NoContentStatements(self):
279    with self.assertRaises(CheckerException):
280      self.parse(
281        """
282          /// CHECK-START: Example Group
283          /// CHECK-ELSE:    foo
284        """)
285    with self.assertRaises(CheckerException):
286      self.parse(
287        """
288          /// CHECK-START: Example Group
289          /// CHECK-FI:      foo
290        """)
291
292
293class CheckerParser_SuffixTests(unittest.TestCase):
294  NOARCH_BLOCK = """
295                  /// CHECK-START: Group
296                  /// CHECK:       foo
297                  /// CHECK-NEXT:  bar
298                  /// CHECK-NOT:   baz
299                  /// CHECK-DAG:   yoyo
300                  /// CHECK-EVAL: x > y
301                  /// CHECK-IF:   x < y
302                  /// CHECK-ELIF: x == y
303                  /// CHECK-ELSE:
304                  /// CHECK-FI:
305                """
306
307  ARCH_BLOCK = """
308                  /// CHECK-START-{test_arch}: Group
309                  /// CHECK:       foo
310                  /// CHECK-NEXT:  bar
311                  /// CHECK-NOT:   baz
312                  /// CHECK-DAG:   yoyo
313                  /// CHECK-EVAL: x > y
314                  /// CHECK-IF:   x < y
315                  /// CHECK-ELIF: x == y
316                  /// CHECK-ELSE:
317                  /// CHECK-FI:
318                """
319
320  def parse(self, checker_text):
321    return parse_checker_stream("<test_file>", "CHECK", io.StringIO(checker_text))
322
323  def test_NonArchTests(self):
324    for arch in [None] + archs_list:
325      checker_file = self.parse(self.NOARCH_BLOCK)
326      self.assertEqual(len(checker_file.test_cases), 1)
327      self.assertEqual(len(checker_file.test_cases[0].statements), 9)
328
329  def test_IgnoreNonTargetArch(self):
330    for target_arch in archs_list:
331      for test_arch in [a for a in archs_list if a != target_arch]:
332        checker_text = self.ARCH_BLOCK.format(test_arch=test_arch)
333        checker_file = self.parse(checker_text)
334        self.assertEqual(len(checker_file.test_cases), 1)
335        self.assertEqual(len(checker_file.test_cases_for_arch(test_arch)), 1)
336        self.assertEqual(len(checker_file.test_cases_for_arch(target_arch)), 0)
337
338  def test_Arch(self):
339    for arch in archs_list:
340      checker_text = self.ARCH_BLOCK.format(test_arch=arch)
341      checker_file = self.parse(checker_text)
342      self.assertEqual(len(checker_file.test_cases), 1)
343      self.assertEqual(len(checker_file.test_cases_for_arch(arch)), 1)
344      self.assertEqual(len(checker_file.test_cases[0].statements), 9)
345
346  def test_NoDebugAndArch(self):
347    test_case = self.parse("""
348        /// CHECK-START: Group
349        /// CHECK: foo
350        """).test_cases[0]
351    self.assertFalse(test_case.for_debuggable)
352    self.assertEqual(test_case.test_arch, None)
353
354  def test_SetDebugNoArch(self):
355    test_case = self.parse("""
356        /// CHECK-START-DEBUGGABLE: Group
357        /// CHECK: foo
358        """).test_cases[0]
359    self.assertTrue(test_case.for_debuggable)
360    self.assertEqual(test_case.test_arch, None)
361
362  def test_NoDebugSetArch(self):
363    test_case = self.parse("""
364        /// CHECK-START-ARM: Group
365        /// CHECK: foo
366        """).test_cases[0]
367    self.assertFalse(test_case.for_debuggable)
368    self.assertEqual(test_case.test_arch, "ARM")
369
370  def test_SetDebugAndArch(self):
371    test_case = self.parse("""
372        /// CHECK-START-ARM-DEBUGGABLE: Group
373        /// CHECK: foo
374        """).test_cases[0]
375    self.assertTrue(test_case.for_debuggable)
376    self.assertEqual(test_case.test_arch, "ARM")
377
378
379class CheckerParser_EvalTests(unittest.TestCase):
380  def parse_test_case(self, string):
381    checker_text = "/// CHECK-START: pass\n" + string
382    checker_file = parse_checker_stream("<test-file>", "CHECK", io.StringIO(checker_text))
383    self.assertEqual(len(checker_file.test_cases), 1)
384    return checker_file.test_cases[0]
385
386  def parse_expressions(self, string):
387    test_case = self.parse_test_case("/// CHECK-EVAL: " + string)
388    self.assertEqual(len(test_case.statements), 1)
389    statement = test_case.statements[0]
390    self.assertEqual(statement.variant, TestStatement.Variant.EVAL)
391    self.assertEqual(statement.original_text, string)
392    return statement.expressions
393
394  def assertParsesToPlainText(self, text):
395    test_case = self.parse_test_case("/// CHECK-EVAL: " + text)
396    self.assertEqual(len(test_case.statements), 1)
397    statement = test_case.statements[0]
398    self.assertEqual(statement.variant, TestStatement.Variant.EVAL)
399    self.assertEqual(statement.original_text, text)
400    self.assertEqual(len(statement.expressions), 1)
401    expression = statement.expressions[0]
402    self.assertEqual(expression.variant, TestExpression.Variant.PLAIN_TEXT)
403    self.assertEqual(expression.text, text)
404
405  def test_PlainText(self):
406    self.assertParsesToPlainText("XYZ")
407    self.assertParsesToPlainText("True")
408    self.assertParsesToPlainText("{{abc}}")
409    self.assertParsesToPlainText("<<ABC:abc>>")
410    self.assertParsesToPlainText("<<ABC=>>")
411
412  def test_VariableReference(self):
413    self.assertEqual(self.parse_expressions("<<ABC>>"),
414                     [TestExpression.create_variable_reference("ABC")])
415    self.assertEqual(self.parse_expressions("123<<ABC>>"),
416                     [TestExpression.create_plain_text("123"),
417                      TestExpression.create_variable_reference("ABC")])
418    self.assertEqual(self.parse_expressions("123  <<ABC>>"),
419                     [TestExpression.create_plain_text("123  "),
420                      TestExpression.create_variable_reference("ABC")])
421    self.assertEqual(self.parse_expressions("<<ABC>>XYZ"),
422                     [TestExpression.create_variable_reference("ABC"),
423                      TestExpression.create_plain_text("XYZ")])
424    self.assertEqual(self.parse_expressions("<<ABC>>   XYZ"),
425                     [TestExpression.create_variable_reference("ABC"),
426                      TestExpression.create_plain_text("   XYZ")])
427    self.assertEqual(self.parse_expressions("123<<ABC>>XYZ"),
428                     [TestExpression.create_plain_text("123"),
429                      TestExpression.create_variable_reference("ABC"),
430                      TestExpression.create_plain_text("XYZ")])
431    self.assertEqual(self.parse_expressions("123 <<ABC>>  XYZ"),
432                     [TestExpression.create_plain_text("123 "),
433                      TestExpression.create_variable_reference("ABC"),
434                      TestExpression.create_plain_text("  XYZ")])
435