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 script = parseDG(open(self.filename).read()) 74 output = [] 75 76 for command, data in script: 77 if command == 'run': 78 action = 'run' 79 action_data = data 80 if command == 'expect': 81 output.append(data) 82 output = ''.join(output) 83 output = output.replace('\\', '') 84 85 d = action_data.split() 86 if d and d[1] == 'target': 87 for item in d[2:]: 88 if platform_matches(item): 89 break 90 91 else: 92 # Test shouldn't be run on this platform 93 return 94 95 # NOTE: We're ignoring the xfail data for now, none of the 96 # testcases are supposed to fail on darwin. 97 98 self.compileTestCase() 99 data = self.runTestCase() 100 101 if output != '': 102 self.assertEquals(data.rstrip(), output.rstrip()) 103 os.unlink('/tmp/test.bin') 104 105 106 def shortDescription(self): 107 fn = os.path.basename(self.filename)[:-2] 108 dn = os.path.basename(os.path.dirname(self.filename)) 109 return "dejagnu.%s.%s"%(dn, fn) 110 111 def compileTestCase(self): 112 libdir = os.path.join('build', 'temp.%s-%d.%d'%(get_platform(), sys.version_info[0], sys.version_info[1])) 113 if hasattr(sys, 'gettotalrefcount'): 114 libdir += "-pydebug" 115 libdir = os.path.join(libdir, 'libffi-src') 116 117 libffiobjects = self.object_files(libdir) 118 119 120 if self.filename.endswith('.m'): 121 extra_link = '-framework Foundation' 122 else: 123 extra_link = '' 124 125 commandline='MACOSX_DEPLPOYMENT_TARGET=%s %s %s -g -DMACOSX -Ilibffi-src/include -Ilibffi-src/powerpc -o /tmp/test.bin %s %s %s 2>&1'%( 126 get_config_var('MACOSX_DEPLOYMENT_TARGET'), 127 get_config_var('CC'), 128 get_config_var('CFLAGS'), self.filename, ' '.join(libffiobjects), 129 extra_link) 130 131 fp = os.popen(commandline) 132 data = fp.read() 133 xit = fp.close() 134 if xit != None: 135 self.fail("Compile failed[%s]:\n%s"%(xit, data)) 136 137 138 def runTestCase(self): 139 os.environ['DYLD_BIND_AT_LAUNCH'] = '1' 140 fp = os.popen('/tmp/test.bin', 'r') 141 del os.environ['DYLD_BIND_AT_LAUNCH'] 142 data = fp.read() 143 xit = fp.close() 144 if xit != None: 145 self.fail("Running failed (%s)"%(exitCode2Description(xit),)) 146 return data 147 148 149 def object_files(self, basedir): 150 result = [] 151 for dirpath, dirnames, filenames in os.walk(basedir): 152 for fn in filenames: 153 if fn.endswith('.o'): 154 result.append(os.path.join(dirpath, fn)) 155 return result 156 157 158def testSuiteForDirectory(dirname): 159 tests = [] 160 for fn in os.listdir(dirname): 161 if not fn.endswith('.c') and not fn.endswith('.m'): continue 162 tst = DgTestCase(os.path.join(dirname, fn)) 163 if alltests and tst.shortDescription() not in alltests: 164 continue 165 tests.append(tst) 166 167 return unittest.TestSuite(tests) 168 169 170alltests = [] 171if __name__ == "__main__": 172 alltests = sys.argv[1:] 173 runner = unittest.TextTestRunner(verbosity=2) 174 runner.run(testSuiteForDirectory('libffi-src/tests/testsuite/libffi.call')) 175