| #!/usr/bin/env python |
| # Copyright (C) 2013 Google Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above |
| # copyright notice, this list of conditions and the following disclaimer |
| # in the documentation and/or other materials provided with the |
| # distribution. |
| # * Neither the name of Google Inc. nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import tempfile |
| import unittest |
| |
| from make_token_matcher import BadInput, CaseLineProcessor, MainLineProcessor, Optimizer, process_file, SwitchCase, SwitchLineProcessor |
| |
| |
| class OptimizerTest(unittest.TestCase): |
| def test_nonalphabetic(self): |
| optimizer = Optimizer(None, None, None) |
| self.assertRaises( |
| BadInput, |
| optimizer.inspect_array, |
| [SwitchCase('-', None), SwitchCase('x', None)], |
| [0]) |
| |
| |
| class MainLineProcessorTest(unittest.TestCase): |
| def test_switch(self): |
| processor = MainLineProcessor(None) |
| switchLineProcessor = processor.process_line('SWITCH(array, length) {') |
| self.assertIsInstance(switchLineProcessor, SwitchLineProcessor) |
| self.assertEquals('array', switchLineProcessor.array_variable) |
| self.assertEquals('length', switchLineProcessor.length_variable) |
| |
| |
| class SwitchLineProcessorTest(unittest.TestCase): |
| def test_case(self): |
| processor = SwitchLineProcessor(None, None, None, None) |
| caseLineProcessor = processor.process_line('CASE("identifier") {') |
| self.assertIsInstance(caseLineProcessor, CaseLineProcessor) |
| self.assertEquals('identifier', caseLineProcessor.identifier) |
| |
| def test_unexpected(self): |
| processor = SwitchLineProcessor(None, None, None, None) |
| self.assertRaises( |
| BadInput, |
| processor.process_line, |
| 'unexpected') |
| |
| def test_repeated(self): |
| processor = SwitchLineProcessor(None, None, None, None) |
| processor.process_line('CASE("x") {').process_line('}') |
| caseLineProcessor = processor.process_line('CASE("x") {') |
| self.assertRaises( |
| BadInput, |
| caseLineProcessor.process_line, |
| '}') |
| |
| |
| class CaseLineProcessorTest(unittest.TestCase): |
| def test_break(self): |
| processor = CaseLineProcessor(None, None, None) |
| self.assertRaises( |
| BadInput, |
| processor.process_line, |
| 'break;') |
| |
| |
| class ProcessFileTest(unittest.TestCase): |
| SOURCE_SMALL = """ |
| SWITCH(p, q) { |
| CASE("a(") { |
| X; |
| } |
| CASE("b(") { |
| Y; |
| } |
| } |
| """ |
| |
| EXPECTED_SMALL = """ |
| if (LIKELY(q == 2)) { |
| if (LIKELY(p[1] == '(')) { |
| if ((p[0] | 0x20) == 'a') { |
| X; |
| } else if (LIKELY((p[0] | 0x20) == 'b')) { |
| Y; |
| } |
| } |
| } |
| """ |
| |
| SOURCE_MEDIUM = """ |
| SWITCH (p, q) { |
| CASE ("ab") { |
| X; |
| } |
| CASE ("cd") { |
| Y; |
| } |
| CASE ("ed") { |
| Z; |
| } |
| } |
| """ |
| |
| EXPECTED_MEDIUM = """ |
| if (LIKELY(q == 2)) { |
| if ((p[1] | 0x20) == 'b') { |
| if (LIKELY((p[0] | 0x20) == 'a')) { |
| X; |
| } |
| } else if (LIKELY((p[1] | 0x20) == 'd')) { |
| if ((p[0] | 0x20) == 'c') { |
| Y; |
| } else if (LIKELY((p[0] | 0x20) == 'e')) { |
| Z; |
| } |
| } |
| } |
| """ |
| |
| SOURCE_LARGE = """ |
| prefix; |
| SWITCH(p, q) { |
| CASE("hij") { |
| R; |
| } |
| CASE("efg") { |
| S; |
| } |
| CASE("c-") { |
| T; |
| } |
| CASE("klm") { |
| U; |
| } |
| |
| CASE("d-") { |
| V; |
| } |
| CASE("a") { |
| W; |
| X; |
| } |
| CASE("b-") { |
| Y; |
| Z; |
| } |
| } |
| suffix; |
| """ |
| |
| EXPECTED_LARGE = """ |
| prefix; |
| switch (q) { |
| case 1: { |
| if (LIKELY((p[0] | 0x20) == 'a')) { |
| W; |
| X; |
| } |
| } break; |
| case 2: { |
| if (LIKELY(p[1] == '-')) { |
| switch ((p[0] | 0x20)) { |
| case 'b': { |
| Y; |
| Z; |
| } break; |
| case 'c': { |
| T; |
| } break; |
| case 'd': { |
| V; |
| } break; |
| } |
| } |
| } break; |
| case 3: { |
| switch ((p[0] | 0x20)) { |
| case 'e': { |
| if (LIKELY((p[1] | 0x20) == 'f' && (p[2] | 0x20) == 'g')) { |
| S; |
| } |
| } break; |
| case 'h': { |
| if (LIKELY((p[1] | 0x20) == 'i' && (p[2] | 0x20) == 'j')) { |
| R; |
| } |
| } break; |
| case 'k': { |
| if (LIKELY((p[1] | 0x20) == 'l' && (p[2] | 0x20) == 'm')) { |
| U; |
| } |
| } break; |
| } |
| } break; |
| } |
| suffix; |
| """ |
| |
| def validate(self, source, expected): |
| with tempfile.NamedTemporaryFile() as input_file: |
| with tempfile.NamedTemporaryFile() as generated_file: |
| input_file.write(source) |
| input_file.flush() |
| process_file(input_file.name, generated_file.name) |
| # Our code generation does not yet implement pretty indentation. |
| actual = generated_file.read().replace(' ', '') |
| expected = expected.replace(' ', '') |
| self.assertEquals(actual, expected) |
| |
| def test_small(self): |
| self.validate(ProcessFileTest.SOURCE_SMALL, ProcessFileTest.EXPECTED_SMALL) |
| |
| def test_medium(self): |
| self.validate(ProcessFileTest.SOURCE_MEDIUM, ProcessFileTest.EXPECTED_MEDIUM) |
| |
| def test_large(self): |
| self.validate(ProcessFileTest.SOURCE_LARGE, ProcessFileTest.EXPECTED_LARGE) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |