blob: 667ca900794d6e63cf321a3bbef7696f73064ce6 [file] [log] [blame]
David Brazdil123c5e92015-01-20 09:28:38 +00001#!/usr/bin/env python2
David Brazdilee690a32014-12-01 17:04:16 +00002#
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
17# This is a test file which exercises all feautres supported by the domain-
18# specific markup language implemented by Checker.
19
20import checker
21import io
22import unittest
23
David Brazdil2e15cd22014-12-31 17:28:38 +000024# The parent type of exception expected to be thrown by Checker during tests.
25# It must be specific enough to not cover exceptions thrown due to actual flaws
David Brazdil48942de2015-01-07 21:19:50 +000026# in Checker.
David Brazdil2e15cd22014-12-31 17:28:38 +000027CheckerException = SystemExit
28
David Brazdilee690a32014-12-01 17:04:16 +000029
30class TestCheckFile_PrefixExtraction(unittest.TestCase):
31 def __tryParse(self, string):
32 checkFile = checker.CheckFile(None, [])
33 return checkFile._extractLine("CHECK", string)
34
35 def test_InvalidFormat(self):
36 self.assertIsNone(self.__tryParse("CHECK"))
37 self.assertIsNone(self.__tryParse(":CHECK"))
38 self.assertIsNone(self.__tryParse("CHECK:"))
39 self.assertIsNone(self.__tryParse("//CHECK"))
40 self.assertIsNone(self.__tryParse("#CHECK"))
41
42 self.assertIsNotNone(self.__tryParse("//CHECK:foo"))
43 self.assertIsNotNone(self.__tryParse("#CHECK:bar"))
44
45 def test_InvalidLabel(self):
46 self.assertIsNone(self.__tryParse("//ACHECK:foo"))
47 self.assertIsNone(self.__tryParse("#ACHECK:foo"))
48
49 def test_NotFirstOnTheLine(self):
50 self.assertIsNone(self.__tryParse("A// CHECK: foo"))
51 self.assertIsNone(self.__tryParse("A # CHECK: foo"))
52 self.assertIsNone(self.__tryParse("// // CHECK: foo"))
53 self.assertIsNone(self.__tryParse("# # CHECK: foo"))
54
55 def test_WhitespaceAgnostic(self):
56 self.assertIsNotNone(self.__tryParse(" //CHECK: foo"))
57 self.assertIsNotNone(self.__tryParse("// CHECK: foo"))
58 self.assertIsNotNone(self.__tryParse(" //CHECK: foo"))
59 self.assertIsNotNone(self.__tryParse("// CHECK: foo"))
60
61
62class TestCheckLine_Parse(unittest.TestCase):
David Brazdilb86e7792015-01-27 15:54:30 +000063 def __getPartPattern(self, linePart):
64 if linePart.variant == checker.CheckElement.Variant.Separator:
65 return "\s+"
66 else:
67 return linePart.pattern
68
David Brazdilee690a32014-12-01 17:04:16 +000069 def __getRegex(self, checkLine):
David Brazdilb86e7792015-01-27 15:54:30 +000070 return "".join(map(lambda x: "(" + self.__getPartPattern(x) + ")", checkLine.lineParts))
David Brazdilee690a32014-12-01 17:04:16 +000071
72 def __tryParse(self, string):
73 return checker.CheckLine(string)
74
75 def __parsesTo(self, string, expected):
76 self.assertEqual(expected, self.__getRegex(self.__tryParse(string)))
77
David Brazdil9a6f20e2014-12-19 11:17:21 +000078 def __tryParseNot(self, string):
David Brazdil2e15cd22014-12-31 17:28:38 +000079 return checker.CheckLine(string, checker.CheckLine.Variant.Not)
David Brazdil9a6f20e2014-12-19 11:17:21 +000080
David Brazdilee690a32014-12-01 17:04:16 +000081 def __parsesPattern(self, string, pattern):
82 line = self.__tryParse(string)
83 self.assertEqual(1, len(line.lineParts))
84 self.assertEqual(checker.CheckElement.Variant.Pattern, line.lineParts[0].variant)
85 self.assertEqual(pattern, line.lineParts[0].pattern)
86
87 def __parsesVarRef(self, string, name):
88 line = self.__tryParse(string)
89 self.assertEqual(1, len(line.lineParts))
90 self.assertEqual(checker.CheckElement.Variant.VarRef, line.lineParts[0].variant)
91 self.assertEqual(name, line.lineParts[0].name)
92
93 def __parsesVarDef(self, string, name, body):
94 line = self.__tryParse(string)
95 self.assertEqual(1, len(line.lineParts))
96 self.assertEqual(checker.CheckElement.Variant.VarDef, line.lineParts[0].variant)
97 self.assertEqual(name, line.lineParts[0].name)
98 self.assertEqual(body, line.lineParts[0].pattern)
99
100 def __doesNotParse(self, string, partType):
101 line = self.__tryParse(string)
102 self.assertEqual(1, len(line.lineParts))
103 self.assertNotEqual(partType, line.lineParts[0].variant)
104
105 # Test that individual parts of the line are recognized
106
107 def test_TextOnly(self):
108 self.__parsesTo("foo", "(foo)")
109 self.__parsesTo(" foo ", "(foo)")
110 self.__parsesTo("f$o^o", "(f\$o\^o)")
111
112 def test_TextWithWhitespace(self):
113 self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
114 self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
115
116 def test_RegexOnly(self):
117 self.__parsesPattern("{{a?b.c}}", "a?b.c")
118
119 def test_VarRefOnly(self):
120 self.__parsesVarRef("[[ABC]]", "ABC")
121
122 def test_VarDefOnly(self):
123 self.__parsesVarDef("[[ABC:a?b.c]]", "ABC", "a?b.c")
124
125 def test_TextWithRegex(self):
126 self.__parsesTo("foo{{abc}}bar", "(foo)(abc)(bar)")
127
128 def test_TextWithVar(self):
129 self.__parsesTo("foo[[ABC:abc]]bar", "(foo)(abc)(bar)")
130
131 def test_PlainWithRegexAndWhitespaces(self):
132 self.__parsesTo("foo {{abc}}bar", "(foo)(\s+)(abc)(bar)")
133 self.__parsesTo("foo{{abc}} bar", "(foo)(abc)(\s+)(bar)")
134 self.__parsesTo("foo {{abc}} bar", "(foo)(\s+)(abc)(\s+)(bar)")
135
136 def test_PlainWithVarAndWhitespaces(self):
137 self.__parsesTo("foo [[ABC:abc]]bar", "(foo)(\s+)(abc)(bar)")
138 self.__parsesTo("foo[[ABC:abc]] bar", "(foo)(abc)(\s+)(bar)")
139 self.__parsesTo("foo [[ABC:abc]] bar", "(foo)(\s+)(abc)(\s+)(bar)")
140
141 def test_AllKinds(self):
142 self.__parsesTo("foo [[ABC:abc]]{{def}}bar", "(foo)(\s+)(abc)(def)(bar)")
143 self.__parsesTo("foo[[ABC:abc]] {{def}}bar", "(foo)(abc)(\s+)(def)(bar)")
144 self.__parsesTo("foo [[ABC:abc]] {{def}} bar", "(foo)(\s+)(abc)(\s+)(def)(\s+)(bar)")
145
146 # Test that variables and patterns are parsed correctly
147
148 def test_ValidPattern(self):
149 self.__parsesPattern("{{abc}}", "abc")
150 self.__parsesPattern("{{a[b]c}}", "a[b]c")
151 self.__parsesPattern("{{(a{bc})}}", "(a{bc})")
152
153 def test_ValidRef(self):
154 self.__parsesVarRef("[[ABC]]", "ABC")
155 self.__parsesVarRef("[[A1BC2]]", "A1BC2")
156
157 def test_ValidDef(self):
158 self.__parsesVarDef("[[ABC:abc]]", "ABC", "abc")
159 self.__parsesVarDef("[[ABC:ab:c]]", "ABC", "ab:c")
160 self.__parsesVarDef("[[ABC:a[b]c]]", "ABC", "a[b]c")
161 self.__parsesVarDef("[[ABC:(a[bc])]]", "ABC", "(a[bc])")
162
163 def test_Empty(self):
164 self.__doesNotParse("{{}}", checker.CheckElement.Variant.Pattern)
165 self.__doesNotParse("[[]]", checker.CheckElement.Variant.VarRef)
166 self.__doesNotParse("[[:]]", checker.CheckElement.Variant.VarDef)
167
168 def test_InvalidVarName(self):
169 self.__doesNotParse("[[0ABC]]", checker.CheckElement.Variant.VarRef)
170 self.__doesNotParse("[[AB=C]]", checker.CheckElement.Variant.VarRef)
171 self.__doesNotParse("[[ABC=]]", checker.CheckElement.Variant.VarRef)
172 self.__doesNotParse("[[0ABC:abc]]", checker.CheckElement.Variant.VarDef)
173 self.__doesNotParse("[[AB=C:abc]]", checker.CheckElement.Variant.VarDef)
174 self.__doesNotParse("[[ABC=:abc]]", checker.CheckElement.Variant.VarDef)
175
176 def test_BodyMatchNotGreedy(self):
177 self.__parsesTo("{{abc}}{{def}}", "(abc)(def)")
178 self.__parsesTo("[[ABC:abc]][[DEF:def]]", "(abc)(def)")
179
David Brazdil9a6f20e2014-12-19 11:17:21 +0000180 def test_NoVarDefsInNotChecks(self):
David Brazdil2e15cd22014-12-31 17:28:38 +0000181 with self.assertRaises(CheckerException):
David Brazdil9a6f20e2014-12-19 11:17:21 +0000182 self.__tryParseNot("[[ABC:abc]]")
David Brazdilee690a32014-12-01 17:04:16 +0000183
184class TestCheckLine_Match(unittest.TestCase):
185 def __matchSingle(self, checkString, outputString, varState={}):
186 checkLine = checker.CheckLine(checkString)
187 newVarState = checkLine.match(outputString, varState)
188 self.assertIsNotNone(newVarState)
189 return newVarState
190
191 def __notMatchSingle(self, checkString, outputString, varState={}):
192 checkLine = checker.CheckLine(checkString)
193 self.assertIsNone(checkLine.match(outputString, varState))
194
195 def test_TextAndWhitespace(self):
196 self.__matchSingle("foo", "foo")
David Brazdilb86e7792015-01-27 15:54:30 +0000197 self.__matchSingle("foo", " foo ")
David Brazdilee690a32014-12-01 17:04:16 +0000198 self.__matchSingle("foo", "foo bar")
David Brazdilb86e7792015-01-27 15:54:30 +0000199 self.__notMatchSingle("foo", "XfooX")
David Brazdilee690a32014-12-01 17:04:16 +0000200 self.__notMatchSingle("foo", "zoo")
201
202 self.__matchSingle("foo bar", "foo bar")
203 self.__matchSingle("foo bar", "abc foo bar def")
204 self.__matchSingle("foo bar", "foo foo bar bar")
David Brazdilb86e7792015-01-27 15:54:30 +0000205
206 self.__matchSingle("foo bar", "foo X bar")
207 self.__notMatchSingle("foo bar", "foo Xbar")
David Brazdilee690a32014-12-01 17:04:16 +0000208
209 def test_Pattern(self):
210 self.__matchSingle("foo{{A|B}}bar", "fooAbar")
211 self.__matchSingle("foo{{A|B}}bar", "fooBbar")
212 self.__notMatchSingle("foo{{A|B}}bar", "fooCbar")
213
214 def test_VariableReference(self):
215 self.__matchSingle("foo[[X]]bar", "foobar", {"X": ""})
216 self.__matchSingle("foo[[X]]bar", "fooAbar", {"X": "A"})
217 self.__matchSingle("foo[[X]]bar", "fooBbar", {"X": "B"})
218 self.__notMatchSingle("foo[[X]]bar", "foobar", {"X": "A"})
219 self.__notMatchSingle("foo[[X]]bar", "foo bar", {"X": "A"})
David Brazdil2e15cd22014-12-31 17:28:38 +0000220 with self.assertRaises(CheckerException):
David Brazdilee690a32014-12-01 17:04:16 +0000221 self.__matchSingle("foo[[X]]bar", "foobar", {})
222
223 def test_VariableDefinition(self):
224 self.__matchSingle("foo[[X:A|B]]bar", "fooAbar")
225 self.__matchSingle("foo[[X:A|B]]bar", "fooBbar")
226 self.__notMatchSingle("foo[[X:A|B]]bar", "fooCbar")
227
228 env = self.__matchSingle("foo[[X:A.*B]]bar", "fooABbar", {})
229 self.assertEqual(env, {"X": "AB"})
230 env = self.__matchSingle("foo[[X:A.*B]]bar", "fooAxxBbar", {})
231 self.assertEqual(env, {"X": "AxxB"})
232
233 self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarAbaz")
234 self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooBbarBbaz")
235 self.__notMatchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarBbaz")
236
237 def test_NoVariableRedefinition(self):
David Brazdil2e15cd22014-12-31 17:28:38 +0000238 with self.assertRaises(CheckerException):
David Brazdilee690a32014-12-01 17:04:16 +0000239 self.__matchSingle("[[X:...]][[X]][[X:...]][[X]]", "foofoobarbar")
240
241 def test_EnvNotChangedOnPartialMatch(self):
242 env = {"Y": "foo"}
243 self.__notMatchSingle("[[X:A]]bar", "Abaz", env)
244 self.assertFalse("X" in env.keys())
245
246 def test_VariableContentEscaped(self):
247 self.__matchSingle("[[X:..]]foo[[X]]", ".*foo.*")
248 self.__notMatchSingle("[[X:..]]foo[[X]]", ".*fooAAAA")
249
250
David Brazdil9a6f20e2014-12-19 11:17:21 +0000251CheckVariant = checker.CheckLine.Variant
252
253def prepareSingleCheck(line):
254 if isinstance(line, str):
255 return checker.CheckLine(line)
256 else:
257 return checker.CheckLine(line[0], line[1])
258
259def prepareChecks(lines):
260 if isinstance(lines, str):
261 lines = lines.splitlines()
262 return list(map(lambda line: prepareSingleCheck(line), lines))
263
264
David Brazdilee690a32014-12-01 17:04:16 +0000265class TestCheckGroup_Match(unittest.TestCase):
David Brazdil9a6f20e2014-12-19 11:17:21 +0000266 def __matchMulti(self, checkLines, outputString):
267 checkGroup = checker.CheckGroup("MyGroup", prepareChecks(checkLines))
David Brazdilee690a32014-12-01 17:04:16 +0000268 outputGroup = checker.OutputGroup("MyGroup", outputString.splitlines())
269 return checkGroup.match(outputGroup)
270
271 def __notMatchMulti(self, checkString, outputString):
David Brazdil2e15cd22014-12-31 17:28:38 +0000272 with self.assertRaises(CheckerException):
David Brazdilee690a32014-12-01 17:04:16 +0000273 self.__matchMulti(checkString, outputString)
274
275 def test_TextAndPattern(self):
276 self.__matchMulti("""foo bar
277 abc {{def}}""",
278 """foo bar
279 abc def""");
280 self.__matchMulti("""foo bar
281 abc {{de.}}""",
282 """=======
283 foo bar
284 =======
285 abc de#
286 =======""");
287 self.__notMatchMulti("""//XYZ: foo bar
288 //XYZ: abc {{def}}""",
289 """=======
290 foo bar
291 =======
292 abc de#
293 =======""");
294
295 def test_Variables(self):
296 self.__matchMulti("""foo[[X:.]]bar
297 abc[[X]]def""",
298 """foo bar
299 abc def""");
300 self.__matchMulti("""foo[[X:([0-9]+)]]bar
301 abc[[X]]def
302 ### [[X]] ###""",
303 """foo1234bar
304 abc1234def
305 ### 1234 ###""");
306
307 def test_Ordering(self):
David Brazdil9a6f20e2014-12-19 11:17:21 +0000308 self.__matchMulti([("foo", CheckVariant.InOrder),
309 ("bar", CheckVariant.InOrder)],
David Brazdilee690a32014-12-01 17:04:16 +0000310 """foo
311 bar""")
David Brazdil9a6f20e2014-12-19 11:17:21 +0000312 self.__notMatchMulti([("foo", CheckVariant.InOrder),
313 ("bar", CheckVariant.InOrder)],
David Brazdilee690a32014-12-01 17:04:16 +0000314 """bar
315 foo""")
David Brazdil9a6f20e2014-12-19 11:17:21 +0000316 self.__matchMulti([("abc", CheckVariant.DAG),
317 ("def", CheckVariant.DAG)],
318 """abc
319 def""")
320 self.__matchMulti([("abc", CheckVariant.DAG),
321 ("def", CheckVariant.DAG)],
322 """def
323 abc""")
324 self.__matchMulti([("foo", CheckVariant.InOrder),
325 ("abc", CheckVariant.DAG),
326 ("def", CheckVariant.DAG),
327 ("bar", CheckVariant.InOrder)],
328 """foo
329 def
330 abc
331 bar""")
332 self.__notMatchMulti([("foo", CheckVariant.InOrder),
333 ("abc", CheckVariant.DAG),
334 ("def", CheckVariant.DAG),
335 ("bar", CheckVariant.InOrder)],
336 """foo
337 abc
338 bar""")
339 self.__notMatchMulti([("foo", CheckVariant.InOrder),
340 ("abc", CheckVariant.DAG),
341 ("def", CheckVariant.DAG),
342 ("bar", CheckVariant.InOrder)],
343 """foo
344 def
345 bar""")
346
347 def test_NotAssertions(self):
348 self.__matchMulti([("foo", CheckVariant.Not)],
349 """abc
350 def""")
351 self.__notMatchMulti([("foo", CheckVariant.Not)],
352 """abc foo
353 def""")
David Brazdil21df8892015-01-08 01:49:53 +0000354 self.__notMatchMulti([("foo", CheckVariant.Not),
355 ("bar", CheckVariant.Not)],
356 """abc
357 def bar""")
David Brazdil9a6f20e2014-12-19 11:17:21 +0000358
359 def test_LineOnlyMatchesOnce(self):
360 self.__matchMulti([("foo", CheckVariant.DAG),
361 ("foo", CheckVariant.DAG)],
362 """foo
363 foo""")
364 self.__notMatchMulti([("foo", CheckVariant.DAG),
365 ("foo", CheckVariant.DAG)],
366 """foo
367 bar""")
David Brazdilee690a32014-12-01 17:04:16 +0000368
369class TestOutputFile_Parse(unittest.TestCase):
370 def __parsesTo(self, string, expected):
David Brazdil123c5e92015-01-20 09:28:38 +0000371 if isinstance(string, str):
372 string = unicode(string)
David Brazdilee690a32014-12-01 17:04:16 +0000373 outputStream = io.StringIO(string)
374 return self.assertEqual(checker.OutputFile(outputStream).groups, expected)
375
376 def test_NoInput(self):
377 self.__parsesTo(None, [])
378 self.__parsesTo("", [])
379
380 def test_SingleGroup(self):
381 self.__parsesTo("""begin_compilation
382 method "MyMethod"
383 end_compilation
384 begin_cfg
385 name "pass1"
386 foo
387 bar
388 end_cfg""",
389 [ checker.OutputGroup("MyMethod pass1", [ "foo", "bar" ]) ])
390
391 def test_MultipleGroups(self):
392 self.__parsesTo("""begin_compilation
393 name "xyz1"
394 method "MyMethod1"
395 date 1234
396 end_compilation
397 begin_cfg
398 name "pass1"
399 foo
400 bar
401 end_cfg
402 begin_cfg
403 name "pass2"
404 abc
405 def
406 end_cfg""",
407 [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
408 checker.OutputGroup("MyMethod1 pass2", [ "abc", "def" ]) ])
409
410 self.__parsesTo("""begin_compilation
411 name "xyz1"
412 method "MyMethod1"
413 date 1234
414 end_compilation
415 begin_cfg
416 name "pass1"
417 foo
418 bar
419 end_cfg
420 begin_compilation
421 name "xyz2"
422 method "MyMethod2"
423 date 5678
424 end_compilation
425 begin_cfg
426 name "pass2"
427 abc
428 def
429 end_cfg""",
430 [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
431 checker.OutputGroup("MyMethod2 pass2", [ "abc", "def" ]) ])
432
433class TestCheckFile_Parse(unittest.TestCase):
434 def __parsesTo(self, string, expected):
David Brazdil123c5e92015-01-20 09:28:38 +0000435 if isinstance(string, str):
436 string = unicode(string)
David Brazdilee690a32014-12-01 17:04:16 +0000437 checkStream = io.StringIO(string)
438 return self.assertEqual(checker.CheckFile("CHECK", checkStream).groups, expected)
439
440 def test_NoInput(self):
441 self.__parsesTo(None, [])
442 self.__parsesTo("", [])
443
444 def test_SingleGroup(self):
445 self.__parsesTo("""// CHECK-START: Example Group
446 // CHECK: foo
447 // CHECK: bar""",
David Brazdil9a6f20e2014-12-19 11:17:21 +0000448 [ checker.CheckGroup("Example Group", prepareChecks([ "foo", "bar" ])) ])
David Brazdilee690a32014-12-01 17:04:16 +0000449
450 def test_MultipleGroups(self):
451 self.__parsesTo("""// CHECK-START: Example Group1
452 // CHECK: foo
453 // CHECK: bar
454 // CHECK-START: Example Group2
455 // CHECK: abc
456 // CHECK: def""",
David Brazdil9a6f20e2014-12-19 11:17:21 +0000457 [ checker.CheckGroup("Example Group1", prepareChecks([ "foo", "bar" ])),
458 checker.CheckGroup("Example Group2", prepareChecks([ "abc", "def" ])) ])
459
460 def test_CheckVariants(self):
461 self.__parsesTo("""// CHECK-START: Example Group
462 // CHECK: foo
463 // CHECK-NOT: bar
464 // CHECK-DAG: abc
465 // CHECK-DAG: def""",
466 [ checker.CheckGroup("Example Group",
467 prepareChecks([ ("foo", CheckVariant.InOrder),
468 ("bar", CheckVariant.Not),
469 ("abc", CheckVariant.DAG),
470 ("def", CheckVariant.DAG) ])) ])
David Brazdilee690a32014-12-01 17:04:16 +0000471
472if __name__ == '__main__':
David Brazdil7cca5df2015-01-15 00:40:56 +0000473 checker.Logger.Verbosity = checker.Logger.Level.NoOutput
David Brazdilee690a32014-12-01 17:04:16 +0000474 unittest.main()