1 # 2 # Test the acc compiler 3 4 import unittest 5 import subprocess 6 import os 7 import sys 8 9 gArmInitialized = False 10 gUseArm = True 11 gUseX86 = True 12 gRunOTCCOutput = True 13 gCompileOTCCANSI = True 14 15 16 def parseArgv(): 17 global gUseArm 18 global gUseX86 19 global gRunOTCCOutput 20 for arg in sys.argv[1:]: 21 if arg == "--noarm": 22 print "--noarm: not testing ARM" 23 gUseArm = False 24 elif arg == "--nox86": 25 print "--nox86: not testing x86" 26 gUseX86 = False 27 elif arg == "--norunotcc": 28 print "--norunotcc detected, not running OTCC output" 29 gRunOTCCOutput = False 30 else: 31 print "Unknown parameter: ", arg 32 raise "Unknown parameter" 33 sys.argv = sys.argv[0:1] 34 35 def compile(args): 36 proc = subprocess.Popen(["acc"] + args, stderr=subprocess.PIPE, stdout=subprocess.PIPE) 37 result = proc.communicate() 38 return result 39 40 def runCmd(args): 41 proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 42 result = proc.communicate() 43 return result[0].strip() 44 45 def uname(): 46 return runCmd(["uname"]) 47 48 def unameM(): 49 return runCmd(["uname", "-m"]) 50 51 def which(item): 52 return runCmd(["which", item]) 53 54 def fileType(item): 55 return runCmd(["file", item]) 56 57 def outputCanRun(): 58 ft = fileType(which("acc")) 59 return ft.find("ELF 32-bit LSB executable, Intel 80386") >= 0 60 61 def checkEnvironment(): 62 global gRunOTCCOutput 63 global gCompileOTCCANSI 64 osName = uname() 65 gRunOTCCOutput = osName == "Linux" and unameM() != "x86_64" and outputCanRun() 66 # OSX doesn't have stdin/stdout/stderr accessible through dll load symbols, so 67 # we can't compile the ANSI version of the OTCC compiler on OS X. 68 gCompileOTCCANSI = osName == "Linux" 69 70 def adb(args): 71 return runCmd(["adb"] + args) 72 73 def setupArm(): 74 global gArmInitialized 75 if gArmInitialized: 76 return 77 print "Setting up arm" 78 adb(["remount"]) 79 adb(["shell", "rm", "/system/bin/acc"]) 80 adb(["shell", "mkdir", "/system/bin/accdata"]) 81 adb(["shell", "mkdir", "/system/bin/accdata/data"]) 82 # Clear out old data TODO: handle recursion 83 adb(["shell", "rm", "/system/bin/accdata/data/*"]) 84 # Copy over data 85 for root, dirs, files in os.walk("data"): 86 for d in dirs: 87 adb(["shell", "mkdir", os.path.join(root, d)]) 88 for f in files: 89 adb(["push", os.path.join(root, f), os.path.join("/system/bin/accdata", root, f)]) 90 # Copy over compiler 91 adb(["sync"]) 92 gArmInitialized = True 93 94 def compileArm(args): 95 setupArm() 96 proc = subprocess.Popen(["adb", "shell", "/system/bin/acc"] + args, stdout=subprocess.PIPE) 97 result = proc.communicate() 98 return result[0].replace("\r","") 99 100 def compare(a, b): 101 if a != b: 102 firstDiff = firstDifference(a, b) 103 print "Strings differ at character %d. Common: %s. Difference '%s' != '%s'" % ( 104 firstDiff, a[0:firstDiff], safeAccess(a, firstDiff), safeAccess(b, firstDiff)) 105 106 def safeAccess(s, i): 107 if 0 <= i < len(s): 108 return s[i] 109 else: 110 return '?' 111 112 def firstDifference(a, b): 113 commonLen = min(len(a), len(b)) 114 for i in xrange(0, commonLen): 115 if a[i] != b[i]: 116 return i 117 return commonLen 118 119 # a1 and a2 are the expected stdout and stderr. 120 # b1 and b2 are the actual stdout and stderr. 121 # Compare the two, sets. Allow any individual line 122 # to appear in either stdout or stderr. This is because 123 # the way we obtain output on the ARM combines both 124 # streams into one sequence. 125 126 def compareOuput(a1,a2,b1,b2): 127 while True: 128 totalLen = len(a1) + len(a2) + len(b1) + len(b2) 129 a1, b1 = matchCommon(a1, b1) 130 a1, b2 = matchCommon(a1, b2) 131 a2, b1 = matchCommon(a2, b1) 132 a2, b2 = matchCommon(a2, b2) 133 newTotalLen = len(a1) + len(a2) + len(b1) + len(b2) 134 if newTotalLen == 0: 135 return True 136 if newTotalLen == totalLen: 137 print "Failed at %d %d %d %d" % (len(a1), len(a2), len(b1), len(b2)) 138 print "a1", a1 139 print "a2", a2 140 print "b1", b1 141 print "b2", b2 142 return False 143 144 def matchCommon(a, b): 145 """Remove common items from the beginning of a and b, 146 return just the tails that are different.""" 147 while len(a) > 0 and len(b) > 0 and a[0] == b[0]: 148 a = a[1:] 149 b = b[1:] 150 return a, b 151 152 def rewritePaths(args): 153 return [rewritePath(x) for x in args] 154 155 def rewritePath(p): 156 """Take a path that's correct on the x86 and convert to a path 157 that's correct on ARM.""" 158 if p.startswith("data/"): 159 p = "/system/bin/accdata/" + p 160 return p 161 162 class TestACC(unittest.TestCase): 163 164 def checkResult(self, out, err, stdErrResult, stdOutResult=""): 165 a1 = out.splitlines() 166 a2 = err.splitlines() 167 b2 = stdErrResult.splitlines() 168 b1 = stdOutResult.splitlines() 169 self.assertEqual(True, compareOuput(a1,a2,b1,b2)) 170 171 def compileCheck(self, args, stdErrResult, stdOutResult="", 172 targets=['arm', 'x86']): 173 global gUseArm 174 global gUseX86 175 targetSet = frozenset(targets) 176 if gUseX86 and 'x86' in targetSet: 177 out, err = compile(args) 178 self.checkResult(out, err, stdErrResult, stdOutResult) 179 if gUseArm and 'arm' in targetSet: 180 out = compileArm(rewritePaths(args)) 181 self.checkResult(out, "", stdErrResult, stdOutResult) 182 183 def compileCheckArm(self, args, result): 184 self.assertEqual(compileArm(args), result) 185 186 def testCompileReturnVal(self): 187 self.compileCheck(["data/returnval-ansi.c"], "") 188 189 def testCompileOTCCANSI(self): 190 global gCompileOTCCANSI 191 if gCompileOTCCANSI: 192 self.compileCheck(["data/otcc-ansi.c"], "", "", ['x86']) 193 194 def testRunReturnVal(self): 195 self.compileCheck(["-R", "data/returnval-ansi.c"], 196 "Executing compiled code:\nresult: 42\n") 197 198 def testContinue(self): 199 self.compileCheck(["-R", "data/continue.c"], 200 "Executing compiled code:\nresult: 400\n") 201 202 def testStringLiteralConcatenation(self): 203 self.compileCheck(["-R", "data/testStringConcat.c"], 204 "Executing compiled code:\nresult: 13\n", "Hello, world\n") 205 206 def testRunOTCCANSI(self): 207 global gRunOTCCOutput 208 if gRunOTCCOutput: 209 self.compileCheck(["-R", "data/otcc-ansi.c", "data/returnval.c"], 210 "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\natcc-ansi.c: result: 42\nresult: 42\n", "", 211 ['x86']) 212 213 def testRunOTCCANSI2(self): 214 global gRunOTCCOutput 215 if gRunOTCCOutput: 216 self.compileCheck(["-R", "data/otcc-ansi.c", "data/otcc.c", "data/returnval.c"], 217 "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\notcc.c: about to execute compiled code.\natcc-ansi.c: result: 42\nresult: 42\n", "",['x86']) 218 219 def testRunConstants(self): 220 self.compileCheck(["-R", "data/constants.c"], 221 "Executing compiled code:\nresult: 12\n", 222 "0 = 0\n010 = 8\n0x10 = 16\n'\\a' = 7\n'\\b' = 8\n'\\f' = 12\n'\\n' = 10\n'\\r' = 13\n'\\t' = 9\n'\\v' = 11\n'\\\\' = 92\n'\\'' = 39\n" + 223 "'\\\"' = 34\n'\\?' = 63\n'\\0' = 0\n'\\1' = 1\n'\\12' = 10\n'\\123' = 83\n'\\x0' = 0\n'\\x1' = 1\n'\\x12' = 18\n'\\x123' = 291\n'\\x1f' = 31\n'\\x1F' = 31\n") 224 225 def testRunFloat(self): 226 self.compileCheck(["-R", "data/float.c"], 227 "Executing compiled code:\nresult: 0\n", 228 """Constants: 0 0 0 0.01 0.01 0.1 10 10 0.1 229 int: 1 float: 2.2 double: 3.3 230 ftoi(1.4f)=1 231 dtoi(2.4)=2 232 itof(3)=3 233 itod(4)=4 234 globals: 1 2 3 4 235 args: 1 2 3 4 236 locals: 1 2 3 4 237 cast rval: 2 4 238 cast lval: 1.1 2 3.3 4 239 """) 240 241 def testRunFlops(self): 242 self.compileCheck(["-R", "data/flops.c"], 243 """Executing compiled code: 244 result: 0""", 245 """-1.1 = -1.1 246 !1.2 = 0 247 !0 = 1 248 double op double: 249 1 + 2 = 3 250 1 - 2 = -1 251 1 * 2 = 2 252 1 / 2 = 0.5 253 float op float: 254 1 + 2 = 3 255 1 - 2 = -1 256 1 * 2 = 2 257 1 / 2 = 0.5 258 double op float: 259 1 + 2 = 3 260 1 - 2 = -1 261 1 * 2 = 2 262 1 / 2 = 0.5 263 double op int: 264 1 + 2 = 3 265 1 - 2 = -1 266 1 * 2 = 2 267 1 / 2 = 0.5 268 int op double: 269 1 + 2 = 3 270 1 - 2 = -1 271 1 * 2 = 2 272 1 / 2 = 0.5 273 double op double: 274 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 275 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 276 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 277 double op float: 278 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 279 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 280 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 281 float op float: 282 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 283 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 284 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 285 int op double: 286 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 287 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 288 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 289 double op int: 290 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 291 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 292 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 293 branching: 1 0 1 294 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 295 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 296 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 297 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 298 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 299 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 300 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 301 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 302 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 303 testpassidf: 1 2 3 304 """) 305 def testCasts(self): 306 self.compileCheck(["-R", "data/casts.c"], 307 """Executing compiled code: 308 result: 0""", """Reading from a pointer: 3 3 309 Writing to a pointer: 4 310 Testing casts: 3 3 4.5 4 311 Testing reading (int*): 4 312 Testing writing (int*): 8 9 313 Testing reading (char*): 0x78 0x56 0x34 0x12 314 Testing writing (char*): 0x87654321 315 f(10) 316 Function pointer result: 70 317 Testing read/write (float*): 8.8 9.9 318 Testing read/write (double*): 8.8 9.9 319 """) 320 321 def testChar(self): 322 self.compileCheck(["-R", "data/char.c"], """Executing compiled code: 323 result: 0""", """a = 99, b = 41 324 ga = 100, gb = 44""") 325 326 def testTypedef(self): 327 self.compileCheck(["-R", "data/typedef.c"], """Executing compiled code: 328 result: 0""", """x = 3 329 (4, 6) = (1, 2) + (3, 4) 330 """) 331 332 def testPointerArithmetic(self): 333 self.compileCheck(["-R", "data/pointers.c"], """Executing compiled code: 334 result: 0""", """Pointer difference: 1 4 335 Pointer addition: 2 336 Pointer comparison to zero: 0 0 1 337 Pointer comparison: 1 0 0 0 1 338 """) 339 def testRollo3(self): 340 self.compileCheck(["-R", "data/rollo3.c"], """Executing compiled code: 341 result: 10""", """""") 342 343 def testFloatDouble(self): 344 self.compileCheck(["-R", "data/floatdouble.c"], """Executing compiled code: 345 result: 0""", """0.002 0.1 10""") 346 347 def testIncDec(self): 348 self.compileCheck(["-R", "data/inc.c"], """Executing compiled code: 349 0 350 1 351 2 352 1 353 1 354 2 355 1 356 0 357 result: 0 358 ""","""""") 359 360 def testIops(self): 361 self.compileCheck(["-R", "data/iops.c"], """Executing compiled code: 362 result: 0""", """Literals: 1 -1 363 ++ 364 0 365 1 366 2 367 3 368 4 369 5 370 6 371 7 372 8 373 9 374 -- 375 10 376 9 377 8 378 7 379 6 380 5 381 4 382 3 383 2 384 1 385 0 386 """) 387 388 def testFilm(self): 389 self.compileCheck(["-R", "data/film.c"], """Executing compiled code: 390 result: 0""", """testing... 391 Total bad: 0 392 """) 393 394 def testMacros(self): 395 self.compileCheck(["-R", "data/macros.c"], """Executing compiled code: 396 result: 0""", """A = 6 397 A = 10 398 """) 399 400 def testpointers2(self): 401 self.compileCheck(["-R", "data/pointers2.c"], """Executing compiled code: 402 result: 0""", """a = 0, *pa = 0 403 a = 2, *pa = 2 404 a = 0, *pa = 0 **ppa = 0 405 a = 2, *pa = 2 **ppa = 2 406 a = 0, *pa = 0 **ppa = 0 407 a = 2, *pa = 2 **ppa = 2 408 """) 409 410 def testassignmentop(self): 411 self.compileCheck(["-R", "data/assignmentop.c"], """Executing compiled code: 412 result: 0""", """2 *= 5 10 413 20 /= 5 4 414 17 %= 5 2 415 17 += 5 22 416 17 -= 5 12 417 17<<= 1 34 418 17>>= 1 8 419 17&= 1 1 420 17^= 1 16 421 16|= 1 17 422 *f() = *f() + 10; 423 f() 424 f() 425 a = 10 426 *f() += 10; 427 f() 428 a = 10 429 """) 430 431 def testcomma(self): 432 self.compileCheck(["-R", "data/comma.c"], """Executing compiled code: 433 result: 0""", """statement: 10 434 if: a = 0 435 while: b = 11 436 for: b = 22 437 return: 30 438 arg: 12 439 """) 440 441 def testBrackets(self): 442 self.compileCheck(["-R", "data/brackets.c"], """Executing compiled code: 443 Errors: 0 444 2D Errors: 0 445 result: 0 446 ""","""""") 447 448 def testShort(self): 449 self.compileCheck(["-R", "data/short.c"], """Executing compiled code: 450 result: -2 451 ""","""""") 452 453 def testAssignment(self): 454 self.compileCheck(["-R", "data/assignment.c"], """Executing compiled code: 455 result: 7 456 ""","""""") 457 458 def testArray(self): 459 self.compileCheck(["-R", "data/array.c"], """Executing compiled code: 460 localInt: 3 461 localDouble: 3 3 462 globalChar: 3 463 globalDouble: 3 464 testArgs: 0 2 4 465 testDecay: Hi! 466 test2D: 467 abcdefghijdefghijklm 468 defghijklmghijklmnop 469 ghijklmnopjklmnopabc 470 jklmnopabcmnopabcdef 471 mnopabcdefpabcdefghi 472 pabcdefghicdefghijkl 473 cdefghijklfghijklmno 474 fghijklmnoijklmnopab 475 ijklmnopablmnopabcde 476 lmnopabcdefghijklmno 477 result: 0 478 ""","""""") 479 480 def testDefines(self): 481 self.compileCheck(["-R", "data/defines.c"], """Executing compiled code: 482 result: 3 483 ""","""""") 484 485 def testFuncArgs(self): 486 self.compileCheck(["-R", "data/funcargs.c"], """Executing compiled code: 487 result: 4 488 ""","""""") 489 490 def testB2071670(self): 491 self.compileCheck(["-R", "data/b2071670.c"], """Executing compiled code: 492 result: 1092616192 493 ""","""""") 494 495 def testStructs(self): 496 self.compileCheck(["-R", "data/structs.c"], """Executing compiled code: 497 testCopying: 37 == 37 498 testUnion: 1 == 0x3f800000 499 testArgs: (6, 8, 10, 12) 500 result: 6 501 ""","""""") 502 503 def testAddressOf(self): 504 self.compileCheck(["-R", "data/addressOf.c"], """Executing compiled code: 505 testStruct: 10 10 10 506 testArray: 1 1 1 507 result: 0 508 ""","""""") 509 510 def main(): 511 checkEnvironment() 512 parseArgv() 513 unittest.main() 514 515 if __name__ == '__main__': 516 main() 517 518