1#!/usr/bin/env python2
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 common.testing             import ToUnicode
19from file_format.checker.parser import ParseCheckerStream
20from file_format.checker.struct import CheckerFile, TestCase, TestStatement, TestExpression
21
22import io
23import unittest
24
25CheckerException = SystemExit
26
27class CheckerParser_PrefixTest(unittest.TestCase):
28
29  def tryParse(self, string):
30    checkerText = u"/// CHECK-START: pass\n" + ToUnicode(string)
31    return ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
32
33  def assertParses(self, string):
34    checkFile = self.tryParse(string)
35    self.assertEqual(len(checkFile.testCases), 1)
36    self.assertNotEqual(len(checkFile.testCases[0].statements), 0)
37
38  def assertIgnored(self, string):
39    checkFile = self.tryParse(string)
40    self.assertEqual(len(checkFile.testCases), 1)
41    self.assertEqual(len(checkFile.testCases[0].statements), 0)
42
43  def assertInvalid(self, string):
44    with self.assertRaises(CheckerException):
45      self.tryParse(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
76class CheckerParser_TestExpressionTest(unittest.TestCase):
77
78  def parseStatement(self, string, variant=""):
79    checkerText = (u"/// CHECK-START: pass\n" +
80                   u"/// CHECK" + ToUnicode(variant) + u": " + ToUnicode(string))
81    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
82    self.assertEqual(len(checkerFile.testCases), 1)
83    testCase = checkerFile.testCases[0]
84    self.assertEqual(len(testCase.statements), 1)
85    return testCase.statements[0]
86
87  def parseExpression(self, string):
88    line = self.parseStatement(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.parseStatement(string).toRegex())
94
95  def assertEqualsText(self, string, text):
96    self.assertEqual(self.parseExpression(string), TestExpression.createPatternFromPlainText(text))
97
98  def assertEqualsPattern(self, string, pattern):
99    self.assertEqual(self.parseExpression(string), TestExpression.createPattern(pattern))
100
101  def assertEqualsVarRef(self, string, name):
102    self.assertEqual(self.parseExpression(string), TestExpression.createVariableReference(name))
103
104  def assertEqualsVarDef(self, string, name, pattern):
105    self.assertEqual(self.parseExpression(string),
106                     TestExpression.createVariableDefinition(name, pattern))
107
108  def assertVariantNotEqual(self, string, variant):
109    self.assertNotEqual(variant, self.parseExpression(string).variant)
110
111  # Test that individual parts of the line are recognized
112
113  def test_TextOnly(self):
114    self.assertEqualsText("foo", "foo")
115    self.assertEqualsText("  foo  ", "foo")
116    self.assertEqualsRegex("f$o^o", "(f\$o\^o)")
117
118  def test_PatternOnly(self):
119    self.assertEqualsPattern("{{a?b.c}}", "a?b.c")
120
121  def test_VarRefOnly(self):
122    self.assertEqualsVarRef("<<ABC>>", "ABC")
123
124  def test_VarDefOnly(self):
125    self.assertEqualsVarDef("<<ABC:a?b.c>>", "ABC", "a?b.c")
126
127  def test_TextWithWhitespace(self):
128    self.assertEqualsRegex("foo bar", "(foo), (bar)")
129    self.assertEqualsRegex("foo   bar", "(foo), (bar)")
130
131  def test_TextWithRegex(self):
132    self.assertEqualsRegex("foo{{abc}}bar", "(foo)(abc)(bar)")
133
134  def test_TextWithVar(self):
135    self.assertEqualsRegex("foo<<ABC:abc>>bar", "(foo)(abc)(bar)")
136
137  def test_PlainWithRegexAndWhitespaces(self):
138    self.assertEqualsRegex("foo {{abc}}bar", "(foo), (abc)(bar)")
139    self.assertEqualsRegex("foo{{abc}} bar", "(foo)(abc), (bar)")
140    self.assertEqualsRegex("foo {{abc}} bar", "(foo), (abc), (bar)")
141
142  def test_PlainWithVarAndWhitespaces(self):
143    self.assertEqualsRegex("foo <<ABC:abc>>bar", "(foo), (abc)(bar)")
144    self.assertEqualsRegex("foo<<ABC:abc>> bar", "(foo)(abc), (bar)")
145    self.assertEqualsRegex("foo <<ABC:abc>> bar", "(foo), (abc), (bar)")
146
147  def test_AllKinds(self):
148    self.assertEqualsRegex("foo <<ABC:abc>>{{def}}bar", "(foo), (abc)(def)(bar)")
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
152  # # Test that variables and patterns are parsed correctly
153
154  def test_ValidPattern(self):
155    self.assertEqualsPattern("{{abc}}", "abc")
156    self.assertEqualsPattern("{{a[b]c}}", "a[b]c")
157    self.assertEqualsPattern("{{(a{bc})}}", "(a{bc})")
158
159  def test_ValidRef(self):
160    self.assertEqualsVarRef("<<ABC>>", "ABC")
161    self.assertEqualsVarRef("<<A1BC2>>", "A1BC2")
162
163  def test_ValidDef(self):
164    self.assertEqualsVarDef("<<ABC:abc>>", "ABC", "abc")
165    self.assertEqualsVarDef("<<ABC:ab:c>>", "ABC", "ab:c")
166    self.assertEqualsVarDef("<<ABC:a[b]c>>", "ABC", "a[b]c")
167    self.assertEqualsVarDef("<<ABC:(a[bc])>>", "ABC", "(a[bc])")
168
169  def test_Empty(self):
170    self.assertEqualsText("{{}}", "{{}}")
171    self.assertVariantNotEqual("<<>>", TestExpression.Variant.VarRef)
172    self.assertVariantNotEqual("<<:>>", TestExpression.Variant.VarDef)
173
174  def test_InvalidVarName(self):
175    self.assertVariantNotEqual("<<0ABC>>", TestExpression.Variant.VarRef)
176    self.assertVariantNotEqual("<<AB=C>>", TestExpression.Variant.VarRef)
177    self.assertVariantNotEqual("<<ABC=>>", TestExpression.Variant.VarRef)
178    self.assertVariantNotEqual("<<0ABC:abc>>", TestExpression.Variant.VarDef)
179    self.assertVariantNotEqual("<<AB=C:abc>>", TestExpression.Variant.VarDef)
180    self.assertVariantNotEqual("<<ABC=:abc>>", TestExpression.Variant.VarDef)
181
182  def test_BodyMatchNotGreedy(self):
183    self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)")
184    self.assertEqualsRegex("<<ABC:abc>><<DEF:def>>", "(abc)(def)")
185
186  def test_NoVarDefsInNotChecks(self):
187    with self.assertRaises(CheckerException):
188      self.parseStatement("<<ABC:abc>>", "-NOT")
189
190
191class CheckerParser_FileLayoutTest(unittest.TestCase):
192
193  # Creates an instance of CheckerFile from provided info.
194  # Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
195  def createFile(self, caseList):
196    testFile = CheckerFile("<test_file>")
197    for caseEntry in caseList:
198      caseName = caseEntry[0]
199      testCase = TestCase(testFile, caseName, 0)
200      statementList = caseEntry[1]
201      for statementEntry in statementList:
202        content = statementEntry[0]
203        variant = statementEntry[1]
204        statement = TestStatement(testCase, variant, content, 0)
205        if statement.isEvalContentStatement():
206          statement.addExpression(TestExpression.createPlainText(content))
207        elif statement.isPatternMatchContentStatement():
208          statement.addExpression(TestExpression.createPatternFromPlainText(content))
209    return testFile
210
211  def assertParsesTo(self, checkerText, expectedData):
212    expectedFile = self.createFile(expectedData)
213    actualFile = self.parse(checkerText)
214    return self.assertEqual(expectedFile, actualFile)
215
216  def parse(self, checkerText):
217    return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
218
219  def test_EmptyFile(self):
220    self.assertParsesTo("", [])
221
222  def test_SingleGroup(self):
223    self.assertParsesTo(
224      """
225        /// CHECK-START: Example Group
226        /// CHECK:  foo
227        /// CHECK:    bar
228      """,
229      [ ( "Example Group", [ ("foo", TestStatement.Variant.InOrder),
230                             ("bar", TestStatement.Variant.InOrder) ] ) ])
231
232  def test_MultipleGroups(self):
233    self.assertParsesTo(
234      """
235        /// CHECK-START: Example Group1
236        /// CHECK: foo
237        /// CHECK: bar
238        /// CHECK-START: Example Group2
239        /// CHECK: abc
240        /// CHECK: def
241      """,
242      [ ( "Example Group1", [ ("foo", TestStatement.Variant.InOrder),
243                              ("bar", TestStatement.Variant.InOrder) ] ),
244        ( "Example Group2", [ ("abc", TestStatement.Variant.InOrder),
245                              ("def", TestStatement.Variant.InOrder) ] ) ])
246
247  def test_StatementVariants(self):
248    self.assertParsesTo(
249      """
250        /// CHECK-START: Example Group
251        /// CHECK:      foo1
252        /// CHECK:      foo2
253        /// CHECK-NEXT: foo3
254        /// CHECK-NEXT: foo4
255        /// CHECK-NOT:  bar
256        /// CHECK-DAG:  abc
257        /// CHECK-DAG:  def
258        /// CHECK-EVAL: x > y
259        /// CHECK-IF:   x < y
260        /// CHECK-ELIF: x == y
261        /// CHECK-ELSE:
262        /// CHECK-FI:
263      """,
264      [ ( "Example Group", [ ("foo1", TestStatement.Variant.InOrder),
265                             ("foo2", TestStatement.Variant.InOrder),
266                             ("foo3", TestStatement.Variant.NextLine),
267                             ("foo4", TestStatement.Variant.NextLine),
268                             ("bar", TestStatement.Variant.Not),
269                             ("abc", TestStatement.Variant.DAG),
270                             ("def", TestStatement.Variant.DAG),
271                             ("x > y", TestStatement.Variant.Eval),
272                             ("x < y", TestStatement.Variant.If),
273                             ("x == y", TestStatement.Variant.Elif),
274                             (None, TestStatement.Variant.Else),
275                             (None, TestStatement.Variant.Fi) ] ) ])
276
277  def test_NoContentStatements(self):
278    with self.assertRaises(CheckerException):
279      self.parse(
280        """
281          /// CHECK-START: Example Group
282          /// CHECK-ELSE:    foo
283        """)
284    with self.assertRaises(CheckerException):
285      self.parse(
286        """
287          /// CHECK-START: Example Group
288          /// CHECK-FI:      foo
289        """)
290
291class CheckerParser_SuffixTests(unittest.TestCase):
292
293  noarch_block = """
294                  /// CHECK-START: Group
295                  /// CHECK:       foo
296                  /// CHECK-NEXT:  bar
297                  /// CHECK-NOT:   baz
298                  /// CHECK-DAG:   yoyo
299                  /// CHECK-EVAL: x > y
300                  /// CHECK-IF:   x < y
301                  /// CHECK-ELIF: x == y
302                  /// CHECK-ELSE:
303                  /// CHECK-FI:
304                """
305
306  arch_block = """
307                  /// CHECK-START-{test_arch}: Group
308                  /// CHECK:       foo
309                  /// CHECK-NEXT:  bar
310                  /// CHECK-NOT:   baz
311                  /// CHECK-DAG:   yoyo
312                  /// CHECK-EVAL: x > y
313                  /// CHECK-IF:   x < y
314                  /// CHECK-ELIF: x == y
315                  /// CHECK-ELSE:
316                  /// CHECK-FI:
317                """
318
319  def parse(self, checkerText):
320    return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
321
322  def test_NonArchTests(self):
323    for arch in [None] + archs_list:
324      checkerFile = self.parse(self.noarch_block)
325      self.assertEqual(len(checkerFile.testCases), 1)
326      self.assertEqual(len(checkerFile.testCases[0].statements), 9)
327
328  def test_IgnoreNonTargetArch(self):
329    for targetArch in archs_list:
330      for testArch in [a for a in archs_list if a != targetArch]:
331        checkerText = self.arch_block.format(test_arch = testArch)
332        checkerFile = self.parse(checkerText)
333        self.assertEqual(len(checkerFile.testCases), 1)
334        self.assertEqual(len(checkerFile.testCasesForArch(testArch)), 1)
335        self.assertEqual(len(checkerFile.testCasesForArch(targetArch)), 0)
336
337  def test_Arch(self):
338    for arch in archs_list:
339      checkerText = self.arch_block.format(test_arch = arch)
340      checkerFile = self.parse(checkerText)
341      self.assertEqual(len(checkerFile.testCases), 1)
342      self.assertEqual(len(checkerFile.testCasesForArch(arch)), 1)
343      self.assertEqual(len(checkerFile.testCases[0].statements), 9)
344
345  def test_NoDebugAndArch(self):
346    testCase = self.parse("""
347        /// CHECK-START: Group
348        /// CHECK: foo
349        """).testCases[0]
350    self.assertFalse(testCase.forDebuggable)
351    self.assertEqual(testCase.testArch, None)
352
353  def test_SetDebugNoArch(self):
354    testCase = self.parse("""
355        /// CHECK-START-DEBUGGABLE: Group
356        /// CHECK: foo
357        """).testCases[0]
358    self.assertTrue(testCase.forDebuggable)
359    self.assertEqual(testCase.testArch, None)
360
361  def test_NoDebugSetArch(self):
362    testCase = self.parse("""
363        /// CHECK-START-ARM: Group
364        /// CHECK: foo
365        """).testCases[0]
366    self.assertFalse(testCase.forDebuggable)
367    self.assertEqual(testCase.testArch, "ARM")
368
369  def test_SetDebugAndArch(self):
370    testCase = self.parse("""
371        /// CHECK-START-ARM-DEBUGGABLE: Group
372        /// CHECK: foo
373        """).testCases[0]
374    self.assertTrue(testCase.forDebuggable)
375    self.assertEqual(testCase.testArch, "ARM")
376
377class CheckerParser_EvalTests(unittest.TestCase):
378  def parseTestCase(self, string):
379    checkerText = u"/// CHECK-START: pass\n" + ToUnicode(string)
380    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
381    self.assertEqual(len(checkerFile.testCases), 1)
382    return checkerFile.testCases[0]
383
384  def parseExpressions(self, string):
385    testCase = self.parseTestCase("/// CHECK-EVAL: " + string)
386    self.assertEqual(len(testCase.statements), 1)
387    statement = testCase.statements[0]
388    self.assertEqual(statement.variant, TestStatement.Variant.Eval)
389    self.assertEqual(statement.originalText, string)
390    return statement.expressions
391
392  def assertParsesToPlainText(self, text):
393    testCase = self.parseTestCase("/// CHECK-EVAL: " + text)
394    self.assertEqual(len(testCase.statements), 1)
395    statement = testCase.statements[0]
396    self.assertEqual(statement.variant, TestStatement.Variant.Eval)
397    self.assertEqual(statement.originalText, text)
398    self.assertEqual(len(statement.expressions), 1)
399    expression = statement.expressions[0]
400    self.assertEqual(expression.variant, TestExpression.Variant.PlainText)
401    self.assertEqual(expression.text, text)
402
403  def test_PlainText(self):
404    self.assertParsesToPlainText("XYZ")
405    self.assertParsesToPlainText("True")
406    self.assertParsesToPlainText("{{abc}}")
407    self.assertParsesToPlainText("<<ABC:abc>>")
408    self.assertParsesToPlainText("<<ABC=>>")
409
410  def test_VariableReference(self):
411    self.assertEqual(self.parseExpressions("<<ABC>>"),
412                     [ TestExpression.createVariableReference("ABC") ])
413    self.assertEqual(self.parseExpressions("123<<ABC>>"),
414                     [ TestExpression.createPlainText("123"),
415                       TestExpression.createVariableReference("ABC") ])
416    self.assertEqual(self.parseExpressions("123  <<ABC>>"),
417                     [ TestExpression.createPlainText("123  "),
418                       TestExpression.createVariableReference("ABC") ])
419    self.assertEqual(self.parseExpressions("<<ABC>>XYZ"),
420                     [ TestExpression.createVariableReference("ABC"),
421                       TestExpression.createPlainText("XYZ") ])
422    self.assertEqual(self.parseExpressions("<<ABC>>   XYZ"),
423                     [ TestExpression.createVariableReference("ABC"),
424                       TestExpression.createPlainText("   XYZ") ])
425    self.assertEqual(self.parseExpressions("123<<ABC>>XYZ"),
426                     [ TestExpression.createPlainText("123"),
427                       TestExpression.createVariableReference("ABC"),
428                       TestExpression.createPlainText("XYZ") ])
429    self.assertEqual(self.parseExpressions("123 <<ABC>>  XYZ"),
430                     [ TestExpression.createPlainText("123 "),
431                       TestExpression.createVariableReference("ABC"),
432                       TestExpression.createPlainText("  XYZ") ])
433