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
21 _wvtest_random_seed = os.environ.get('BUP_TEST_SEED')
22 if _wvtest_random_seed:
23 random.seed(int(_wvtest_random_seed))
25 from os.path import relpath
32 sys.path[:0] = [os.path.realpath('test/lib')]
34 _start_dir = os.getcwd()
37 # Why do we do we need the "!= main" check? Because if you run
38 # wvtest.py as a main program and it imports your test files, then
39 # those test files will try to import the wvtest module recursively.
40 # That actually *works* fine, because we don't run this main program
41 # when we're imported as a module. But you end up with two separate
42 # wvtest modules, the one that gets imported, and the one that's the
43 # main program. Each of them would have duplicated global variables
44 # (most importantly, wvtest._registered), and so screwy things could
45 # happen. Thus, we make the main program module *totally* different
46 # from the imported module. Then we import wvtest (the module) into
47 # wvtest (the main program) here and make sure to refer to the right
48 # versions of global variables.
50 # All this is done just so that wvtest.py can be a single file that's
51 # easy to import into your own applications.
52 if __name__ != '__main__': # we're imported as a module
58 """ Use this decorator (@wvtest) in front of any function you want to
59 run as part of the unit test suite. Then run:
60 python wvtest.py path/to/yourtest.py [other test.py files...]
61 to run all the @wvtest functions in the given file(s).
63 _registered.append(func)
67 def _result(msg, tb, code):
72 (filename, line, func, text) = tb
73 filename = os.path.basename(filename)
74 msg = re.sub(r'\s+', ' ', str(msg))
76 print('! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
81 def _caller_stack(wv_call_depth):
82 # Without the chdir, the source text lookup may fail
86 return traceback.extract_stack()[-(wv_call_depth + 2)]
91 def _check(cond, msg = 'unknown', tb = None):
92 if tb == None: tb = _caller_stack(2)
94 _result(msg, tb, 'ok')
96 _result(msg, tb, 'FAILED')
99 def wvcheck(cond, msg, tb = None):
100 if tb == None: tb = _caller_stack(2)
102 _result(msg, tb, 'ok')
104 _result(msg, tb, 'FAILED')
107 _code_rx = re.compile(r'^\w+\((.*)\)(\s*#.*)?$')
109 text = _caller_stack(2)[3]
110 return _code_rx.sub(r'\1', text)
112 def WVSTART(message):
113 filename = _caller_stack(1)[0]
114 sys.stderr.write('Testing \"' + message + '\" in ' + filename + ':\n')
117 ''' Issues a notification. '''
118 return _result(message, _caller_stack(1), 'ok')
120 def WVPASS(cond = True):
121 ''' Counts a test failure unless cond is true. '''
122 return _check(cond, _code())
124 def WVFAIL(cond = True):
125 ''' Counts a test failure unless cond is false. '''
126 return _check(not cond, 'NOT(%s)' % _code())
129 ''' Counts a test failure unless a == b. '''
130 return _check(a == b, '%s == %s' % (repr(a), repr(b)))
133 ''' Counts a test failure unless a != b. '''
134 return _check(a != b, '%s != %s' % (repr(a), repr(b)))
137 ''' Counts a test failure unless a < b. '''
138 return _check(a < b, '%s < %s' % (repr(a), repr(b)))
141 ''' Counts a test failure unless a <= b. '''
142 return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
145 ''' Counts a test failure unless a > b. '''
146 return _check(a > b, '%s > %s' % (repr(a), repr(b)))
149 ''' Counts a test failure unless a >= b. '''
150 return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
152 def WVEXCEPT(etype, func, *args, **kwargs):
153 ''' Counts a test failure unless func throws an 'etype' exception.
154 You have to spell out the function name and arguments, rather than
155 calling the function yourself, so that WVEXCEPT can run before
156 your test code throws an exception.
159 func(*args, **kwargs)
161 return _check(True, 'EXCEPT(%s)' % _code())
163 _check(False, 'EXCEPT(%s)' % _code())
166 return _check(False, 'EXCEPT(%s)' % _code())
180 def wvfailure_count():
183 def _check_unfinished():
185 for func in _registered:
186 print('WARNING: not run: %r' % (func,))
187 WVFAIL('wvtest_main() not called')
191 atexit.register(_check_unfinished)
194 def _run_in_chdir(path, func, *args, **kwargs):
199 sys.path += [path, os.path.split(path)[0]]
200 return func(*args, **kwargs)
206 def _runtest(fname, f):
207 mod = inspect.getmodule(f)
208 rpath = relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
210 print('Testing "%s" in %s:' % (fname, rpath))
213 _run_in_chdir(os.path.split(mod.__file__)[0], f)
214 except Exception as e:
216 print(traceback.format_exc())
217 tb = sys.exc_info()[2]
218 wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
221 def _run_registered_tests():
222 import wvtest as _wvtestmod
223 while _wvtestmod._registered:
224 t = _wvtestmod._registered.pop(0)
225 _runtest(t.__name__, t)
229 def wvtest_main(extra_testfiles=tuple()):
230 import wvtest as _wvtestmod
231 _run_registered_tests()
232 for modname in extra_testfiles:
233 if not os.path.exists(modname):
234 print('Skipping: %s' % modname)
236 if modname.endswith('.py'):
237 modname = modname[:-3]
238 print('Importing: %s' % modname)
239 path, mod = os.path.split(os.path.abspath(modname))
240 nicename = modname.replace(os.path.sep, '.')
241 while nicename.startswith('.'):
242 nicename = modname[1:]
243 _run_in_chdir(path, __import__, nicename, None, None, [])
244 _run_registered_tests()
246 print('WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
250 if __name__ == '__main__':
251 import wvtest as _wvtestmod
252 sys.modules['wvtest'] = _wvtestmod
253 sys.modules['wvtest.wvtest'] = _wvtestmod
255 wvtest_main(sys.argv[1:])