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