# # Test the acc compiler import unittest import subprocess import os import sys gArmInitialized = False gUseArm = True gUseX86 = True gRunOTCCOutput = True gCompileOTCCANSI = True def parseArgv(): global gUseArm global gUseX86 global gRunOTCCOutput for arg in sys.argv[1:]: if arg == "--noarm": print "--noarm: not testing ARM" gUseArm = False elif arg == "--nox86": print "--nox86: not testing x86" gUseX86 = False elif arg == "--norunotcc": print "--norunotcc detected, not running OTCC output" gRunOTCCOutput = False else: print "Unknown parameter: ", arg raise "Unknown parameter" sys.argv = sys.argv[0:1] def compile(args): proc = subprocess.Popen(["acc"] + args, stderr=subprocess.PIPE, stdout=subprocess.PIPE) result = proc.communicate() return result def runCmd(args): proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = proc.communicate() return result[0].strip() def uname(): return runCmd(["uname"]) def unameM(): return runCmd(["uname", "-m"]) def which(item): return runCmd(["which", item]) def fileType(item): return runCmd(["file", item]) def outputCanRun(): ft = fileType(which("acc")) return ft.find("ELF 32-bit LSB executable, Intel 80386") >= 0 def checkEnvironment(): global gRunOTCCOutput global gCompileOTCCANSI osName = uname() gRunOTCCOutput = osName == "Linux" and unameM() != "x86_64" and outputCanRun() # OSX doesn't have stdin/stdout/stderr accessible through dll load symbols, so # we can't compile the ANSI version of the OTCC compiler on OS X. gCompileOTCCANSI = osName == "Linux" def adb(args): return runCmd(["adb"] + args) def setupArm(): global gArmInitialized if gArmInitialized: return print "Setting up arm" adb(["remount"]) adb(["shell", "rm", "/system/bin/acc"]) adb(["shell", "mkdir", "/system/bin/accdata"]) adb(["shell", "mkdir", "/system/bin/accdata/data"]) # Clear out old data TODO: handle recursion adb(["shell", "rm", "/system/bin/accdata/data/*"]) # Copy over data for root, dirs, files in os.walk("data"): for d in dirs: adb(["shell", "mkdir", os.path.join(root, d)]) for f in files: adb(["push", os.path.join(root, f), os.path.join("/system/bin/accdata", root, f)]) # Copy over compiler adb(["sync"]) gArmInitialized = True def compileArm(args): setupArm() proc = subprocess.Popen(["adb", "shell", "/system/bin/acc"] + args, stdout=subprocess.PIPE) result = proc.communicate() return result[0].replace("\r","") def compare(a, b): if a != b: firstDiff = firstDifference(a, b) print "Strings differ at character %d. Common: %s. Difference '%s' != '%s'" % ( firstDiff, a[0:firstDiff], safeAccess(a, firstDiff), safeAccess(b, firstDiff)) def safeAccess(s, i): if 0 <= i < len(s): return s[i] else: return '?' def firstDifference(a, b): commonLen = min(len(a), len(b)) for i in xrange(0, commonLen): if a[i] != b[i]: return i return commonLen # a1 and a2 are the expected stdout and stderr. # b1 and b2 are the actual stdout and stderr. # Compare the two, sets. Allow any individual line # to appear in either stdout or stderr. This is because # the way we obtain output on the ARM combines both # streams into one sequence. def compareOuput(a1,a2,b1,b2): while True: totalLen = len(a1) + len(a2) + len(b1) + len(b2) a1, b1 = matchCommon(a1, b1) a1, b2 = matchCommon(a1, b2) a2, b1 = matchCommon(a2, b1) a2, b2 = matchCommon(a2, b2) newTotalLen = len(a1) + len(a2) + len(b1) + len(b2) if newTotalLen == 0: return True if newTotalLen == totalLen: print "Failed at %d %d %d %d" % (len(a1), len(a2), len(b1), len(b2)) print "a1", a1 print "a2", a2 print "b1", b1 print "b2", b2 return False def matchCommon(a, b): """Remove common items from the beginning of a and b, return just the tails that are different.""" while len(a) > 0 and len(b) > 0 and a[0] == b[0]: a = a[1:] b = b[1:] return a, b def rewritePaths(args): return [rewritePath(x) for x in args] def rewritePath(p): """Take a path that's correct on the x86 and convert to a path that's correct on ARM.""" if p.startswith("data/"): p = "/system/bin/accdata/" + p return p class TestACC(unittest.TestCase): def checkResult(self, out, err, stdErrResult, stdOutResult=""): a1 = out.splitlines() a2 = err.splitlines() b2 = stdErrResult.splitlines() b1 = stdOutResult.splitlines() self.assertEqual(True, compareOuput(a1,a2,b1,b2)) def compileCheck(self, args, stdErrResult, stdOutResult="", targets=['arm', 'x86']): global gUseArm global gUseX86 targetSet = frozenset(targets) if gUseX86 and 'x86' in targetSet: out, err = compile(args) self.checkResult(out, err, stdErrResult, stdOutResult) if gUseArm and 'arm' in targetSet: out = compileArm(rewritePaths(args)) self.checkResult(out, "", stdErrResult, stdOutResult) def compileCheckArm(self, args, result): self.assertEqual(compileArm(args), result) def testCompileReturnVal(self): self.compileCheck(["data/returnval-ansi.c"], "") def testCompileOTCCANSI(self): global gCompileOTCCANSI if gCompileOTCCANSI: self.compileCheck(["data/otcc-ansi.c"], "", "", ['x86']) def testRunReturnVal(self): self.compileCheck(["-R", "data/returnval-ansi.c"], "Executing compiled code:\nresult: 42\n") def testContinue(self): self.compileCheck(["-R", "data/continue.c"], "Executing compiled code:\nresult: 400\n") def testStringLiteralConcatenation(self): self.compileCheck(["-R", "data/testStringConcat.c"], "Executing compiled code:\nresult: 13\n", "Hello, world\n") def testRunOTCCANSI(self): global gRunOTCCOutput if gRunOTCCOutput: self.compileCheck(["-R", "data/otcc-ansi.c", "data/returnval.c"], "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\natcc-ansi.c: result: 42\nresult: 42\n", "", ['x86']) def testRunOTCCANSI2(self): global gRunOTCCOutput if gRunOTCCOutput: self.compileCheck(["-R", "data/otcc-ansi.c", "data/otcc.c", "data/returnval.c"], "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']) def testRunConstants(self): self.compileCheck(["-R", "data/constants.c"], "Executing compiled code:\nresult: 12\n", "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" + "'\\\"' = 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") def testRunFloat(self): self.compileCheck(["-R", "data/float.c"], "Executing compiled code:\nresult: 0\n", """Constants: 0 0 0 0.01 0.01 0.1 10 10 0.1 int: 1 float: 2.2 double: 3.3 ftoi(1.4f)=1 dtoi(2.4)=2 itof(3)=3 itod(4)=4 globals: 1 2 3 4 args: 1 2 3 4 locals: 1 2 3 4 cast rval: 2 4 cast lval: 1.1 2 3.3 4 """) def testRunFlops(self): self.compileCheck(["-R", "data/flops.c"], """Executing compiled code: result: 0""", """-1.1 = -1.1 !1.2 = 0 !0 = 1 double op double: 1 + 2 = 3 1 - 2 = -1 1 * 2 = 2 1 / 2 = 0.5 float op float: 1 + 2 = 3 1 - 2 = -1 1 * 2 = 2 1 / 2 = 0.5 double op float: 1 + 2 = 3 1 - 2 = -1 1 * 2 = 2 1 / 2 = 0.5 double op int: 1 + 2 = 3 1 - 2 = -1 1 * 2 = 2 1 / 2 = 0.5 int op double: 1 + 2 = 3 1 - 2 = -1 1 * 2 = 2 1 / 2 = 0.5 double op double: 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 double op float: 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 float op float: 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 int op double: 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 double op int: 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 branching: 1 0 1 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 testpassi: 1 2 3 4 5 6 7 8 9 10 11 12 testpassf: 1 2 3 4 5 6 7 8 9 10 11 12 testpassd: 1 2 3 4 5 6 7 8 9 10 11 12 testpassidf: 1 2 3 """) def testCasts(self): self.compileCheck(["-R", "data/casts.c"], """Executing compiled code: result: 0""", """Reading from a pointer: 3 3 Writing to a pointer: 4 Testing casts: 3 3 4.5 4 Testing reading (int*): 4 Testing writing (int*): 8 9 Testing reading (char*): 0x78 0x56 0x34 0x12 Testing writing (char*): 0x87654321 f(10) Function pointer result: 70 Testing read/write (float*): 8.8 9.9 Testing read/write (double*): 8.8 9.9 """) def testChar(self): self.compileCheck(["-R", "data/char.c"], """Executing compiled code: result: 0""", """a = 99, b = 41 ga = 100, gb = 44""") def testTypedef(self): self.compileCheck(["-R", "data/typedef.c"], """Executing compiled code: result: 0""", """x = 3 (4, 6) = (1, 2) + (3, 4) """) def testPointerArithmetic(self): self.compileCheck(["-R", "data/pointers.c"], """Executing compiled code: result: 0""", """Pointer difference: 1 4 Pointer addition: 2 Pointer comparison to zero: 0 0 1 Pointer comparison: 1 0 0 0 1 """) def testRollo3(self): self.compileCheck(["-R", "data/rollo3.c"], """Executing compiled code: result: 10""", """""") def testFloatDouble(self): self.compileCheck(["-R", "data/floatdouble.c"], """Executing compiled code: result: 0""", """0.002 0.1 10""") def testIncDec(self): self.compileCheck(["-R", "data/inc.c"], """Executing compiled code: 0 1 2 1 1 2 1 0 result: 0 ""","""""") def testIops(self): self.compileCheck(["-R", "data/iops.c"], """Executing compiled code: result: 0""", """Literals: 1 -1 ++ 0 1 2 3 4 5 6 7 8 9 -- 10 9 8 7 6 5 4 3 2 1 0 """) def testFilm(self): self.compileCheck(["-R", "data/film.c"], """Executing compiled code: result: 0""", """testing... Total bad: 0 """) def testMacros(self): self.compileCheck(["-R", "data/macros.c"], """Executing compiled code: result: 0""", """A = 6 A = 10 """) def testpointers2(self): self.compileCheck(["-R", "data/pointers2.c"], """Executing compiled code: result: 0""", """a = 0, *pa = 0 a = 2, *pa = 2 a = 0, *pa = 0 **ppa = 0 a = 2, *pa = 2 **ppa = 2 a = 0, *pa = 0 **ppa = 0 a = 2, *pa = 2 **ppa = 2 """) def testassignmentop(self): self.compileCheck(["-R", "data/assignmentop.c"], """Executing compiled code: result: 0""", """2 *= 5 10 20 /= 5 4 17 %= 5 2 17 += 5 22 17 -= 5 12 17<<= 1 34 17>>= 1 8 17&= 1 1 17^= 1 16 16|= 1 17 *f() = *f() + 10; f() f() a = 10 *f() += 10; f() a = 10 """) def testcomma(self): self.compileCheck(["-R", "data/comma.c"], """Executing compiled code: result: 0""", """statement: 10 if: a = 0 while: b = 11 for: b = 22 return: 30 arg: 12 """) def testBrackets(self): self.compileCheck(["-R", "data/brackets.c"], """Executing compiled code: Errors: 0 2D Errors: 0 result: 0 ""","""""") def testShort(self): self.compileCheck(["-R", "data/short.c"], """Executing compiled code: result: -2 ""","""""") def testAssignment(self): self.compileCheck(["-R", "data/assignment.c"], """Executing compiled code: result: 7 ""","""""") def testArray(self): self.compileCheck(["-R", "data/array.c"], """Executing compiled code: localInt: 3 localDouble: 3 3 globalChar: 3 globalDouble: 3 testArgs: 0 2 4 testDecay: Hi! test2D: abcdefghijdefghijklm defghijklmghijklmnop ghijklmnopjklmnopabc jklmnopabcmnopabcdef mnopabcdefpabcdefghi pabcdefghicdefghijkl cdefghijklfghijklmno fghijklmnoijklmnopab ijklmnopablmnopabcde lmnopabcdefghijklmno result: 0 ""","""""") def testDefines(self): self.compileCheck(["-R", "data/defines.c"], """Executing compiled code: result: 3 ""","""""") def testFuncArgs(self): self.compileCheck(["-R", "data/funcargs.c"], """Executing compiled code: result: 4 ""","""""") def testB2071670(self): self.compileCheck(["-R", "data/b2071670.c"], """Executing compiled code: result: 1092616192 ""","""""") def testStructs(self): self.compileCheck(["-R", "data/structs.c"], """Executing compiled code: testCopying: 37 == 37 testUnion: 1 == 0x3f800000 testArgs: (6, 8, 10, 12) result: 6 ""","""""") def testAddressOf(self): self.compileCheck(["-R", "data/addressOf.c"], """Executing compiled code: testStruct: 10 10 10 testArray: 1 1 1 result: 0 ""","""""") def main(): checkEnvironment() parseArgv() unittest.main() if __name__ == '__main__': main()