3 bup_python="$(dirname "$0")/dev/bup-python"
4 exec "$bup_python" "$0" ${1+"$@"}
10 # Copyright (C)2007-2012 Versabanq Innovations Inc. and contributors.
11 # Licensed under the GNU Library General Public License, version 2.
12 # See the included file named LICENSE for license information.
13 # You can get wvtest from: http://github.com/apenwarr/wvtest
16 from __future__ import absolute_import, print_function
17 from os.path import relpath
25 _start_dir = os.getcwd()
28 # Why do we do we need the "!= main" check? Because if you run
29 # wvtest.py as a main program and it imports your test files, then
30 # those test files will try to import the wvtest module recursively.
31 # That actually *works* fine, because we don't run this main program
32 # when we're imported as a module. But you end up with two separate
33 # wvtest modules, the one that gets imported, and the one that's the
34 # main program. Each of them would have duplicated global variables
35 # (most importantly, wvtest._registered), and so screwy things could
36 # happen. Thus, we make the main program module *totally* different
37 # from the imported module. Then we import wvtest (the module) into
38 # wvtest (the main program) here and make sure to refer to the right
39 # versions of global variables.
41 # All this is done just so that wvtest.py can be a single file that's
42 # easy to import into your own applications.
43 if __name__ != '__main__': # we're imported as a module
49 """ Use this decorator (@wvtest) in front of any function you want to
50 run as part of the unit test suite. Then run:
51 python wvtest.py path/to/yourtest.py [other test.py files...]
52 to run all the @wvtest functions in the given file(s).
54 _registered.append(func)
58 def _result(msg, tb, code):
63 (filename, line, func, text) = tb
64 filename = os.path.basename(filename)
65 msg = re.sub(r'\s+', ' ', str(msg))
67 print('! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
72 def _caller_stack(wv_call_depth):
73 # Without the chdir, the source text lookup may fail
77 return traceback.extract_stack()[-(wv_call_depth + 2)]
82 def _check(cond, msg = 'unknown', tb = None):
83 if tb == None: tb = _caller_stack(2)
85 _result(msg, tb, 'ok')
87 _result(msg, tb, 'FAILED')
90 def wvcheck(cond, msg, tb = None):
91 if tb == None: tb = _caller_stack(2)
93 _result(msg, tb, 'ok')
95 _result(msg, tb, 'FAILED')
98 _code_rx = re.compile(r'^\w+\((.*)\)(\s*#.*)?$')
100 text = _caller_stack(2)[3]
101 return _code_rx.sub(r'\1', text)
103 def WVSTART(message):
104 filename = _caller_stack(1)[0]
105 sys.stderr.write('Testing \"' + message + '\" in ' + filename + ':\n')
108 ''' Issues a notification. '''
109 return _result(message, _caller_stack(1), 'ok')
111 def WVPASS(cond = True):
112 ''' Counts a test failure unless cond is true. '''
113 return _check(cond, _code())
115 def WVFAIL(cond = True):
116 ''' Counts a test failure unless cond is false. '''
117 return _check(not cond, 'NOT(%s)' % _code())
120 ''' Counts a test failure unless a == b. '''
121 return _check(a == b, '%s == %s' % (repr(a), repr(b)))
124 ''' Counts a test failure unless a != b. '''
125 return _check(a != b, '%s != %s' % (repr(a), repr(b)))
128 ''' Counts a test failure unless a < b. '''
129 return _check(a < b, '%s < %s' % (repr(a), repr(b)))
132 ''' Counts a test failure unless a <= b. '''
133 return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
136 ''' Counts a test failure unless a > b. '''
137 return _check(a > b, '%s > %s' % (repr(a), repr(b)))
140 ''' Counts a test failure unless a >= b. '''
141 return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
143 def WVEXCEPT(etype, func, *args, **kwargs):
144 ''' Counts a test failure unless func throws an 'etype' exception.
145 You have to spell out the function name and arguments, rather than
146 calling the function yourself, so that WVEXCEPT can run before
147 your test code throws an exception.
150 func(*args, **kwargs)
152 return _check(True, 'EXCEPT(%s)' % _code())
154 _check(False, 'EXCEPT(%s)' % _code())
157 return _check(False, 'EXCEPT(%s)' % _code())
171 def wvfailure_count():
174 def _check_unfinished():
176 for func in _registered:
177 print('WARNING: not run: %r' % (func,))
178 WVFAIL('wvtest_main() not called')
182 atexit.register(_check_unfinished)
185 def _run_in_chdir(path, func, *args, **kwargs):
190 sys.path += [path, os.path.split(path)[0]]
191 return func(*args, **kwargs)
197 def _runtest(fname, f):
198 mod = inspect.getmodule(f)
199 rpath = relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
201 print('Testing "%s" in %s:' % (fname, rpath))
204 _run_in_chdir(os.path.split(mod.__file__)[0], f)
205 except Exception as e:
207 print(traceback.format_exc())
208 tb = sys.exc_info()[2]
209 wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
212 def _run_registered_tests():
213 import wvtest as _wvtestmod
214 while _wvtestmod._registered:
215 t = _wvtestmod._registered.pop(0)
216 _runtest(t.__name__, t)
220 def wvtest_main(extra_testfiles=tuple()):
221 import wvtest as _wvtestmod
222 _run_registered_tests()
223 for modname in extra_testfiles:
224 if not os.path.exists(modname):
225 print('Skipping: %s' % modname)
227 if modname.endswith('.py'):
228 modname = modname[:-3]
229 print('Importing: %s' % modname)
230 path, mod = os.path.split(os.path.abspath(modname))
231 nicename = modname.replace(os.path.sep, '.')
232 while nicename.startswith('.'):
233 nicename = modname[1:]
234 _run_in_chdir(path, __import__, nicename, None, None, [])
235 _run_registered_tests()
237 print('WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
241 if __name__ == '__main__':
242 import wvtest as _wvtestmod
243 sys.modules['wvtest'] = _wvtestmod
244 sys.modules['wvtest.wvtest'] = _wvtestmod
246 wvtest_main(sys.argv[1:])