blob: 8947d8a07628b5abd9932a1d74a748cc1771fb61 [file] [log] [blame]
David Brazdilee690a32014-12-01 17:04:16 +00001#!/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
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
24
25class TestCheckFile_PrefixExtraction(unittest.TestCase):
26 def __tryParse(self, string):
27 checkFile = checker.CheckFile(None, [])
28 return checkFile._extractLine("CHECK", string)
29
30 def test_InvalidFormat(self):
31 self.assertIsNone(self.__tryParse("CHECK"))
32 self.assertIsNone(self.__tryParse(":CHECK"))
33 self.assertIsNone(self.__tryParse("CHECK:"))
34 self.assertIsNone(self.__tryParse("//CHECK"))
35 self.assertIsNone(self.__tryParse("#CHECK"))
36
37 self.assertIsNotNone(self.__tryParse("//CHECK:foo"))
38 self.assertIsNotNone(self.__tryParse("#CHECK:bar"))
39
40 def test_InvalidLabel(self):
41 self.assertIsNone(self.__tryParse("//ACHECK:foo"))
42 self.assertIsNone(self.__tryParse("#ACHECK:foo"))
43
44 def test_NotFirstOnTheLine(self):
45 self.assertIsNone(self.__tryParse("A// CHECK: foo"))
46 self.assertIsNone(self.__tryParse("A # CHECK: foo"))
47 self.assertIsNone(self.__tryParse("// // CHECK: foo"))
48 self.assertIsNone(self.__tryParse("# # CHECK: foo"))
49
50 def test_WhitespaceAgnostic(self):
51 self.assertIsNotNone(self.__tryParse(" //CHECK: foo"))
52 self.assertIsNotNone(self.__tryParse("// CHECK: foo"))
53 self.assertIsNotNone(self.__tryParse(" //CHECK: foo"))
54 self.assertIsNotNone(self.__tryParse("// CHECK: foo"))
55
56
57class TestCheckLine_Parse(unittest.TestCase):
58 def __getRegex(self, checkLine):
59 return "".join(map(lambda x: "(" + x.pattern + ")", checkLine.lineParts))
60
61 def __tryParse(self, string):
62 return checker.CheckLine(string)
63
64 def __parsesTo(self, string, expected):
65 self.assertEqual(expected, self.__getRegex(self.__tryParse(string)))
66
David Brazdil9a6f20e2014-12-19 11:17:21 +000067 def __tryParseNot(self, string):
68 return checker.CheckLine(string, checker.CheckLine.Variant.UnorderedNot)
69
David Brazdilee690a32014-12-01 17:04:16 +000070 def __parsesPattern(self, string, pattern):
71 line = self.__tryParse(string)
72 self.assertEqual(1, len(line.lineParts))
73 self.assertEqual(checker.CheckElement.Variant.Pattern, line.lineParts[0].variant)
74 self.assertEqual(pattern, line.lineParts[0].pattern)
75
76 def __parsesVarRef(self, string, name):
77 line = self.__tryParse(string)
78 self.assertEqual(1, len(line.lineParts))
79 self.assertEqual(checker.CheckElement.Variant.VarRef, line.lineParts[0].variant)
80 self.assertEqual(name, line.lineParts[0].name)
81
82 def __parsesVarDef(self, string, name, body):
83 line = self.__tryParse(string)
84 self.assertEqual(1, len(line.lineParts))
85 self.assertEqual(checker.CheckElement.Variant.VarDef, line.lineParts[0].variant)
86 self.assertEqual(name, line.lineParts[0].name)
87 self.assertEqual(body, line.lineParts[0].pattern)
88
89 def __doesNotParse(self, string, partType):
90 line = self.__tryParse(string)
91 self.assertEqual(1, len(line.lineParts))
92 self.assertNotEqual(partType, line.lineParts[0].variant)
93
94 # Test that individual parts of the line are recognized
95
96 def test_TextOnly(self):
97 self.__parsesTo("foo", "(foo)")
98 self.__parsesTo(" foo ", "(foo)")
99 self.__parsesTo("f$o^o", "(f\$o\^o)")
100
101 def test_TextWithWhitespace(self):
102 self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
103 self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
104
105 def test_RegexOnly(self):
106 self.__parsesPattern("{{a?b.c}}", "a?b.c")
107
108 def test_VarRefOnly(self):
109 self.__parsesVarRef("[[ABC]]", "ABC")
110
111 def test_VarDefOnly(self):
112 self.__parsesVarDef("[[ABC:a?b.c]]", "ABC", "a?b.c")
113
114 def test_TextWithRegex(self):
115 self.__parsesTo("foo{{abc}}bar", "(foo)(abc)(bar)")
116
117 def test_TextWithVar(self):
118 self.__parsesTo("foo[[ABC:abc]]bar", "(foo)(abc)(bar)")
119
120 def test_PlainWithRegexAndWhitespaces(self):
121 self.__parsesTo("foo {{abc}}bar", "(foo)(\s+)(abc)(bar)")
122 self.__parsesTo("foo{{abc}} bar", "(foo)(abc)(\s+)(bar)")
123 self.__parsesTo("foo {{abc}} bar", "(foo)(\s+)(abc)(\s+)(bar)")
124
125 def test_PlainWithVarAndWhitespaces(self):
126 self.__parsesTo("foo [[ABC:abc]]bar", "(foo)(\s+)(abc)(bar)")
127 self.__parsesTo("foo[[ABC:abc]] bar", "(foo)(abc)(\s+)(bar)")
128 self.__parsesTo("foo [[ABC:abc]] bar", "(foo)(\s+)(abc)(\s+)(bar)")
129
130 def test_AllKinds(self):
131 self.__parsesTo("foo [[ABC:abc]]{{def}}bar", "(foo)(\s+)(abc)(def)(bar)")
132 self.__parsesTo("foo[[ABC:abc]] {{def}}bar", "(foo)(abc)(\s+)(def)(bar)")
133 self.__parsesTo("foo [[ABC:abc]] {{def}} bar", "(foo)(\s+)(abc)(\s+)(def)(\s+)(bar)")
134
135 # Test that variables and patterns are parsed correctly
136
137 def test_ValidPattern(self):
138 self.__parsesPattern("{{abc}}", "abc")
139 self.__parsesPattern("{{a[b]c}}", "a[b]c")
140 self.__parsesPattern("{{(a{bc})}}", "(a{bc})")
141
142 def test_ValidRef(self):
143 self.__parsesVarRef("[[ABC]]", "ABC")
144 self.__parsesVarRef("[[A1BC2]]", "A1BC2")
145
146 def test_ValidDef(self):
147 self.__parsesVarDef("[[ABC:abc]]", "ABC", "abc")
148 self.__parsesVarDef("[[ABC:ab:c]]", "ABC", "ab:c")
149 self.__parsesVarDef("[[ABC:a[b]c]]", "ABC", "a[b]c")
150 self.__parsesVarDef("[[ABC:(a[bc])]]", "ABC", "(a[bc])")
151
152 def test_Empty(self):
153 self.__doesNotParse("{{}}", checker.CheckElement.Variant.Pattern)
154 self.__doesNotParse("[[]]", checker.CheckElement.Variant.VarRef)
155 self.__doesNotParse("[[:]]", checker.CheckElement.Variant.VarDef)
156
157 def test_InvalidVarName(self):
158 self.__doesNotParse("[[0ABC]]", checker.CheckElement.Variant.VarRef)
159 self.__doesNotParse("[[AB=C]]", checker.CheckElement.Variant.VarRef)
160 self.__doesNotParse("[[ABC=]]", checker.CheckElement.Variant.VarRef)
161 self.__doesNotParse("[[0ABC:abc]]", checker.CheckElement.Variant.VarDef)
162 self.__doesNotParse("[[AB=C:abc]]", checker.CheckElement.Variant.VarDef)
163 self.__doesNotParse("[[ABC=:abc]]", checker.CheckElement.Variant.VarDef)
164
165 def test_BodyMatchNotGreedy(self):
166 self.__parsesTo("{{abc}}{{def}}", "(abc)(def)")
167 self.__parsesTo("[[ABC:abc]][[DEF:def]]", "(abc)(def)")
168
David Brazdil9a6f20e2014-12-19 11:17:21 +0000169 def test_NoVarDefsInNotChecks(self):
170 with self.assertRaises(Exception):
171 self.__tryParseNot("[[ABC:abc]]")
David Brazdilee690a32014-12-01 17:04:16 +0000172
173class TestCheckLine_Match(unittest.TestCase):
174 def __matchSingle(self, checkString, outputString, varState={}):
175 checkLine = checker.CheckLine(checkString)
176 newVarState = checkLine.match(outputString, varState)
177 self.assertIsNotNone(newVarState)
178 return newVarState
179
180 def __notMatchSingle(self, checkString, outputString, varState={}):
181 checkLine = checker.CheckLine(checkString)
182 self.assertIsNone(checkLine.match(outputString, varState))
183
184 def test_TextAndWhitespace(self):
185 self.__matchSingle("foo", "foo")
186 self.__matchSingle("foo", "XfooX")
187 self.__matchSingle("foo", "foo bar")
188 self.__notMatchSingle("foo", "zoo")
189
190 self.__matchSingle("foo bar", "foo bar")
191 self.__matchSingle("foo bar", "abc foo bar def")
192 self.__matchSingle("foo bar", "foo foo bar bar")
193 self.__notMatchSingle("foo bar", "foo abc bar")
194
195 def test_Pattern(self):
196 self.__matchSingle("foo{{A|B}}bar", "fooAbar")
197 self.__matchSingle("foo{{A|B}}bar", "fooBbar")
198 self.__notMatchSingle("foo{{A|B}}bar", "fooCbar")
199
200 def test_VariableReference(self):
201 self.__matchSingle("foo[[X]]bar", "foobar", {"X": ""})
202 self.__matchSingle("foo[[X]]bar", "fooAbar", {"X": "A"})
203 self.__matchSingle("foo[[X]]bar", "fooBbar", {"X": "B"})
204 self.__notMatchSingle("foo[[X]]bar", "foobar", {"X": "A"})
205 self.__notMatchSingle("foo[[X]]bar", "foo bar", {"X": "A"})
206 with self.assertRaises(Exception):
207 self.__matchSingle("foo[[X]]bar", "foobar", {})
208
209 def test_VariableDefinition(self):
210 self.__matchSingle("foo[[X:A|B]]bar", "fooAbar")
211 self.__matchSingle("foo[[X:A|B]]bar", "fooBbar")
212 self.__notMatchSingle("foo[[X:A|B]]bar", "fooCbar")
213
214 env = self.__matchSingle("foo[[X:A.*B]]bar", "fooABbar", {})
215 self.assertEqual(env, {"X": "AB"})
216 env = self.__matchSingle("foo[[X:A.*B]]bar", "fooAxxBbar", {})
217 self.assertEqual(env, {"X": "AxxB"})
218
219 self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarAbaz")
220 self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooBbarBbaz")
221 self.__notMatchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarBbaz")
222
223 def test_NoVariableRedefinition(self):
224 with self.assertRaises(Exception):
225 self.__matchSingle("[[X:...]][[X]][[X:...]][[X]]", "foofoobarbar")
226
227 def test_EnvNotChangedOnPartialMatch(self):
228 env = {"Y": "foo"}
229 self.__notMatchSingle("[[X:A]]bar", "Abaz", env)
230 self.assertFalse("X" in env.keys())
231
232 def test_VariableContentEscaped(self):
233 self.__matchSingle("[[X:..]]foo[[X]]", ".*foo.*")
234 self.__notMatchSingle("[[X:..]]foo[[X]]", ".*fooAAAA")
235
236
David Brazdil9a6f20e2014-12-19 11:17:21 +0000237CheckVariant = checker.CheckLine.Variant
238
239def prepareSingleCheck(line):
240 if isinstance(line, str):
241 return checker.CheckLine(line)
242 else:
243 return checker.CheckLine(line[0], line[1])
244
245def prepareChecks(lines):
246 if isinstance(lines, str):
247 lines = lines.splitlines()
248 return list(map(lambda line: prepareSingleCheck(line), lines))
249
250
David Brazdilee690a32014-12-01 17:04:16 +0000251class TestCheckGroup_Match(unittest.TestCase):
David Brazdil9a6f20e2014-12-19 11:17:21 +0000252 def __matchMulti(self, checkLines, outputString):
253 checkGroup = checker.CheckGroup("MyGroup", prepareChecks(checkLines))
David Brazdilee690a32014-12-01 17:04:16 +0000254 outputGroup = checker.OutputGroup("MyGroup", outputString.splitlines())
255 return checkGroup.match(outputGroup)
256
257 def __notMatchMulti(self, checkString, outputString):
258 with self.assertRaises(Exception):
259 self.__matchMulti(checkString, outputString)
260
261 def test_TextAndPattern(self):
262 self.__matchMulti("""foo bar
263 abc {{def}}""",
264 """foo bar
265 abc def""");
266 self.__matchMulti("""foo bar
267 abc {{de.}}""",
268 """=======
269 foo bar
270 =======
271 abc de#
272 =======""");
273 self.__notMatchMulti("""//XYZ: foo bar
274 //XYZ: abc {{def}}""",
275 """=======
276 foo bar
277 =======
278 abc de#
279 =======""");
280
281 def test_Variables(self):
282 self.__matchMulti("""foo[[X:.]]bar
283 abc[[X]]def""",
284 """foo bar
285 abc def""");
286 self.__matchMulti("""foo[[X:([0-9]+)]]bar
287 abc[[X]]def
288 ### [[X]] ###""",
289 """foo1234bar
290 abc1234def
291 ### 1234 ###""");
292
293 def test_Ordering(self):
David Brazdil9a6f20e2014-12-19 11:17:21 +0000294 self.__matchMulti([("foo", CheckVariant.InOrder),
295 ("bar", CheckVariant.InOrder)],
David Brazdilee690a32014-12-01 17:04:16 +0000296 """foo
297 bar""")
David Brazdil9a6f20e2014-12-19 11:17:21 +0000298 self.__notMatchMulti([("foo", CheckVariant.InOrder),
299 ("bar", CheckVariant.InOrder)],
David Brazdilee690a32014-12-01 17:04:16 +0000300 """bar
301 foo""")
David Brazdil9a6f20e2014-12-19 11:17:21 +0000302 self.__matchMulti([("abc", CheckVariant.DAG),
303 ("def", CheckVariant.DAG)],
304 """abc
305 def""")
306 self.__matchMulti([("abc", CheckVariant.DAG),
307 ("def", CheckVariant.DAG)],
308 """def
309 abc""")
310 self.__matchMulti([("foo", CheckVariant.InOrder),
311 ("abc", CheckVariant.DAG),
312 ("def", CheckVariant.DAG),
313 ("bar", CheckVariant.InOrder)],
314 """foo
315 def
316 abc
317 bar""")
318 self.__notMatchMulti([("foo", CheckVariant.InOrder),
319 ("abc", CheckVariant.DAG),
320 ("def", CheckVariant.DAG),
321 ("bar", CheckVariant.InOrder)],
322 """foo
323 abc
324 bar""")
325 self.__notMatchMulti([("foo", CheckVariant.InOrder),
326 ("abc", CheckVariant.DAG),
327 ("def", CheckVariant.DAG),
328 ("bar", CheckVariant.InOrder)],
329 """foo
330 def
331 bar""")
332
333 def test_NotAssertions(self):
334 self.__matchMulti([("foo", CheckVariant.Not)],
335 """abc
336 def""")
337 self.__notMatchMulti([("foo", CheckVariant.Not)],
338 """abc foo
339 def""")
340
341 def test_LineOnlyMatchesOnce(self):
342 self.__matchMulti([("foo", CheckVariant.DAG),
343 ("foo", CheckVariant.DAG)],
344 """foo
345 foo""")
346 self.__notMatchMulti([("foo", CheckVariant.DAG),
347 ("foo", CheckVariant.DAG)],
348 """foo
349 bar""")
David Brazdilee690a32014-12-01 17:04:16 +0000350
351class TestOutputFile_Parse(unittest.TestCase):
352 def __parsesTo(self, string, expected):
353 outputStream = io.StringIO(string)
354 return self.assertEqual(checker.OutputFile(outputStream).groups, expected)
355
356 def test_NoInput(self):
357 self.__parsesTo(None, [])
358 self.__parsesTo("", [])
359
360 def test_SingleGroup(self):
361 self.__parsesTo("""begin_compilation
362 method "MyMethod"
363 end_compilation
364 begin_cfg
365 name "pass1"
366 foo
367 bar
368 end_cfg""",
369 [ checker.OutputGroup("MyMethod pass1", [ "foo", "bar" ]) ])
370
371 def test_MultipleGroups(self):
372 self.__parsesTo("""begin_compilation
373 name "xyz1"
374 method "MyMethod1"
375 date 1234
376 end_compilation
377 begin_cfg
378 name "pass1"
379 foo
380 bar
381 end_cfg
382 begin_cfg
383 name "pass2"
384 abc
385 def
386 end_cfg""",
387 [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
388 checker.OutputGroup("MyMethod1 pass2", [ "abc", "def" ]) ])
389
390 self.__parsesTo("""begin_compilation
391 name "xyz1"
392 method "MyMethod1"
393 date 1234
394 end_compilation
395 begin_cfg
396 name "pass1"
397 foo
398 bar
399 end_cfg
400 begin_compilation
401 name "xyz2"
402 method "MyMethod2"
403 date 5678
404 end_compilation
405 begin_cfg
406 name "pass2"
407 abc
408 def
409 end_cfg""",
410 [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
411 checker.OutputGroup("MyMethod2 pass2", [ "abc", "def" ]) ])
412
413class TestCheckFile_Parse(unittest.TestCase):
414 def __parsesTo(self, string, expected):
415 checkStream = io.StringIO(string)
416 return self.assertEqual(checker.CheckFile("CHECK", checkStream).groups, expected)
417
418 def test_NoInput(self):
419 self.__parsesTo(None, [])
420 self.__parsesTo("", [])
421
422 def test_SingleGroup(self):
423 self.__parsesTo("""// CHECK-START: Example Group
424 // CHECK: foo
425 // CHECK: bar""",
David Brazdil9a6f20e2014-12-19 11:17:21 +0000426 [ checker.CheckGroup("Example Group", prepareChecks([ "foo", "bar" ])) ])
David Brazdilee690a32014-12-01 17:04:16 +0000427
428 def test_MultipleGroups(self):
429 self.__parsesTo("""// CHECK-START: Example Group1
430 // CHECK: foo
431 // CHECK: bar
432 // CHECK-START: Example Group2
433 // CHECK: abc
434 // CHECK: def""",
David Brazdil9a6f20e2014-12-19 11:17:21 +0000435 [ checker.CheckGroup("Example Group1", prepareChecks([ "foo", "bar" ])),
436 checker.CheckGroup("Example Group2", prepareChecks([ "abc", "def" ])) ])
437
438 def test_CheckVariants(self):
439 self.__parsesTo("""// CHECK-START: Example Group
440 // CHECK: foo
441 // CHECK-NOT: bar
442 // CHECK-DAG: abc
443 // CHECK-DAG: def""",
444 [ checker.CheckGroup("Example Group",
445 prepareChecks([ ("foo", CheckVariant.InOrder),
446 ("bar", CheckVariant.Not),
447 ("abc", CheckVariant.DAG),
448 ("def", CheckVariant.DAG) ])) ])
David Brazdilee690a32014-12-01 17:04:16 +0000449
450if __name__ == '__main__':
451 unittest.main()