]> arthur.barton.de Git - bup.git/blob - wvtest.py
Don't even test for Linux xattrs if platform.system() doesn't include Linux.
[bup.git] / wvtest.py
1 #!/usr/bin/env python
2 #
3 # WvTest:
4 #   Copyright (C)2007-2012 Versabanq Innovations Inc. and contributors.
5 #       Licensed under the GNU Library General Public License, version 2.
6 #       See the included file named LICENSE for license information.
7 #       You can get wvtest from: http://github.com/apenwarr/wvtest
8 #
9 import atexit
10 import inspect
11 import os
12 import re
13 import sys
14 import traceback
15
16 # NOTE
17 # Why do we do we need the "!= main" check?  Because if you run
18 # wvtest.py as a main program and it imports your test files, then
19 # those test files will try to import the wvtest module recursively.
20 # That actually *works* fine, because we don't run this main program
21 # when we're imported as a module.  But you end up with two separate
22 # wvtest modules, the one that gets imported, and the one that's the
23 # main program.  Each of them would have duplicated global variables
24 # (most importantly, wvtest._registered), and so screwy things could
25 # happen.  Thus, we make the main program module *totally* different
26 # from the imported module.  Then we import wvtest (the module) into
27 # wvtest (the main program) here and make sure to refer to the right
28 # versions of global variables.
29 #
30 # All this is done just so that wvtest.py can be a single file that's
31 # easy to import into your own applications.
32 if __name__ != '__main__':   # we're imported as a module
33     _registered = []
34     _tests = 0
35     _fails = 0
36
37     def wvtest(func):
38         """ Use this decorator (@wvtest) in front of any function you want to
39             run as part of the unit test suite.  Then run:
40                 python wvtest.py path/to/yourtest.py [other test.py files...]
41             to run all the @wvtest functions in the given file(s).
42         """
43         _registered.append(func)
44         return func
45
46
47     def _result(msg, tb, code):
48         global _tests, _fails
49         _tests += 1
50         if code != 'ok':
51             _fails += 1
52         (filename, line, func, text) = tb
53         filename = os.path.basename(filename)
54         msg = re.sub(r'\s+', ' ', str(msg))
55         sys.stderr.flush()
56         print '! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
57                               code)
58         sys.stdout.flush()
59
60
61     def _check(cond, msg = 'unknown', tb = None):
62         if tb == None: tb = traceback.extract_stack()[-3]
63         if cond:
64             _result(msg, tb, 'ok')
65         else:
66             _result(msg, tb, 'FAILED')
67         return cond
68
69
70     def _code():
71         (filename, line, func, text) = traceback.extract_stack()[-3]
72         text = re.sub(r'^\w+\((.*)\)(\s*#.*)?$', r'\1', text);
73         return text
74
75
76     def WVMSG(message):
77         ''' Issues a notification. '''
78         return _result(message, traceback.extract_stack()[-3], 'ok')
79
80     def WVPASS(cond = True):
81         ''' Counts a test failure unless cond is true. '''
82         return _check(cond, _code())
83
84     def WVFAIL(cond = True):
85         ''' Counts a test failure  unless cond is false. '''
86         return _check(not cond, 'NOT(%s)' % _code())
87
88     def WVPASSEQ(a, b):
89         ''' Counts a test failure unless a == b. '''
90         return _check(a == b, '%s == %s' % (repr(a), repr(b)))
91
92     def WVPASSNE(a, b):
93         ''' Counts a test failure unless a != b. '''
94         return _check(a != b, '%s != %s' % (repr(a), repr(b)))
95
96     def WVPASSLT(a, b):
97         ''' Counts a test failure unless a < b. '''
98         return _check(a < b, '%s < %s' % (repr(a), repr(b)))
99
100     def WVPASSLE(a, b):
101         ''' Counts a test failure unless a <= b. '''
102         return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
103
104     def WVPASSGT(a, b):
105         ''' Counts a test failure unless a > b. '''
106         return _check(a > b, '%s > %s' % (repr(a), repr(b)))
107
108     def WVPASSGE(a, b):
109         ''' Counts a test failure unless a >= b. '''
110         return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
111
112     def WVEXCEPT(etype, func, *args, **kwargs):
113         ''' Counts a test failure unless func throws an 'etype' exception.
114             You have to spell out the function name and arguments, rather than
115             calling the function yourself, so that WVEXCEPT can run before
116             your test code throws an exception.
117         '''
118         try:
119             func(*args, **kwargs)
120         except etype, e:
121             return _check(True, 'EXCEPT(%s)' % _code())
122         except:
123             _check(False, 'EXCEPT(%s)' % _code())
124             raise
125         else:
126             return _check(False, 'EXCEPT(%s)' % _code())
127
128
129     def _check_unfinished():
130         if _registered:
131             for func in _registered:
132                 print 'WARNING: not run: %r' % (func,)
133             WVFAIL('wvtest_main() not called')
134         if _fails:
135             sys.exit(1)
136
137     atexit.register(_check_unfinished)
138
139
140 def _run_in_chdir(path, func, *args, **kwargs):
141     oldwd = os.getcwd()
142     oldpath = sys.path
143     try:
144         os.chdir(path)
145         sys.path += [path, os.path.split(path)[0]]
146         return func(*args, **kwargs)
147     finally:
148         os.chdir(oldwd)
149         sys.path = oldpath
150
151
152 def _runtest(fname, f):
153     mod = inspect.getmodule(f)
154     relpath = os.path.relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
155     print
156     print 'Testing "%s" in %s:' % (fname, relpath)
157     sys.stdout.flush()
158     try:
159         _run_in_chdir(os.path.split(mod.__file__)[0], f)
160     except Exception, e:
161         print
162         print traceback.format_exc()
163         tb = sys.exc_info()[2]
164         wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
165
166
167 def _run_registered_tests():
168     import wvtest as _wvtestmod
169     while _wvtestmod._registered:
170         t = _wvtestmod._registered.pop(0)
171         _runtest(t.func_name, t)
172         print
173
174
175 def wvtest_main(extra_testfiles=[]):
176     import wvtest as _wvtestmod
177     _run_registered_tests()
178     for modname in extra_testfiles:
179         if not os.path.exists(modname):
180             print 'Skipping: %s' % modname
181             continue
182         if modname.endswith('.py'):
183             modname = modname[:-3]
184         print 'Importing: %s' % modname
185         path, mod = os.path.split(os.path.abspath(modname))
186         nicename = modname.replace(os.path.sep, '.')
187         while nicename.startswith('.'):
188             nicename = modname[1:]
189         _run_in_chdir(path, __import__, nicename, None, None, [])
190         _run_registered_tests()
191     print
192     print 'WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
193                                               _wvtestmod._fails)
194
195
196 if __name__ == '__main__':
197     import wvtest as _wvtestmod
198     sys.modules['wvtest'] = _wvtestmod
199     sys.modules['wvtest.wvtest'] = _wvtestmod
200     wvtest_main(sys.argv[1:])