Home | History | Annotate | Download | only in tests
      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