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
21 _start_dir = os.getcwd()
24 # Why do we do we need the "!= main" check? Because if you run
25 # wvtest.py as a main program and it imports your test files, then
26 # those test files will try to import the wvtest module recursively.
27 # That actually *works* fine, because we don't run this main program
28 # when we're imported as a module. But you end up with two separate
29 # wvtest modules, the one that gets imported, and the one that's the
30 # main program. Each of them would have duplicated global variables
31 # (most importantly, wvtest._registered), and so screwy things could
32 # happen. Thus, we make the main program module *totally* different
33 # from the imported module. Then we import wvtest (the module) into
34 # wvtest (the main program) here and make sure to refer to the right
35 # versions of global variables.
37 # All this is done just so that wvtest.py can be a single file that's
38 # easy to import into your own applications.
39 if __name__ != '__main__': # we're imported as a module
45 """ Use this decorator (@wvtest) in front of any function you want to
46 run as part of the unit test suite. Then run:
47 python wvtest.py path/to/yourtest.py [other test.py files...]
48 to run all the @wvtest functions in the given file(s).
50 _registered.append(func)
54 def _result(msg, tb, code):
59 (filename, line, func, text) = tb
60 filename = os.path.basename(filename)
61 msg = re.sub(r'\s+', ' ', str(msg))
63 print '! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
69 # Without the chdir, the source text lookup may fail
73 return traceback.extract_stack()[-4]
78 def _check(cond, msg = 'unknown', tb = None):
79 if tb == None: tb = _caller_stack()
81 _result(msg, tb, 'ok')
83 _result(msg, tb, 'FAILED')
86 _code_rx = re.compile(r'^\w+\((.*)\)(\s*#.*)?$')
88 text = _caller_stack()[3]
89 return _code_rx.sub(r'\1', text)
92 ''' Issues a notification. '''
93 return _result(message, _caller_stack(), 'ok')
95 def WVPASS(cond = True):
96 ''' Counts a test failure unless cond is true. '''
97 return _check(cond, _code())
99 def WVFAIL(cond = True):
100 ''' Counts a test failure unless cond is false. '''
101 return _check(not cond, 'NOT(%s)' % _code())
104 ''' Counts a test failure unless a == b. '''
105 return _check(a == b, '%s == %s' % (repr(a), repr(b)))
108 ''' Counts a test failure unless a != b. '''
109 return _check(a != b, '%s != %s' % (repr(a), repr(b)))
112 ''' Counts a test failure unless a < b. '''
113 return _check(a < b, '%s < %s' % (repr(a), repr(b)))
116 ''' Counts a test failure unless a <= b. '''
117 return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
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)))
127 def WVEXCEPT(etype, func, *args, **kwargs):
128 ''' Counts a test failure unless func throws an 'etype' exception.
129 You have to spell out the function name and arguments, rather than
130 calling the function yourself, so that WVEXCEPT can run before
131 your test code throws an exception.
134 func(*args, **kwargs)
136 return _check(True, 'EXCEPT(%s)' % _code())
138 _check(False, 'EXCEPT(%s)' % _code())
141 return _check(False, 'EXCEPT(%s)' % _code())
143 def wvfailure_count():
146 def _check_unfinished():
148 for func in _registered:
149 print 'WARNING: not run: %r' % (func,)
150 WVFAIL('wvtest_main() not called')
154 atexit.register(_check_unfinished)
157 def _run_in_chdir(path, func, *args, **kwargs):
162 sys.path += [path, os.path.split(path)[0]]
163 return func(*args, **kwargs)
169 if sys.version_info >= (2,6,0):
170 _relpath = os.path.relpath;
172 # Implementation for Python 2.5, taken from CPython (tag v2.6,
173 # file Lib/posixpath.py, hg-commit 95fff5a6a276). Update
174 # ./LICENSE When this code is eventually removed.
175 def _relpath(path, start=os.path.curdir):
177 raise ValueError("no path specified")
179 start_list = os.path.abspath(start).split(os.path.sep)
180 path_list = os.path.abspath(path).split(os.path.sep)
182 # Work out how much of the filepath is shared by start and path.
183 i = len(os.path.commonprefix([start_list, path_list]))
185 rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
188 return os.path.join(*rel_list)
191 def _runtest(fname, f):
192 mod = inspect.getmodule(f)
193 relpath = _relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
195 print 'Testing "%s" in %s:' % (fname, relpath)
198 _run_in_chdir(os.path.split(mod.__file__)[0], f)
199 except Exception as e:
201 print traceback.format_exc()
202 tb = sys.exc_info()[2]
203 wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
206 def _run_registered_tests():
207 import wvtest as _wvtestmod
208 while _wvtestmod._registered:
209 t = _wvtestmod._registered.pop(0)
210 _runtest(t.func_name, t)
214 def wvtest_main(extra_testfiles=tuple()):
215 import wvtest as _wvtestmod
216 _run_registered_tests()
217 for modname in extra_testfiles:
218 if not os.path.exists(modname):
219 print 'Skipping: %s' % modname
221 if modname.endswith('.py'):
222 modname = modname[:-3]
223 print 'Importing: %s' % modname
224 path, mod = os.path.split(os.path.abspath(modname))
225 nicename = modname.replace(os.path.sep, '.')
226 while nicename.startswith('.'):
227 nicename = modname[1:]
228 _run_in_chdir(path, __import__, nicename, None, None, [])
229 _run_registered_tests()
231 print 'WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
235 if __name__ == '__main__':
236 import wvtest as _wvtestmod
237 sys.modules['wvtest'] = _wvtestmod
238 sys.modules['wvtest.wvtest'] = _wvtestmod
240 wvtest_main(sys.argv[1:])