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