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 sys.path[:0] = [os.path.realpath('test/lib')]
27 _start_dir = os.getcwd()
30 # Why do we do we need the "!= main" check? Because if you run
31 # wvtest.py as a main program and it imports your test files, then
32 # those test files will try to import the wvtest module recursively.
33 # That actually *works* fine, because we don't run this main program
34 # when we're imported as a module. But you end up with two separate
35 # wvtest modules, the one that gets imported, and the one that's the
36 # main program. Each of them would have duplicated global variables
37 # (most importantly, wvtest._registered), and so screwy things could
38 # happen. Thus, we make the main program module *totally* different
39 # from the imported module. Then we import wvtest (the module) into
40 # wvtest (the main program) here and make sure to refer to the right
41 # versions of global variables.
43 # All this is done just so that wvtest.py can be a single file that's
44 # easy to import into your own applications.
45 if __name__ != '__main__': # we're imported as a module
51 """ Use this decorator (@wvtest) in front of any function you want to
52 run as part of the unit test suite. Then run:
53 python wvtest.py path/to/yourtest.py [other test.py files...]
54 to run all the @wvtest functions in the given file(s).
56 _registered.append(func)
60 def _result(msg, tb, code):
65 (filename, line, func, text) = tb
66 filename = os.path.basename(filename)
67 msg = re.sub(r'\s+', ' ', str(msg))
69 print('! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
74 def _caller_stack(wv_call_depth):
75 # Without the chdir, the source text lookup may fail
79 return traceback.extract_stack()[-(wv_call_depth + 2)]
84 def _check(cond, msg = 'unknown', tb = None):
85 if tb == None: tb = _caller_stack(2)
87 _result(msg, tb, 'ok')
89 _result(msg, tb, 'FAILED')
92 def wvcheck(cond, msg, tb = None):
93 if tb == None: tb = _caller_stack(2)
95 _result(msg, tb, 'ok')
97 _result(msg, tb, 'FAILED')
100 _code_rx = re.compile(r'^\w+\((.*)\)(\s*#.*)?$')
102 text = _caller_stack(2)[3]
103 return _code_rx.sub(r'\1', text)
105 def WVSTART(message):
106 filename = _caller_stack(1)[0]
107 sys.stderr.write('Testing \"' + message + '\" in ' + filename + ':\n')
110 ''' Issues a notification. '''
111 return _result(message, _caller_stack(1), 'ok')
113 def WVPASS(cond = True):
114 ''' Counts a test failure unless cond is true. '''
115 return _check(cond, _code())
117 def WVFAIL(cond = True):
118 ''' Counts a test failure unless cond is false. '''
119 return _check(not cond, 'NOT(%s)' % _code())
122 ''' Counts a test failure unless a == b. '''
123 return _check(a == b, '%s == %s' % (repr(a), repr(b)))
126 ''' Counts a test failure unless a != b. '''
127 return _check(a != b, '%s != %s' % (repr(a), repr(b)))
130 ''' Counts a test failure unless a < b. '''
131 return _check(a < b, '%s < %s' % (repr(a), repr(b)))
134 ''' Counts a test failure unless a <= b. '''
135 return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
138 ''' Counts a test failure unless a > b. '''
139 return _check(a > b, '%s > %s' % (repr(a), repr(b)))
142 ''' Counts a test failure unless a >= b. '''
143 return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
145 def WVEXCEPT(etype, func, *args, **kwargs):
146 ''' Counts a test failure unless func throws an 'etype' exception.
147 You have to spell out the function name and arguments, rather than
148 calling the function yourself, so that WVEXCEPT can run before
149 your test code throws an exception.
152 func(*args, **kwargs)
154 return _check(True, 'EXCEPT(%s)' % _code())
156 _check(False, 'EXCEPT(%s)' % _code())
159 return _check(False, 'EXCEPT(%s)' % _code())
173 def wvfailure_count():
176 def _check_unfinished():
178 for func in _registered:
179 print('WARNING: not run: %r' % (func,))
180 WVFAIL('wvtest_main() not called')
184 atexit.register(_check_unfinished)
187 def _run_in_chdir(path, func, *args, **kwargs):
192 sys.path += [path, os.path.split(path)[0]]
193 return func(*args, **kwargs)
199 def _runtest(fname, f):
200 mod = inspect.getmodule(f)
201 rpath = relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
203 print('Testing "%s" in %s:' % (fname, rpath))
206 _run_in_chdir(os.path.split(mod.__file__)[0], f)
207 except Exception as e:
209 print(traceback.format_exc())
210 tb = sys.exc_info()[2]
211 wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
214 def _run_registered_tests():
215 import wvtest as _wvtestmod
216 while _wvtestmod._registered:
217 t = _wvtestmod._registered.pop(0)
218 _runtest(t.__name__, t)
222 def wvtest_main(extra_testfiles=tuple()):
223 import wvtest as _wvtestmod
224 _run_registered_tests()
225 for modname in extra_testfiles:
226 if not os.path.exists(modname):
227 print('Skipping: %s' % modname)
229 if modname.endswith('.py'):
230 modname = modname[:-3]
231 print('Importing: %s' % modname)
232 path, mod = os.path.split(os.path.abspath(modname))
233 nicename = modname.replace(os.path.sep, '.')
234 while nicename.startswith('.'):
235 nicename = modname[1:]
236 _run_in_chdir(path, __import__, nicename, None, None, [])
237 _run_registered_tests()
239 print('WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
243 if __name__ == '__main__':
244 import wvtest as _wvtestmod
245 sys.modules['wvtest'] = _wvtestmod
246 sys.modules['wvtest.wvtest'] = _wvtestmod
248 wvtest_main(sys.argv[1:])