1# Copyright (C) 2014 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#   http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from common.immutables               import ImmutableDict
16from common.testing                  import ToUnicode
17from file_format.c1visualizer.parser import ParseC1visualizerStream
18from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
19from file_format.checker.parser      import ParseCheckerStream, ParseCheckerStatement
20from file_format.checker.struct      import CheckerFile, TestCase, TestStatement
21from match.file                      import MatchTestCase, MatchFailedException, \
22                                            BadStructureException
23from match.line                      import MatchLines
24
25import io
26import unittest
27
28CheckerException = SystemExit
29
30class MatchLines_Test(unittest.TestCase):
31
32  def createTestStatement(self, checkerString):
33    checkerFile = CheckerFile("<checker-file>")
34    testCase = TestCase(checkerFile, "TestMethod TestPass", 0)
35    return ParseCheckerStatement(testCase, checkerString, TestStatement.Variant.InOrder, 0)
36
37  def tryMatch(self, checkerString, c1String, varState={}):
38    return MatchLines(self.createTestStatement(checkerString),
39                      ToUnicode(c1String),
40                      ImmutableDict(varState))
41
42  def assertMatches(self, checkerString, c1String, varState={}):
43    self.assertIsNotNone(self.tryMatch(checkerString, c1String, varState))
44
45  def assertDoesNotMatch(self, checkerString, c1String, varState={}):
46    self.assertIsNone(self.tryMatch(checkerString, c1String, varState))
47
48  def test_TextAndWhitespace(self):
49    self.assertMatches("foo", "foo")
50    self.assertMatches("foo", "  foo  ")
51    self.assertMatches("foo", "foo bar")
52    self.assertDoesNotMatch("foo", "XfooX")
53    self.assertDoesNotMatch("foo", "zoo")
54
55    self.assertMatches("foo bar", "foo   bar")
56    self.assertMatches("foo bar", "abc foo bar def")
57    self.assertMatches("foo bar", "foo foo bar bar")
58
59    self.assertMatches("foo bar", "foo X bar")
60    self.assertDoesNotMatch("foo bar", "foo Xbar")
61
62  def test_Pattern(self):
63    self.assertMatches("foo{{A|B}}bar", "fooAbar")
64    self.assertMatches("foo{{A|B}}bar", "fooBbar")
65    self.assertDoesNotMatch("foo{{A|B}}bar", "fooCbar")
66
67  def test_VariableReference(self):
68    self.assertMatches("foo<<X>>bar", "foobar", {"X": ""})
69    self.assertMatches("foo<<X>>bar", "fooAbar", {"X": "A"})
70    self.assertMatches("foo<<X>>bar", "fooBbar", {"X": "B"})
71    self.assertDoesNotMatch("foo<<X>>bar", "foobar", {"X": "A"})
72    self.assertDoesNotMatch("foo<<X>>bar", "foo bar", {"X": "A"})
73    with self.assertRaises(CheckerException):
74      self.tryMatch("foo<<X>>bar", "foobar", {})
75
76  def test_VariableDefinition(self):
77    self.assertMatches("foo<<X:A|B>>bar", "fooAbar")
78    self.assertMatches("foo<<X:A|B>>bar", "fooBbar")
79    self.assertDoesNotMatch("foo<<X:A|B>>bar", "fooCbar")
80
81    env = self.tryMatch("foo<<X:A.*B>>bar", "fooABbar", {})
82    self.assertEqual(env, {"X": "AB"})
83    env = self.tryMatch("foo<<X:A.*B>>bar", "fooAxxBbar", {})
84    self.assertEqual(env, {"X": "AxxB"})
85
86    self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooAbarAbaz")
87    self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooBbarBbaz")
88    self.assertDoesNotMatch("foo<<X:A|B>>bar<<X>>baz", "fooAbarBbaz")
89
90  def test_NoVariableRedefinition(self):
91    with self.assertRaises(CheckerException):
92      self.tryMatch("<<X:...>><<X>><<X:...>><<X>>", "foofoobarbar")
93
94  def test_EnvNotChangedOnPartialMatch(self):
95    env = {"Y": "foo"}
96    self.assertDoesNotMatch("<<X:A>>bar", "Abaz", env)
97    self.assertFalse("X" in env.keys())
98
99  def test_VariableContentEscaped(self):
100    self.assertMatches("<<X:..>>foo<<X>>", ".*foo.*")
101    self.assertDoesNotMatch("<<X:..>>foo<<X>>", ".*fooAAAA")
102
103
104class MatchFiles_Test(unittest.TestCase):
105
106  def assertMatches(self, checkerString, c1String, isa=None, instructionSetFeatures=None):
107    checkerString = \
108      """
109        /// CHECK-START: MyMethod MyPass
110      """ + checkerString
111    metaData = ""
112    if isa:
113      metaData += "isa:" + isa
114
115    if instructionSetFeatures:
116      if metaData:
117        metaData += " "
118
119      joinedFeatures = ",".join(map(lambda feature: feature
120                                                    if instructionSetFeatures[feature]
121                                                    else "-" + feature,
122                                    instructionSetFeatures))
123      metaData += "isa_features:" + joinedFeatures
124
125    metaDataString = ""
126    if metaData:
127      metaDataString = \
128        """
129          begin_compilation
130            name "%s"
131            method "%s"
132            date 1234
133          end_compilation
134        """ % (metaData, metaData)
135    c1String = metaDataString + \
136      """
137        begin_compilation
138          name "MyMethod"
139          method "MyMethod"
140          date 1234
141        end_compilation
142        begin_cfg
143          name "MyPass"
144      """ + c1String + \
145      """
146        end_cfg
147      """
148    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(ToUnicode(checkerString)))
149    c1File = ParseC1visualizerStream("<c1-file>", io.StringIO(ToUnicode(c1String)))
150    assert len(checkerFile.testCases) == 1
151    assert len(c1File.passes) == 1
152    MatchTestCase(checkerFile.testCases[0], c1File.passes[0], c1File.instructionSetFeatures)
153
154  def assertDoesNotMatch(self, checkerString, c1String, isa=None, instructionSetFeatures=None):
155    with self.assertRaises(MatchFailedException):
156      self.assertMatches(checkerString, c1String, isa, instructionSetFeatures)
157
158  def assertBadStructure(self, checkerString, c1String):
159    with self.assertRaises(BadStructureException):
160      self.assertMatches(checkerString, c1String)
161
162  def test_Text(self):
163    self.assertMatches("/// CHECK: foo bar", "foo bar")
164    self.assertDoesNotMatch("/// CHECK: foo bar", "abc def")
165
166  def test_Pattern(self):
167    self.assertMatches("/// CHECK: abc {{de.}}", "abc de#")
168    self.assertDoesNotMatch("/// CHECK: abc {{de.}}", "abc d#f")
169
170  def test_Variables(self):
171    self.assertMatches(
172    """
173      /// CHECK: foo<<X:.>>bar
174      /// CHECK: abc<<X>>def
175    """,
176    """
177      foo0bar
178      abc0def
179    """)
180    self.assertMatches(
181    """
182      /// CHECK: foo<<X:([0-9]+)>>bar
183      /// CHECK: abc<<X>>def
184      /// CHECK: ### <<X>> ###
185    """,
186    """
187      foo1234bar
188      abc1234def
189      ### 1234 ###
190    """)
191    self.assertDoesNotMatch(
192    """
193      /// CHECK: foo<<X:([0-9]+)>>bar
194      /// CHECK: abc<<X>>def
195    """,
196    """
197      foo1234bar
198      abc1235def
199    """)
200
201  def test_WholeWordMustMatch(self):
202    self.assertMatches("/// CHECK: b{{.}}r", "abc bar def")
203    self.assertDoesNotMatch("/// CHECK: b{{.}}r", "abc Xbar def")
204    self.assertDoesNotMatch("/// CHECK: b{{.}}r", "abc barX def")
205    self.assertDoesNotMatch("/// CHECK: b{{.}}r", "abc b r def")
206
207  def test_InOrderStatements(self):
208    self.assertMatches(
209    """
210      /// CHECK: foo
211      /// CHECK: bar
212    """,
213    """
214      foo
215      bar
216    """)
217    self.assertDoesNotMatch(
218    """
219      /// CHECK: foo
220      /// CHECK: bar
221    """,
222    """
223      bar
224      foo
225    """)
226
227  def test_NextLineStatements(self):
228    self.assertMatches(
229    """
230      /// CHECK:      foo
231      /// CHECK-NEXT: bar
232      /// CHECK-NEXT: abc
233      /// CHECK:      def
234    """,
235    """
236      foo
237      bar
238      abc
239      def
240    """)
241    self.assertMatches(
242    """
243      /// CHECK:      foo
244      /// CHECK-NEXT: bar
245      /// CHECK:      def
246    """,
247    """
248      foo
249      bar
250      abc
251      def
252    """)
253    self.assertDoesNotMatch(
254    """
255      /// CHECK:      foo
256      /// CHECK-NEXT: bar
257    """,
258    """
259      foo
260      abc
261      bar
262    """)
263
264    self.assertDoesNotMatch(
265    """
266      /// CHECK:      foo
267      /// CHECK-NEXT: bar
268    """,
269    """
270      bar
271      foo
272      abc
273    """)
274
275  def test_DagStatements(self):
276    self.assertMatches(
277    """
278      /// CHECK-DAG: foo
279      /// CHECK-DAG: bar
280    """,
281    """
282      foo
283      bar
284    """)
285    self.assertMatches(
286    """
287      /// CHECK-DAG: foo
288      /// CHECK-DAG: bar
289    """,
290    """
291      bar
292      foo
293    """)
294
295  def test_DagStatementsScope(self):
296    self.assertMatches(
297    """
298      /// CHECK:     foo
299      /// CHECK-DAG: abc
300      /// CHECK-DAG: def
301      /// CHECK:     bar
302    """,
303    """
304      foo
305      def
306      abc
307      bar
308    """)
309    self.assertDoesNotMatch(
310    """
311      /// CHECK:     foo
312      /// CHECK-DAG: abc
313      /// CHECK-DAG: def
314      /// CHECK:     bar
315    """,
316    """
317      foo
318      abc
319      bar
320      def
321    """)
322    self.assertDoesNotMatch(
323    """
324      /// CHECK:     foo
325      /// CHECK-DAG: abc
326      /// CHECK-DAG: def
327      /// CHECK:     bar
328    """,
329    """
330      foo
331      def
332      bar
333      abc
334    """)
335
336  def test_NotStatements(self):
337    self.assertMatches(
338    """
339      /// CHECK-NOT: foo
340    """,
341    """
342      abc
343      def
344    """)
345    self.assertDoesNotMatch(
346    """
347      /// CHECK-NOT: foo
348    """,
349    """
350      abc foo
351      def
352    """)
353    self.assertDoesNotMatch(
354    """
355      /// CHECK-NOT: foo
356      /// CHECK-NOT: bar
357    """,
358    """
359      abc
360      def bar
361    """)
362
363  def test_NotStatementsScope(self):
364    self.assertMatches(
365    """
366      /// CHECK:     abc
367      /// CHECK-NOT: foo
368      /// CHECK:     def
369    """,
370    """
371      abc
372      def
373    """)
374    self.assertMatches(
375    """
376      /// CHECK:     abc
377      /// CHECK-NOT: foo
378      /// CHECK:     def
379    """,
380    """
381      abc
382      def
383      foo
384    """)
385    self.assertDoesNotMatch(
386    """
387      /// CHECK:     abc
388      /// CHECK-NOT: foo
389      /// CHECK:     def
390    """,
391    """
392      abc
393      foo
394      def
395    """)
396    self.assertDoesNotMatch(
397    """
398      /// CHECK-NOT:  foo
399      /// CHECK-EVAL: 1 + 1 == 2
400      /// CHECK:      bar
401    """,
402    """
403      foo
404      abc
405      bar
406    """);
407    self.assertMatches(
408    """
409      /// CHECK-DAG:  bar
410      /// CHECK-DAG:  abc
411      /// CHECK-NOT:  foo
412    """,
413    """
414      foo
415      abc
416      bar
417    """);
418    self.assertDoesNotMatch(
419    """
420      /// CHECK-DAG:  abc
421      /// CHECK-DAG:  foo
422      /// CHECK-NOT:  bar
423    """,
424    """
425      foo
426      abc
427      bar
428    """);
429
430  def test_LineOnlyMatchesOnce(self):
431    self.assertMatches(
432    """
433      /// CHECK-DAG: foo
434      /// CHECK-DAG: foo
435    """,
436    """
437      foo
438      abc
439      foo
440    """)
441    self.assertDoesNotMatch(
442    """
443      /// CHECK-DAG: foo
444      /// CHECK-DAG: foo
445    """,
446    """
447      foo
448      abc
449      bar
450    """)
451
452  def test_EvalStatements(self):
453    self.assertMatches("/// CHECK-EVAL: True", "foo")
454    self.assertDoesNotMatch("/// CHECK-EVAL: False", "foo")
455
456    self.assertMatches("/// CHECK-EVAL: 1 + 2 == 3", "foo")
457    self.assertDoesNotMatch("/// CHECK-EVAL: 1 + 2 == 4", "foo")
458
459    twoVarTestCase = """
460                       /// CHECK-DAG: <<X:\d+>> <<Y:\d+>>
461                       /// CHECK-EVAL: <<X>> > <<Y>>
462                     """
463    self.assertMatches(twoVarTestCase, "42 41");
464    self.assertDoesNotMatch(twoVarTestCase, "42 43")
465
466  def test_MisplacedNext(self):
467    self.assertBadStructure(
468      """
469        /// CHECK-DAG:  foo
470        /// CHECK-NEXT: bar
471      """,
472      """
473      foo
474      bar
475      """)
476    self.assertBadStructure(
477      """
478        /// CHECK-NOT:  foo
479        /// CHECK-NEXT: bar
480      """,
481      """
482      foo
483      bar
484      """)
485    self.assertBadStructure(
486      """
487        /// CHECK-EVAL: True
488        /// CHECK-NEXT: bar
489      """,
490      """
491      foo
492      bar
493      """)
494    self.assertBadStructure(
495      """
496        /// CHECK-NEXT: bar
497      """,
498      """
499      foo
500      bar
501      """)
502
503  def test_EnvVariableEval(self):
504    self.assertMatches(
505    """
506      /// CHECK-IF: os.environ.get('MARTY_MCFLY') != '89mph!'
507      /// CHECK-FI:
508    """,
509    """
510    foo
511    """
512    )
513    self.assertMatches(
514    """
515      /// CHECK-EVAL: os.environ.get('MARTY_MCFLY') != '89mph!'
516    """,
517    """
518    foo
519    """
520    )
521
522  def test_IfStatements(self):
523    self.assertMatches(
524    """
525      /// CHECK: foo1
526      /// CHECK-IF: True
527      ///   CHECK-NEXT: foo2
528      /// CHECK-FI:
529      /// CHECK-NEXT: foo3
530      /// CHECK-NEXT: bar
531    """,
532    """
533    foo1
534    foo2
535    foo3
536    bar
537    """)
538    self.assertMatches(
539    """
540      /// CHECK: foo1
541      /// CHECK-IF: False
542      ///   CHECK-NEXT:    foo2
543      /// CHECK-FI:
544      /// CHECK-NEXT:    bar
545    """,
546    """
547    foo1
548    bar
549    """)
550    self.assertMatches(
551    """
552      /// CHECK: foo1
553      /// CHECK-IF: True
554      ///   CHECK-DAG:    foo2
555      /// CHECK-FI:
556      /// CHECK-DAG:    bar
557      /// CHECK: foo3
558    """,
559    """
560    foo1
561    bar
562    foo2
563    foo3
564    """)
565    self.assertDoesNotMatch(
566    """
567      /// CHECK: foo1
568      /// CHECK-IF: False
569      ///   CHECK-NEXT: foo2
570      /// CHECK-FI:
571      /// CHECK-NEXT: foo3
572    """,
573    """
574    foo1
575    foo2
576    foo3
577    """)
578
579  def test_IfElseStatements(self):
580    self.assertMatches(
581    """
582      /// CHECK: foo1
583      /// CHECK-IF: True
584      ///   CHECK-NEXT:    foo2
585      /// CHECK-ELSE:
586      ///   CHECK-NEXT:    foo3
587      /// CHECK-FI:
588      /// CHECK-NEXT:    bar
589    """,
590    """
591    foo1
592    foo2
593    bar
594    """)
595    self.assertMatches(
596    """
597      /// CHECK: foo1
598      /// CHECK-IF: False
599      ///   CHECK-NEXT:    foo2
600      /// CHECK-ELSE:
601      ///   CHECK-NEXT:    foo3
602      /// CHECK-FI:
603      /// CHECK-NEXT:    bar
604    """,
605    """
606    foo1
607    foo3
608    bar
609    """)
610    self.assertMatches(
611    """
612      /// CHECK: foo1
613      /// CHECK-IF: False
614      ///   CHECK-NEXT:    foo2
615      /// CHECK-ELSE:
616      ///   CHECK-DAG:    bar
617      /// CHECK-FI:
618      /// CHECK-DAG:    foo3
619      /// CHECK: foo4
620    """,
621    """
622    foo1
623    foo3
624    bar
625    foo4
626    """)
627    self.assertDoesNotMatch(
628    """
629      /// CHECK: foo1
630      /// CHECK-IF: False
631      ///   CHECK-NEXT:    foo2
632      /// CHECK-ELSE:
633      ///   CHECK-NEXT:    foo3
634      /// CHECK-FI:
635      /// CHECK-NEXT:    bar
636    """,
637    """
638    foo1
639    foo2
640    bar
641    """)
642
643  def test_IfElifElseStatements(self):
644    self.assertMatches(
645    """
646      /// CHECK: foo1
647      /// CHECK-IF: True
648      ///   CHECK-NEXT:    foo2
649      /// CHECK-ELIF: True
650      ///   CHECK-NEXT:    foo3
651      /// CHECK-ELIF: True
652      ///   CHECK-NEXT:    foo4
653      /// CHECK-FI:
654      /// CHECK-NEXT:    bar
655    """,
656    """
657    foo1
658    foo2
659    bar
660    """)
661    self.assertMatches(
662    """
663      /// CHECK: foo1
664      /// CHECK-IF: False
665      ///   CHECK-NEXT:    foo2
666      /// CHECK-ELIF: False
667      ///   CHECK-NEXT:    foo3
668      /// CHECK-ELIF: True
669      ///   CHECK-NEXT:    foo4
670      /// CHECK-FI:
671      /// CHECK-NEXT:    bar
672    """,
673    """
674    foo1
675    foo4
676    bar
677    """)
678    self.assertMatches(
679    """
680      /// CHECK: foo1
681      /// CHECK-IF: False
682      ///   CHECK-NEXT:    foo2
683      /// CHECK-ELIF: True
684      ///   CHECK-NEXT:    foo3
685      /// CHECK-ELIF: True
686      ///   CHECK-NEXT:    foo4
687      /// CHECK-FI:
688      /// CHECK-NEXT:    bar
689    """,
690    """
691    foo1
692    foo3
693    bar
694    """)
695    self.assertMatches(
696    """
697      /// CHECK: foo1
698      /// CHECK-IF: False
699      ///   CHECK-NEXT:    foo2
700      /// CHECK-ELIF: False
701      ///   CHECK-NEXT:    foo3
702      /// CHECK-ELIF: False
703      ///   CHECK-NEXT:    foo4
704      /// CHECK-FI:
705      /// CHECK-NEXT:    bar
706    """,
707    """
708    foo1
709    bar
710    """)
711    self.assertDoesNotMatch(
712    """
713      /// CHECK: foo1
714      /// CHECK-IF: False
715      ///   CHECK-NEXT:    foo2
716      /// CHECK-ELIF: True
717      ///   CHECK-NEXT:    foo3
718      /// CHECK-ELSE:
719      ///   CHECK-NEXT:    foo4
720      /// CHECK-FI:
721      /// CHECK-NEXT:    bar
722    """,
723    """
724    foo1
725    foo2
726    bar
727    """)
728
729  def test_NestedBranching(self):
730    self.assertMatches(
731    """
732      /// CHECK: foo1
733      /// CHECK-IF: True
734      ///   CHECK-IF: True
735      ///     CHECK-NEXT:    foo2
736      ///   CHECK-ELSE:
737      ///     CHECK-NEXT:    foo3
738      ///   CHECK-FI:
739      /// CHECK-ELSE:
740      ///   CHECK-IF: True
741      ///     CHECK-NEXT:    foo4
742      ///   CHECK-ELSE:
743      ///     CHECK-NEXT:    foo5
744      ///   CHECK-FI:
745      /// CHECK-FI:
746      /// CHECK-NEXT: foo6
747    """,
748    """
749    foo1
750    foo2
751    foo6
752    """)
753    self.assertMatches(
754    """
755      /// CHECK-IF: True
756      ///   CHECK-IF: False
757      ///     CHECK:    foo1
758      ///   CHECK-ELSE:
759      ///     CHECK:    foo2
760      ///   CHECK-FI:
761      /// CHECK-ELSE:
762      ///   CHECK-IF: True
763      ///     CHECK:    foo3
764      ///   CHECK-ELSE:
765      ///     CHECK:    foo4
766      ///   CHECK-FI:
767      /// CHECK-FI:
768    """,
769    """
770    foo2
771    """)
772    self.assertMatches(
773    """
774      /// CHECK-IF: False
775      ///   CHECK-IF: True
776      ///     CHECK:    foo1
777      ///   CHECK-ELSE:
778      ///     CHECK:    foo2
779      ///   CHECK-FI:
780      /// CHECK-ELSE:
781      ///   CHECK-IF: False
782      ///     CHECK:    foo3
783      ///   CHECK-ELSE:
784      ///     CHECK-IF: False
785      ///       CHECK:    foo4
786      ///     CHECK-ELSE:
787      ///       CHECK: foo5
788      ///     CHECK-FI:
789      ///   CHECK-FI:
790      /// CHECK-FI:
791    """,
792    """
793    foo5
794    """)
795    self.assertDoesNotMatch(
796    """
797      /// CHECK: foo1
798      /// CHECK-IF: True
799      ///   CHECK-IF: False
800      ///     CHECK-NEXT:    foo2
801      ///   CHECK-ELSE:
802      ///     CHECK-NEXT:    foo3
803      ///   CHECK-FI:
804      /// CHECK-NEXT: foo6
805    """,
806    """
807    foo1
808    foo2
809    foo6
810    """)
811
812  def test_VariablesInBranches(self):
813    self.assertMatches(
814    """
815      /// CHECK-IF: True
816      ///   CHECK: foo<<VarA:\d+>>
817      /// CHECK-FI:
818      /// CHECK-EVAL: <<VarA>> == 12
819    """,
820    """
821    foo12
822    """)
823    self.assertDoesNotMatch(
824    """
825      /// CHECK-IF: True
826      ///   CHECK: foo<<VarA:\d+>>
827      /// CHECK-FI:
828      /// CHECK-EVAL: <<VarA>> == 99
829    """,
830    """
831    foo12
832    """)
833    self.assertMatches(
834    """
835      /// CHECK-IF: True
836      ///   CHECK: foo<<VarA:\d+>>
837      ///   CHECK-IF: <<VarA>> == 12
838      ///     CHECK: bar<<VarB:M|N>>
839      ///   CHECK-FI:
840      /// CHECK-FI:
841      /// CHECK-EVAL: "<<VarB>>" == "M"
842    """,
843    """
844    foo12
845    barM
846    """)
847    self.assertMatches(
848    """
849      /// CHECK-IF: False
850      ///   CHECK: foo<<VarA:\d+>>
851      /// CHECK-ELIF: True
852      ///   CHECK: foo<<VarA:M|N>>
853      /// CHECK-FI:
854      /// CHECK-EVAL: "<<VarA>>" == "M"
855    """,
856    """
857    fooM
858    """)
859    self.assertMatches(
860    """
861      /// CHECK-IF: False
862      ///   CHECK: foo<<VarA:A|B>>
863      /// CHECK-ELIF: False
864      ///   CHECK: foo<<VarA:A|B>>
865      /// CHECK-ELSE:
866      ///   CHECK-IF: False
867      ///     CHECK: foo<<VarA:A|B>>
868      ///   CHECK-ELSE:
869      ///     CHECK: foo<<VarA:M|N>>
870      ///   CHECK-FI:
871      /// CHECK-FI:
872      /// CHECK-EVAL: "<<VarA>>" == "N"
873    """,
874    """
875    fooN
876    """)
877
878  def test_MalformedBranching(self):
879    self.assertBadStructure(
880      """
881        /// CHECK-IF: True
882        /// CHECK: foo
883      """,
884      """
885      foo
886      """)
887    self.assertBadStructure(
888      """
889        /// CHECK-ELSE:
890        /// CHECK: foo
891      """,
892      """
893      foo
894      """)
895    self.assertBadStructure(
896      """
897        /// CHECK-IF: True
898        /// CHECK: foo
899        /// CHECK-ELSE:
900      """,
901      """
902      foo
903      """)
904    self.assertBadStructure(
905      """
906        /// CHECK-IF: True
907        ///   CHECK: foo
908        /// CHECK-ELIF:
909        ///   CHECK: foo
910        ///   CHECK-IF: True
911        ///     CHECK: foo
912        /// CHECK-FI:
913      """,
914      """
915      foo
916      """)
917    self.assertBadStructure(
918      """
919        /// CHECK-IF: True
920        ///   CHECK: foo
921        /// CHECK-ELSE:
922        ///   CHECK: foo
923        /// CHECK-ELIF:
924        ///   CHECK: foo
925        /// CHECK-FI:
926      """,
927      """
928      foo
929      """)
930    self.assertBadStructure(
931      """
932        /// CHECK-IF: True
933        ///   CHECK: foo
934        /// CHECK-ELSE:
935        ///   CHECK: foo
936        /// CHECK-ELSE:
937        ///   CHECK: foo
938        /// CHECK-FI:
939      """,
940      """
941      foo
942      """)
943
944  def test_hasIsaFeature(self):
945    no_isa = None
946    self.assertMatches(
947      """
948        /// CHECK-EVAL: hasIsaFeature('feature1') and not hasIsaFeature('feature2')
949      """,
950      """
951      foo
952      """,
953      no_isa,
954      ImmutableDict({"feature1": True})
955    )
956    self.assertDoesNotMatch(
957      """
958        /// CHECK-EVAL: not hasIsaFeature('feature1')
959      """,
960      """
961      foo
962      """,
963      no_isa,
964      ImmutableDict({"feature1": True})
965    )
966    self.assertMatches(
967      """
968        /// CHECK-IF: hasIsaFeature('feature2')
969        ///   CHECK: bar1
970        /// CHECK-ELSE:
971        ///   CHECK: bar2
972        /// CHECK-FI:
973      """,
974      """
975      foo
976      bar1
977      """,
978      no_isa,
979      ImmutableDict({"feature1": False, "feature2": True})
980    )
981    self.assertMatches(
982      """
983        /// CHECK-EVAL: hasIsaFeature('feature1') and not hasIsaFeature('feature2')
984      """,
985      """
986      foo
987      """,
988      "some_isa",
989      ImmutableDict({"feature1": True})
990    )
991    self.assertDoesNotMatch(
992      """
993        /// CHECK-EVAL: not hasIsaFeature('feature1')
994      """,
995      """
996      foo
997      """,
998      "some_isa",
999      ImmutableDict({"feature1": True})
1000    )
1001    self.assertMatches(
1002      """
1003        /// CHECK-IF: hasIsaFeature('feature2')
1004        ///   CHECK: bar1
1005        /// CHECK-ELSE:
1006        ///   CHECK: bar2
1007        /// CHECK-FI:
1008      """,
1009      """
1010      foo
1011      bar1
1012      """,
1013      "some_isa",
1014      ImmutableDict({"feature1": False, "feature2": True})
1015    )
1016