#!/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()