Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/env python
      2 # Copyright (C) 2013 Google Inc. All rights reserved.
      3 #
      4 # Redistribution and use in source and binary forms, with or without
      5 # modification, are permitted provided that the following conditions are
      6 # met:
      7 #
      8 #     * Redistributions of source code must retain the above copyright
      9 # notice, this list of conditions and the following disclaimer.
     10 #     * Redistributions in binary form must reproduce the above
     11 # copyright notice, this list of conditions and the following disclaimer
     12 # in the documentation and/or other materials provided with the
     13 # distribution.
     14 #     * Neither the name of Google Inc. nor the names of its
     15 # contributors may be used to endorse or promote products derived from
     16 # this software without specific prior written permission.
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 import tempfile
     31 import unittest
     32 
     33 from make_token_matcher import BadInput, CaseLineProcessor, MainLineProcessor, Optimizer, process_file, SwitchCase, SwitchLineProcessor
     34 
     35 
     36 class OptimizerTest(unittest.TestCase):
     37     def test_nonalphabetic(self):
     38         optimizer = Optimizer(None, None, None)
     39         self.assertRaises(
     40             BadInput,
     41             optimizer.inspect_array,
     42             [SwitchCase('-', None), SwitchCase('x', None)],
     43             [0])
     44 
     45 
     46 class MainLineProcessorTest(unittest.TestCase):
     47     def test_switch(self):
     48         processor = MainLineProcessor(None)
     49         switchLineProcessor = processor.process_line('SWITCH(array, length) {')
     50         self.assertIsInstance(switchLineProcessor, SwitchLineProcessor)
     51         self.assertEquals('array', switchLineProcessor.array_variable)
     52         self.assertEquals('length', switchLineProcessor.length_variable)
     53 
     54 
     55 class SwitchLineProcessorTest(unittest.TestCase):
     56     def test_case(self):
     57         processor = SwitchLineProcessor(None, None, None, None)
     58         caseLineProcessor = processor.process_line('CASE("identifier") {')
     59         self.assertIsInstance(caseLineProcessor, CaseLineProcessor)
     60         self.assertEquals('identifier', caseLineProcessor.identifier)
     61 
     62     def test_unexpected(self):
     63         processor = SwitchLineProcessor(None, None, None, None)
     64         self.assertRaises(
     65             BadInput,
     66             processor.process_line,
     67             'unexpected')
     68 
     69     def test_repeated(self):
     70         processor = SwitchLineProcessor(None, None, None, None)
     71         processor.process_line('CASE("x") {').process_line('}')
     72         caseLineProcessor = processor.process_line('CASE("x") {')
     73         self.assertRaises(
     74             BadInput,
     75             caseLineProcessor.process_line,
     76             '}')
     77 
     78 
     79 class CaseLineProcessorTest(unittest.TestCase):
     80     def test_break(self):
     81         processor = CaseLineProcessor(None, None, None)
     82         self.assertRaises(
     83             BadInput,
     84             processor.process_line,
     85             'break;')
     86 
     87 
     88 class ProcessFileTest(unittest.TestCase):
     89     SOURCE_SMALL = """
     90         SWITCH(p, q) {
     91             CASE("a(") {
     92                 X;
     93             }
     94             CASE("b(") {
     95                 Y;
     96             }
     97         }
     98         """
     99 
    100     EXPECTED_SMALL = """
    101         if (LIKELY(q == 2)) {
    102             if (LIKELY(p[1] == '(')) {
    103                 if ((p[0] | 0x20) == 'a') {
    104                     X;
    105                 } else if (LIKELY((p[0] | 0x20) == 'b')) {
    106                     Y;
    107                 }
    108             }
    109         }
    110         """
    111 
    112     SOURCE_MEDIUM = """
    113         SWITCH (p, q) {
    114             CASE ("ab") {
    115                 X;
    116             }
    117             CASE ("cd") {
    118                 Y;
    119             }
    120             CASE ("ed") {
    121                 Z;
    122             }
    123         }
    124         """
    125 
    126     EXPECTED_MEDIUM = """
    127         if (LIKELY(q == 2)) {
    128             if ((p[1] | 0x20) == 'b') {
    129                 if (LIKELY((p[0] | 0x20) == 'a')) {
    130                     X;
    131                 }
    132             } else if (LIKELY((p[1] | 0x20) == 'd')) {
    133                 if ((p[0] | 0x20) == 'c') {
    134                     Y;
    135                 } else if (LIKELY((p[0] | 0x20) == 'e')) {
    136                     Z;
    137                 }
    138             }
    139         }
    140         """
    141 
    142     SOURCE_LARGE = """
    143         prefix;
    144         SWITCH(p, q) {
    145             CASE("hij") {
    146                 R;
    147             }
    148             CASE("efg") {
    149                 S;
    150             }
    151             CASE("c-") {
    152                 T;
    153             }
    154             CASE("klm") {
    155                 U;
    156             }
    157 
    158             CASE("d-") {
    159                 V;
    160             }
    161             CASE("a") {
    162                 W;
    163                 X;
    164             }
    165             CASE("b-") {
    166                 Y;
    167                 Z;
    168             }
    169         }
    170         suffix;
    171         """
    172 
    173     EXPECTED_LARGE = """
    174         prefix;
    175         switch (q) {
    176         case 1: {
    177             if (LIKELY((p[0] | 0x20) == 'a')) {
    178                 W;
    179                 X;
    180             }
    181         } break;
    182         case 2: {
    183             if (LIKELY(p[1] == '-')) {
    184                 switch ((p[0] | 0x20)) {
    185                 case 'b': {
    186                     Y;
    187                     Z;
    188                 } break;
    189                 case 'c': {
    190                     T;
    191                 } break;
    192                 case 'd': {
    193                     V;
    194                 } break;
    195                 }
    196             }
    197         } break;
    198         case 3: {
    199             switch ((p[0] | 0x20)) {
    200             case 'e': {
    201                 if (LIKELY((p[1] | 0x20) == 'f' && (p[2] | 0x20) == 'g')) {
    202                     S;
    203                 }
    204             } break;
    205             case 'h': {
    206                 if (LIKELY((p[1] | 0x20) == 'i' && (p[2] | 0x20) == 'j')) {
    207                     R;
    208                 }
    209             } break;
    210             case 'k': {
    211                 if (LIKELY((p[1] | 0x20) == 'l' && (p[2] | 0x20) == 'm')) {
    212                     U;
    213                 }
    214             } break;
    215             }
    216         } break;
    217         }
    218         suffix;
    219         """
    220 
    221     def validate(self, source, expected):
    222         with tempfile.NamedTemporaryFile() as input_file:
    223             with tempfile.NamedTemporaryFile() as generated_file:
    224                 input_file.write(source)
    225                 input_file.flush()
    226                 process_file(input_file.name, generated_file.name)
    227                 # Our code generation does not yet implement pretty indentation.
    228                 actual = generated_file.read().replace('    ', '')
    229                 expected = expected.replace('    ', '')
    230                 self.assertEquals(actual, expected)
    231 
    232     def test_small(self):
    233         self.validate(ProcessFileTest.SOURCE_SMALL, ProcessFileTest.EXPECTED_SMALL)
    234 
    235     def test_medium(self):
    236         self.validate(ProcessFileTest.SOURCE_MEDIUM, ProcessFileTest.EXPECTED_MEDIUM)
    237 
    238     def test_large(self):
    239         self.validate(ProcessFileTest.SOURCE_LARGE, ProcessFileTest.EXPECTED_LARGE)
    240 
    241 
    242 if __name__ == "__main__":
    243     unittest.main()
    244