3 bup_python="$(dirname "$0")/cmd/bup-python"
4 exec "$bup_python" "$0" ${1+"$@"}
9 # Copyright (C)2007-2012 Versabanq Innovations Inc. and contributors.
10 # Licensed under the GNU Library General Public License, version 2.
11 # See the included file named LICENSE for license information.
12 # You can get wvtest from: http://github.com/apenwarr/wvtest
22 # Why do we do we need the "!= main" check? Because if you run
23 # wvtest.py as a main program and it imports your test files, then
24 # those test files will try to import the wvtest module recursively.
25 # That actually *works* fine, because we don't run this main program
26 # when we're imported as a module. But you end up with two separate
27 # wvtest modules, the one that gets imported, and the one that's the
28 # main program. Each of them would have duplicated global variables
29 # (most importantly, wvtest._registered), and so screwy things could
30 # happen. Thus, we make the main program module *totally* different
31 # from the imported module. Then we import wvtest (the module) into
32 # wvtest (the main program) here and make sure to refer to the right
33 # versions of global variables.
35 # All this is done just so that wvtest.py can be a single file that's
36 # easy to import into your own applications.
37 if __name__ != '__main__': # we're imported as a module
43 """ Use this decorator (@wvtest) in front of any function you want to
44 run as part of the unit test suite. Then run:
45 python wvtest.py path/to/yourtest.py [other test.py files...]
46 to run all the @wvtest functions in the given file(s).
48 _registered.append(func)
52 def _result(msg, tb, code):
57 (filename, line, func, text) = tb
58 filename = os.path.basename(filename)
59 msg = re.sub(r'\s+', ' ', str(msg))
61 print '! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
66 def _check(cond, msg = 'unknown', tb = None):
67 if tb == None: tb = traceback.extract_stack()[-3]
69 _result(msg, tb, 'ok')
71 _result(msg, tb, 'FAILED')
76 (filename, line, func, text) = traceback.extract_stack()[-3]
77 text = re.sub(r'^\w+\((.*)\)(\s*#.*)?$', r'\1', text);
82 ''' Issues a notification. '''
83 return _result(message, traceback.extract_stack()[-3], 'ok')
85 def WVPASS(cond = True):
86 ''' Counts a test failure unless cond is true. '''
87 return _check(cond, _code())
89 def WVFAIL(cond = True):
90 ''' Counts a test failure unless cond is false. '''
91 return _check(not cond, 'NOT(%s)' % _code())
94 ''' Counts a test failure unless a == b. '''
95 return _check(a == b, '%s == %s' % (repr(a), repr(b)))
98 ''' Counts a test failure unless a != b. '''
99 return _check(a != b, '%s != %s' % (repr(a), repr(b)))
102 ''' Counts a test failure unless a < b. '''
103 return _check(a < b, '%s < %s' % (repr(a), repr(b)))
106 ''' Counts a test failure unless a <= b. '''
107 return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
110 ''' Counts a test failure unless a > b. '''
111 return _check(a > b, '%s > %s' % (repr(a), repr(b)))
114 ''' Counts a test failure unless a >= b. '''
115 return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
117 def WVEXCEPT(etype, func, *args, **kwargs):
118 ''' Counts a test failure unless func throws an 'etype' exception.
119 You have to spell out the function name and arguments, rather than
120 calling the function yourself, so that WVEXCEPT can run before
121 your test code throws an exception.
124 func(*args, **kwargs)
126 return _check(True, 'EXCEPT(%s)' % _code())
128 _check(False, 'EXCEPT(%s)' % _code())
131 return _check(False, 'EXCEPT(%s)' % _code())
133 def wvfailure_count():
136 def _check_unfinished():
138 for func in _registered:
139 print 'WARNING: not run: %r' % (func,)
140 WVFAIL('wvtest_main() not called')
144 atexit.register(_check_unfinished)
147 def _run_in_chdir(path, func, *args, **kwargs):
152 sys.path += [path, os.path.split(path)[0]]
153 return func(*args, **kwargs)
159 if sys.version_info >= (2,6,0):
160 _relpath = os.path.relpath;
162 # Implementation for Python 2.5, taken from CPython (tag v2.6,
163 # file Lib/posixpath.py, hg-commit 95fff5a6a276). Update
164 # ./LICENSE When this code is eventually removed.
165 def _relpath(path, start=os.path.curdir):
167 raise ValueError("no path specified")
169 start_list = os.path.abspath(start).split(os.path.sep)
170 path_list = os.path.abspath(path).split(os.path.sep)
172 # Work out how much of the filepath is shared by start and path.
173 i = len(os.path.commonprefix([start_list, path_list]))
175 rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
178 return os.path.join(*rel_list)
181 def _runtest(fname, f):
182 mod = inspect.getmodule(f)
183 relpath = _relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
185 print 'Testing "%s" in %s:' % (fname, relpath)
188 _run_in_chdir(os.path.split(mod.__file__)[0], f)
189 except Exception as e:
191 print traceback.format_exc()
192 tb = sys.exc_info()[2]
193 wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
196 def _run_registered_tests():
197 import wvtest as _wvtestmod
198 while _wvtestmod._registered:
199 t = _wvtestmod._registered.pop(0)
200 _runtest(t.func_name, t)
204 def wvtest_main(extra_testfiles=[]):
205 import wvtest as _wvtestmod
206 _run_registered_tests()
207 for modname in extra_testfiles:
208 if not os.path.exists(modname):
209 print 'Skipping: %s' % modname
211 if modname.endswith('.py'):
212 modname = modname[:-3]
213 print 'Importing: %s' % modname
214 path, mod = os.path.split(os.path.abspath(modname))
215 nicename = modname.replace(os.path.sep, '.')
216 while nicename.startswith('.'):
217 nicename = modname[1:]
218 _run_in_chdir(path, __import__, nicename, None, None, [])
219 _run_registered_tests()
221 print 'WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
225 if __name__ == '__main__':
226 import wvtest as _wvtestmod
227 sys.modules['wvtest'] = _wvtestmod
228 sys.modules['wvtest.wvtest'] = _wvtestmod
230 wvtest_main(sys.argv[1:])