Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 1 | # |
| 2 | # Test the acc compiler |
| 3 | |
| 4 | import unittest |
| 5 | import subprocess |
| 6 | import os |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 7 | import sets |
| 8 | |
| 9 | gArmInitialized = False |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 10 | |
| 11 | def compile(args): |
| 12 | proc = subprocess.Popen(["acc"] + args, stderr=subprocess.PIPE, stdout=subprocess.PIPE) |
| 13 | result = proc.communicate() |
| 14 | return result |
| 15 | |
| 16 | def runCmd(args): |
| 17 | proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 18 | result = proc.communicate() |
| 19 | return result[0].strip() |
| 20 | |
| 21 | def which(item): |
| 22 | return runCmd(["which", item]) |
| 23 | |
| 24 | def fileType(item): |
| 25 | return runCmd(["file", item]) |
| 26 | |
| 27 | def outputCanRun(): |
| 28 | ft = fileType(which("acc")) |
| 29 | return ft.find("ELF 32-bit LSB executable, Intel 80386") >= 0 |
| 30 | |
| 31 | def adb(args): |
| 32 | return runCmd(["adb"] + args) |
| 33 | |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 34 | def setupArm(): |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 35 | global gArmInitialized |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 36 | if gArmInitialized: |
| 37 | return |
| 38 | print "Setting up arm" |
| 39 | adb(["remount"]) |
| 40 | adb(["shell", "rm", "/system/bin/acc"]) |
| 41 | adb(["shell", "mkdir", "/system/bin/accdata"]) |
| 42 | adb(["shell", "mkdir", "/system/bin/accdata/data"]) |
| 43 | # Clear out old data TODO: handle recursion |
| 44 | adb(["shell", "rm", "/system/bin/accdata/data/*"]) |
| 45 | # Copy over data |
| 46 | for root, dirs, files in os.walk("data"): |
| 47 | for d in dirs: |
| 48 | adb(["shell", "mkdir", os.path.join(root, d)]) |
| 49 | for f in files: |
| 50 | adb(["push", os.path.join(root, f), os.path.join("/system/bin/accdata", root, f)]) |
| 51 | # Copy over compiler |
| 52 | adb(["sync"]) |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 53 | gArmInitialized = True |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 54 | |
| 55 | def compileArm(args): |
| 56 | setupArm() |
| 57 | proc = subprocess.Popen(["adb", "shell", "/system/bin/acc"] + args, stdout=subprocess.PIPE) |
| 58 | result = proc.communicate() |
| 59 | return result[0].replace("\r","") |
| 60 | |
| 61 | def compare(a, b): |
| 62 | if a != b: |
Jack Palevich | 40600de | 2009-07-01 15:32:35 -0700 | [diff] [blame] | 63 | firstDiff = firstDifference(a, b) |
Jack Palevich | bab8064 | 2009-07-09 13:54:54 -0700 | [diff] [blame] | 64 | print "Strings differ at character %d. Common: %s. Difference '%s' != '%s'" % ( |
| 65 | firstDiff, a[0:firstDiff], safeAccess(a, firstDiff), safeAccess(b, firstDiff)) |
Jack Palevich | 40600de | 2009-07-01 15:32:35 -0700 | [diff] [blame] | 66 | |
| 67 | def safeAccess(s, i): |
| 68 | if 0 <= i < len(s): |
| 69 | return s[i] |
| 70 | else: |
| 71 | return '?' |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 72 | |
| 73 | def firstDifference(a, b): |
| 74 | commonLen = min(len(a), len(b)) |
| 75 | for i in xrange(0, commonLen): |
| 76 | if a[i] != b[i]: |
| 77 | return i |
| 78 | return commonLen |
| 79 | |
Jack Palevich | 45431bc | 2009-07-13 15:57:26 -0700 | [diff] [blame] | 80 | # a1 and a2 are the expected stdout and stderr. |
| 81 | # b1 and b2 are the actual stdout and stderr. |
| 82 | # Compare the two, sets. Allow any individual line |
| 83 | # to appear in either stdout or stderr. This is because |
| 84 | # the way we obtain output on the ARM combines both |
| 85 | # streams into one sequence. |
| 86 | |
| 87 | def compareOuput(a1,a2,b1,b2): |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 88 | while True: |
| 89 | totalLen = len(a1) + len(a2) + len(b1) + len(b2) |
| 90 | a1, b1 = matchCommon(a1, b1) |
| 91 | a1, b2 = matchCommon(a1, b2) |
| 92 | a2, b1 = matchCommon(a2, b1) |
| 93 | a2, b2 = matchCommon(a2, b2) |
| 94 | newTotalLen = len(a1) + len(a2) + len(b1) + len(b2) |
| 95 | if newTotalLen == 0: |
| 96 | return True |
| 97 | if newTotalLen == totalLen: |
| 98 | print "Failed at %d %d %d %d" % (len(a1), len(a2), len(b1), len(b2)) |
| 99 | print "a1", a1 |
| 100 | print "a2", a2 |
| 101 | print "b1", b1 |
| 102 | print "b2", b2 |
| 103 | return False |
| 104 | |
| 105 | def matchCommon(a, b): |
Jack Palevich | 45431bc | 2009-07-13 15:57:26 -0700 | [diff] [blame] | 106 | """Remove common items from the beginning of a and b, |
| 107 | return just the tails that are different.""" |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 108 | while len(a) > 0 and len(b) > 0 and a[0] == b[0]: |
| 109 | a = a[1:] |
| 110 | b = b[1:] |
| 111 | return a, b |
| 112 | |
| 113 | def rewritePaths(args): |
| 114 | return [rewritePath(x) for x in args] |
| 115 | |
| 116 | def rewritePath(p): |
Jack Palevich | 45431bc | 2009-07-13 15:57:26 -0700 | [diff] [blame] | 117 | """Take a path that's correct on the x86 and convert to a path |
| 118 | that's correct on ARM.""" |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 119 | if p.startswith("data/"): |
| 120 | p = "/system/bin/accdata/" + p |
| 121 | return p |
| 122 | |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 123 | class TestACC(unittest.TestCase): |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 124 | |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 125 | def checkResult(self, out, err, stdErrResult, stdOutResult=""): |
| 126 | a1 = out.splitlines() |
| 127 | a2 = err.splitlines() |
| 128 | b2 = stdErrResult.splitlines() |
| 129 | b1 = stdOutResult.splitlines() |
Jack Palevich | 45431bc | 2009-07-13 15:57:26 -0700 | [diff] [blame] | 130 | self.assertEqual(True, compareOuput(a1,a2,b1,b2)) |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 131 | |
| 132 | def compileCheck(self, args, stdErrResult, stdOutResult="", |
| 133 | targets=['arm', 'x86']): |
| 134 | targetSet = sets.ImmutableSet(targets) |
| 135 | if 'x86' in targetSet: |
| 136 | out, err = compile(args) |
| 137 | self.checkResult(out, err, stdErrResult, stdOutResult) |
| 138 | if 'arm' in targetSet: |
| 139 | out = compileArm(rewritePaths(args)) |
| 140 | self.checkResult(out, "", stdErrResult, stdOutResult) |
| 141 | |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 142 | def compileCheckArm(self, args, result): |
| 143 | self.assertEqual(compileArm(args), result) |
| 144 | |
| 145 | def testCompileReturnVal(self): |
| 146 | self.compileCheck(["data/returnval-ansi.c"], "") |
| 147 | |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 148 | def testCompileOTCCANSII(self): |
| 149 | self.compileCheck(["data/otcc-ansi.c"], "", "", ['x86']) |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 150 | |
| 151 | def testRunReturnVal(self): |
| 152 | self.compileCheck(["-R", "data/returnval-ansi.c"], |
| 153 | "Executing compiled code:\nresult: 42\n") |
Jack Palevich | 40600de | 2009-07-01 15:32:35 -0700 | [diff] [blame] | 154 | |
Jack Palevich | bab8064 | 2009-07-09 13:54:54 -0700 | [diff] [blame] | 155 | def testStringLiteralConcatenation(self): |
Jack Palevich | 40600de | 2009-07-01 15:32:35 -0700 | [diff] [blame] | 156 | self.compileCheck(["-R", "data/testStringConcat.c"], |
| 157 | "Executing compiled code:\nresult: 13\n", "Hello, world\n") |
| 158 | |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 159 | def testRunOTCCANSI(self): |
| 160 | self.compileCheck(["-R", "data/otcc-ansi.c", "data/returnval.c"], |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 161 | "Executing compiled code:\notcc-ansi.c: About to execute compiled code:\natcc-ansi.c: result: 42\nresult: 42\n", "", |
| 162 | ['x86']) |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 163 | |
| 164 | def testRunOTCCANSI2(self): |
| 165 | self.compileCheck(["-R", "data/otcc-ansi.c", "data/otcc.c", "data/returnval.c"], |
Jack Palevich | 59178c0 | 2009-07-13 14:15:18 -0700 | [diff] [blame] | 166 | "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']) |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 167 | |
| 168 | def testRunConstants(self): |
| 169 | self.compileCheck(["-R", "data/constants.c"], |
| 170 | "Executing compiled code:\nresult: 12\n", |
| 171 | "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" + |
| 172 | "'\\\"' = 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") |
| 173 | |
Jack Palevich | bab8064 | 2009-07-09 13:54:54 -0700 | [diff] [blame] | 174 | def testRunFloat(self): |
| 175 | self.compileCheck(["-R", "data/float.c"], |
| 176 | "Executing compiled code:\nresult: 0\n", |
Jack Palevich | b7718b9 | 2009-07-09 22:00:24 -0700 | [diff] [blame] | 177 | "int: 1 float: 2.2 double: 3.3\n ftoi(1.4f)=1\n dtoi(2.4)=2\n itof(3)=3\n itod(4)=4\nglobals: 1 2 3 4\nargs: 1 2 3 4\nlocals: 1 2 3 4\ncast rval: 2 4\ncast lval: 1.1 2 3.3 4\n") |
Jack Palevich | bab8064 | 2009-07-09 13:54:54 -0700 | [diff] [blame] | 178 | |
| 179 | def testRunFlops(self): |
| 180 | self.compileCheck(["-R", "data/flops.c"], |
Jack Palevich | 45431bc | 2009-07-13 15:57:26 -0700 | [diff] [blame] | 181 | """Executing compiled code: |
| 182 | result: 0""", |
| 183 | """-1.1 = -1.1 |
| 184 | !1.2 = 0 |
| 185 | !0 = 1 |
| 186 | double op double: |
| 187 | 1 + 2 = 3 |
| 188 | 1 - 2 = -1 |
| 189 | 1 * 2 = 2 |
| 190 | 1 / 2 = 0.5 |
| 191 | float op float: |
| 192 | 1 + 2 = 3 |
| 193 | 1 - 2 = -1 |
| 194 | 1 * 2 = 2 |
| 195 | 1 / 2 = 0.5 |
| 196 | double op float: |
| 197 | 1 + 2 = 3 |
| 198 | 1 - 2 = -1 |
| 199 | 1 * 2 = 2 |
| 200 | 1 / 2 = 0.5 |
| 201 | double op int: |
| 202 | 1 + 2 = 3 |
| 203 | 1 - 2 = -1 |
| 204 | 1 * 2 = 2 |
| 205 | 1 / 2 = 0.5 |
| 206 | int op double: |
| 207 | 1 + 2 = 3 |
| 208 | 1 - 2 = -1 |
| 209 | 1 * 2 = 2 |
| 210 | 1 / 2 = 0.5 |
| 211 | double op double: |
| 212 | 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 |
| 213 | 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 |
| 214 | 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 |
| 215 | double op float: |
| 216 | 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 |
| 217 | 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 |
| 218 | 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 |
| 219 | float op float: |
| 220 | 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 |
| 221 | 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 |
| 222 | 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 |
| 223 | int op double: |
| 224 | 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 |
| 225 | 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 |
| 226 | 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 |
| 227 | double op int: |
| 228 | 1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1 |
| 229 | 1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0 |
| 230 | 2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1 |
| 231 | branching: 1 0 1 |
| 232 | testpassi: 1 2 3 4 5 6 7 8 |
| 233 | testpassf: 1 2 3 4 5 6 7 8 |
| 234 | testpassd: 1 2 3 4 5 6 7 8 |
| 235 | testpassidf: 1 2 3 |
| 236 | """) |
| 237 | def testCasts(self): |
| 238 | self.compileCheck(["-R", "data/casts.c"], |
| 239 | """Executing compiled code: |
| 240 | result: 0""", """Reading from a pointer: 3 3 |
| 241 | Writing to a pointer: 4 |
| 242 | Testing casts: 3 3 4.5 4 |
| 243 | Testing reading (int*): 4 |
| 244 | Testing writing (int*): 8 9 |
| 245 | Testing reading (char*): 0x78 0x56 0x34 0x12 |
| 246 | Testing writing (char*): 0x87654321 |
| 247 | f(10) |
| 248 | Function pointer result: 70 |
| 249 | Testing read/write (float*): 8.8 9.9 |
| 250 | Testing read/write (double*): 8.8 9.9 |
| 251 | """) |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 252 | |
Jack Palevich | 25c0cca | 2009-07-13 16:56:28 -0700 | [diff] [blame] | 253 | def testChar(self): |
| 254 | self.compileCheck(["-R", "data/char.c"], """Executing compiled code: |
| 255 | result: 0""", """a = 99, b = 41 |
| 256 | ga = 100, gb = 44""") |
| 257 | |
Jack Palevich | a8f427f | 2009-07-13 18:40:08 -0700 | [diff] [blame] | 258 | def testPointerArithmetic(self): |
| 259 | self.compileCheck(["-R", "data/pointers.c"], """Executing compiled code: |
| 260 | result: 0""", """Pointer difference: 1 4 |
| 261 | Pointer addition: 2 |
| 262 | Pointer comparison to zero: 0 0 1 |
| 263 | Pointer comparison: 1 0 0 0 1 |
| 264 | """) |
| 265 | |
Jack Palevich | 25c0cca | 2009-07-13 16:56:28 -0700 | [diff] [blame] | 266 | |
Jack Palevich | 609c994 | 2009-06-25 11:49:43 -0700 | [diff] [blame] | 267 | if __name__ == '__main__': |
| 268 | if not outputCanRun(): |
| 269 | print "Many tests are expected to fail, because acc is not a 32-bit x86 Linux executable." |
| 270 | unittest.main() |
| 271 | |