7 if __name__
!= "__main__": # we're imported as a module
13 """ Use this decorator (@wvtest) in front of any function you want to run
14 as part of the unit test suite. Then run:
15 python wvtest.py path/to/yourtest.py
16 to run all the @wvtest functions in that file.
18 _registered
.append(func
)
22 def _result(msg
, tb
, code
):
27 (filename
, line
, func
, text
) = tb
28 filename
= os
.path
.basename(filename
)
29 msg
= re
.sub(r
'\s+', ' ', str(msg
))
31 print '! %-70s %s' % ('%s:%-4d %s' % (filename
, line
, msg
),
36 def _check(cond
, msg
= 'unknown', tb
= None):
37 if tb
== None: tb
= traceback
.extract_stack()[-3]
39 _result(msg
, tb
, 'ok')
41 _result(msg
, tb
, 'FAILED')
46 (filename
, line
, func
, text
) = traceback
.extract_stack()[-3]
47 text
= re
.sub(r
'^\w+\((.*)\)(\s*#.*)?$', r
'\1', text
);
51 def WVPASS(cond
= True):
52 ''' Counts a test failure unless cond is true. '''
53 return _check(cond
, _code())
55 def WVFAIL(cond
= True):
56 ''' Counts a test failure unless cond is false. '''
57 return _check(not cond
, 'NOT(%s)' % _code())
60 ''' Counts a test failure unless a == b. '''
61 return _check(a
== b
, '%s == %s' % (repr(a
), repr(b
)))
64 ''' Counts a test failure unless a != b. '''
65 return _check(a
!= b
, '%s != %s' % (repr(a
), repr(b
)))
68 ''' Counts a test failure unless a < b. '''
69 return _check(a
< b
, '%s < %s' % (repr(a
), repr(b
)))
72 ''' Counts a test failure unless a <= b. '''
73 return _check(a
<= b
, '%s <= %s' % (repr(a
), repr(b
)))
76 ''' Counts a test failure unless a > b. '''
77 return _check(a
> b
, '%s > %s' % (repr(a
), repr(b
)))
80 ''' Counts a test failure unless a >= b. '''
81 return _check(a
>= b
, '%s >= %s' % (repr(a
), repr(b
)))
83 def WVEXCEPT(etype
, func
, *args
, **kwargs
):
84 ''' Counts a test failure unless func throws an 'etype' exception.
85 You have to spell out the function name and arguments, rather than
86 calling the function yourself, so that WVEXCEPT can run before
87 your test code throws an exception.
92 return _check(True, 'EXCEPT(%s)' % _code())
94 _check(False, 'EXCEPT(%s)' % _code())
97 return _check(False, 'EXCEPT(%s)' % _code())
99 else: # we're the main program
101 # Why do we do this in such a convoluted way? Because if you run
102 # wvtest.py as a main program and it imports your test files, then
103 # those test files will try to import the wvtest module recursively.
104 # That actually *works* fine, because we don't run this main program
105 # when we're imported as a module. But you end up with two separate
106 # wvtest modules, the one that gets imported, and the one that's the
107 # main program. Each of them would have duplicated global variables
108 # (most importantly, wvtest._registered), and so screwy things could
109 # happen. Thus, we make the main program module *totally* different
110 # from the imported module. Then we import wvtest (the module) into
111 # wvtest (the main program) here and make sure to refer to the right
112 # versions of global variables.
114 # All this is done just so that wvtest.py can be a single file that's
115 # easy to import into your own applications.
118 def _runtest(modname
, fname
, f
):
120 print 'Testing "%s" in %s.py:' % (fname
, modname
)
126 print traceback
.format_exc()
127 tb
= sys
.exc_info()[2]
128 wvtest
._result
(e
, traceback
.extract_tb(tb
)[1], 'EXCEPTION')
131 for modname
in sys
.argv
[1:]:
132 if not os
.path
.exists(modname
):
133 print 'Skipping: %s' % modname
135 if modname
.endswith('.py'):
136 modname
= modname
[:-3]
137 print 'Importing: %s' % modname
138 wvtest
._registered
= []
142 path
, mod
= os
.path
.split(os
.path
.abspath(modname
))
144 sys
.path
+= [path
, os
.path
.split(path
)[0]]
145 mod
= __import__(modname
.replace(os
.path
.sep
, '.'), None, None, [])
146 for t
in wvtest
._registered
:
147 _runtest(modname
, t
.func_name
, t
)
154 print 'WvTest: %d tests, %d failures.' % (wvtest
._tests
, wvtest
._fails
)