1#!/usr/bin/python 2""" 3A very crude emulator of dejagnu, just enough to integrate the libbfi 4unittests into the pyobjc ones. 5""" 6import os 7import re 8import sys 9import signal 10from fnmatch import fnmatch 11import unittest 12from distutils.util import get_platform 13 14gDgCommands=re.compile(r''' 15 (?:{\s*(dg-do)\s*run\s*({[^}]*})?\s*}) 16 | 17 (?:{\s*(dg-output)\s*"([^"]*)"\s*}) 18 ''', 19 re.VERBOSE|re.MULTILINE) 20 21def signame(code): 22 for nm in dir(signal): 23 if nm.startswith('SIG') and nm[3] != '_' \ 24 and getattr(signal, nm) == code: 25 return nm 26 return code 27 28def exitCode2Description(code): 29 """ 30 Convert the exit code as returned by os.popen().close() to a string 31 """ 32 if os.WIFEXITED(code): 33 return 'exited with status %s'%(os.WEXITSTATUS(code),) 34 35 elif os.WIFSIGNALED(code): 36 sig = os.WTERMSIG(code) 37 return 'crashed with signal %s [%s]'%(signame(sig), sig) 38 39 else: 40 return 'exit code %s'%(code,) 41 42def platform_matches(matchstr): 43 # This is a hack 44 if sys.byteorder == 'little': 45 platform = 'i386-apple-darwin' 46 else: 47 platform = 'powerpc-apple-darwin' 48 49 return fnmatch(platform, matchstr) 50 51def parseDG(fdata): 52 result = [] 53 for item in gDgCommands.findall(fdata): 54 if item[0] == 'dg-do': 55 result.append(('run', item[1])) 56 elif item[2] == 'dg-output': 57 result.append(('expect', item[3].decode('string_escape'))) 58 return result 59 60 61class DgTestCase (unittest.TestCase): 62 def __init__(self, filename): 63 unittest.TestCase.__init__(self) 64 self.filename = filename 65 66 #archOption = "-arch ppc" 67 #archOption = "-arch ppc64" 68 archOption = "-arch i386" 69 #archOption = "-arch x86_64" 70 #archOption = "" 71 compileOptionsBase = "-g -DMACOSX -Iinclude -o /tmp/test.bin -lffi" 72 compileOptionsList = ( # HACK ALERT: Yes, there are better ways to do this, but this is easy and extremely flexible 73 "%s %s %s" % (compileOptionsBase, archOption, "-O0"), 74 "%s %s %s" % (compileOptionsBase, archOption, "-O1"), 75 "%s %s %s" % (compileOptionsBase, archOption, "-O2"), 76 "%s %s %s" % (compileOptionsBase, archOption, "-O3"), 77 "%s %s %s" % (compileOptionsBase, archOption, "-Os"), 78# "%s %s %s" % (compileOptionsBase, archOption, "-Oz"), # Note: Apple-Only, see gcc man page for details 79 ) 80 def runTest(self): 81 script = parseDG(open(self.filename).read()) 82 output = [] 83 84 for command, data in script: 85 if command == 'run': 86 action = 'run' 87 action_data = data 88 if command == 'expect': 89 output.append(data) 90 output = ''.join(output) 91 output = output.replace('\\', '') 92 93 d = action_data.split() 94 if d and d[1] == 'target': 95 for item in d[2:]: 96 if platform_matches(item): 97 break 98 99 else: 100 # Test shouldn't be run on this platform 101 return 102 103 # NOTE: We're ignoring the xfail data for now, none of the 104 # testcases are supposed to fail on darwin. 105 106 for compileOptions in self.compileOptionsList: 107 self.compileTestCase(compileOptions) 108 data = self.runTestCase() 109 110 if output != '': 111 self.assertEquals(data.rstrip(), output.rstrip()) 112 os.unlink('/tmp/test.bin') 113 114 115 def shortDescription(self): 116 fn = os.path.basename(self.filename)[:-2] 117 dn = os.path.basename(os.path.dirname(self.filename)) 118 return "dejagnu.%s.%s"%(dn, fn) 119 120 def compileTestCase(self, compileOptions): 121 # libdir = os.path.join('build', 'temp.%s-%d.%d'%(get_platform(), sys.version_info[0], sys.version_info[1]), 'libffi-src') 122 # libffiobjects = self.object_files(libdir) 123 124 #compiler='clang' 125 compiler='gcc' 126 commandline='%s %s %s 2>&1' % (compiler, compileOptions, self.filename) 127# print 128# print "%s (%s)" % (self.filename, compiler) 129# print 130 fp = os.popen(commandline) 131 data = fp.read() 132 xit = fp.close() 133 if xit != None: 134 self.fail("Compile failed[%s]:\n%s"%(xit, data)) 135 136 137 def runTestCase(self): 138 os.environ['DYLD_BIND_AT_LAUNCH'] = '1' 139 fp = os.popen('/tmp/test.bin', 'r') 140 del os.environ['DYLD_BIND_AT_LAUNCH'] 141 data = fp.read() 142 xit = fp.close() 143 if xit != None: 144 self.fail("Running failed (%s)"%(exitCode2Description(xit),)) 145 return data 146 147 148 def object_files(self, basedir): 149 result = [] 150 for dirpath, dirnames, filenames in os.walk(basedir): 151 for fn in filenames: 152 if fn.endswith('.o'): 153 result.append(os.path.join(dirpath, fn)) 154 return result 155 156 157def testSuiteForDirectory(dirname): 158 tests = [] 159 for fn in os.listdir(dirname): 160 if not fn.endswith('.c'): continue 161 tst = DgTestCase(os.path.join(dirname, fn)) 162 if alltests and tst.shortDescription() not in alltests: 163 continue 164 tests.append(tst) 165 166 return unittest.TestSuite(tests) 167 168alltests = [] 169if __name__ == "__main__": 170 alltests = sys.argv[1:] 171 runner = unittest.TextTestRunner(verbosity=5) 172 runner.run(testSuiteForDirectory('tests/testsuite/libffi.call')) 173