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