1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4from __future__ import print_function, unicode_literals 5 6import sys 7import os 8import re 9 10from subprocess import Popen, PIPE 11 12import types 13if sys.version_info.major == 2: 14 import copy_reg as copyreg 15else: 16 import copyreg 17 18def _pickle_method(method): 19 func_name = method.im_func.__name__ 20 obj = method.im_self 21 cls = method.im_class 22 return _unpickle_method, (func_name, obj, cls) 23 24def _unpickle_method(func_name, obj, cls): 25 for cls in cls.mro(): 26 try: 27 func = cls.__dict__[func_name] 28 except KeyError: 29 pass 30 else: 31 break 32 return func.__get__(obj, cls) 33 34copyreg.pickle(types.MethodType, _pickle_method, _unpickle_method) 35 36class LedgerHarness: 37 ledger = None 38 sourcepath = None 39 succeeded = 0 40 failed = 0 41 verify = False 42 gmalloc = False 43 python = False 44 45 def __init__(self, argv): 46 if not os.path.isfile(argv[1]): 47 print("Cannot find ledger at '%s'" % argv[1]) 48 sys.exit(1) 49 if not os.path.isdir(argv[2]): 50 print("Cannot find source path at '%s'" % argv[2]) 51 sys.exit(1) 52 53 self.ledger = os.path.abspath(argv[1]) 54 self.sourcepath = os.path.abspath(argv[2]) 55 self.succeeded = 0 56 self.failed = 0 57 self.verify = '--verify' in argv 58 self.gmalloc = '--gmalloc' in argv 59 self.python = '--python' in argv 60 61 def run(self, command, verify=None, gmalloc=None, columns=True): 62 env = os.environ.copy() 63 64 if (gmalloc is not None and gmalloc) or \ 65 (gmalloc is None and self.gmalloc): 66 env['MallocGuardEdges'] = '1' 67 env['MallocScribble'] = '1' 68 env['MallocPreScribble'] = '1' 69 env['MallocCheckHeapStart'] = '1000' 70 env['MallocCheckHeapEach'] = '10000' 71 env['DYLD_INSERT_LIBRARIES'] = '/usr/lib/libgmalloc.dylib' 72 env['MALLOC_PROTECT_BEFORE'] = '1' 73 env['MALLOC_FILL_SPACE'] = '1' 74 env['MALLOC_STRICT_SIZE'] = '1' 75 76 if (verify is not None and verify) or \ 77 (verify is None and self.verify): 78 insert = ' --verify' 79 else: 80 insert = '' 81 82 if columns: 83 insert += ' --columns=80' 84 85 command = re.sub('\$ledger', '%s%s %s' % \ 86 (self.ledger, insert, '--args-only'), command) 87 88 valgrind = '/usr/bin/valgrind' 89 if not os.path.isfile(valgrind): 90 valgrind = '/opt/local/bin/valgrind' 91 92 if os.path.isfile(valgrind) and '--verify' in insert: 93 command = valgrind + ' -q ' + command 94 95 # If we are running under msys2, use bash to execute the test commands 96 if 'MSYSTEM' in os.environ: 97 bash_path = os.environ['MINGW_PREFIX'] + '/../usr/bin/bash.exe' 98 return Popen([bash_path, '-c', command], shell=False, 99 close_fds=False, env=env, stdin=PIPE, stdout=PIPE, 100 stderr=PIPE, cwd=self.sourcepath) 101 102 return Popen(command, shell=True, close_fds=True, env=env, 103 stdin=PIPE, stdout=PIPE, stderr=PIPE, 104 cwd=self.sourcepath) 105 106 def read(self, fd): 107 text = "" 108 text_data = os.read(fd.fileno(), 8192) 109 while text_data: 110 if text_data: 111 text += text_data 112 text_data = os.read(fd.fileno(), 8192) 113 return text 114 115 def readlines(self, fd): 116 lines = [] 117 for line in fd.readlines(): 118 if sys.version_info.major == 2: 119 line = unicode(line, 'utf-8') 120 else: 121 line = line.decode('utf-8') 122 if not line.startswith('GuardMalloc'): 123 lines.append(line) 124 return lines 125 126 def wait(self, process, msg='Ledger invocation failed:'): 127 if process.wait() != 0: 128 print(msg) 129 print(process.stderr.read()) 130 self.failure() 131 return False 132 return True 133 134 def success(self): 135 sys.stdout.write(".") 136 sys.stdout.flush() 137 self.succeeded += 1 138 139 def failure(self, name=None): 140 sys.stdout.write("E") 141 if name: 142 sys.stdout.write("[%s]" % name) 143 sys.stdout.flush() 144 self.failed += 1 145 146 def exit(self): 147 print() 148 if self.succeeded > 0: 149 print("OK (%d) " % self.succeeded,) 150 if self.failed > 0: 151 print("FAILED (%d)" % self.failed,) 152 print() 153 154 sys.exit(self.failed) 155 156if __name__ == '__main__': 157 harness = LedgerHarness(sys.argv) 158 proc = harness.run('$ledger -f doc/sample.dat reg') 159 print('STDOUT:') 160 print(proc.stdout.read()) 161 print('STDERR:') 162 print(proc.stderr.read()) 163 harness.success() 164 harness.exit() 165