Plot graphs with cairo - it is faster and nicer
[can-benchmark.git] / gw-tests / genhtml / wvtest.py
1 #!/usr/bin/env python
2 import traceback
3 import os
4 import re
5 import sys
6
7 if __name__ != "__main__":   # we're imported as a module
8     _registered = []
9     _tests = 0
10     _fails = 0
11
12     def wvtest(func):
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.
17         """
18         _registered.append(func)
19         return func
20
21
22     def _result(msg, tb, code):
23         global _tests, _fails
24         _tests += 1
25         if code != 'ok':
26             _fails += 1
27         (filename, line, func, text) = tb
28         filename = os.path.basename(filename)
29         msg = re.sub(r'\s+', ' ', str(msg))
30         sys.stderr.flush()
31         print '! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
32                               code)
33         sys.stdout.flush()
34
35
36     def _check(cond, msg = 'unknown', tb = None):
37         if tb == None: tb = traceback.extract_stack()[-3]
38         if cond:
39             _result(msg, tb, 'ok')
40         else:
41             _result(msg, tb, 'FAILED')
42         return cond
43
44
45     def _code():
46         (filename, line, func, text) = traceback.extract_stack()[-3]
47         text = re.sub(r'^\w+\((.*)\)(\s*#.*)?$', r'\1', text);
48         return text
49
50
51     def WVPASS(cond = True):
52         ''' Counts a test failure unless cond is true. '''
53         return _check(cond, _code())
54
55     def WVFAIL(cond = True):
56         ''' Counts a test failure  unless cond is false. '''
57         return _check(not cond, 'NOT(%s)' % _code())
58
59     def WVPASSEQ(a, b):
60         ''' Counts a test failure unless a == b. '''
61         return _check(a == b, '%s == %s' % (repr(a), repr(b)))
62
63     def WVPASSNE(a, b):
64         ''' Counts a test failure unless a != b. '''
65         return _check(a != b, '%s != %s' % (repr(a), repr(b)))
66
67     def WVPASSLT(a, b):
68         ''' Counts a test failure unless a < b. '''
69         return _check(a < b, '%s < %s' % (repr(a), repr(b)))
70
71     def WVPASSLE(a, b):
72         ''' Counts a test failure unless a <= b. '''
73         return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
74
75     def WVPASSGT(a, b):
76         ''' Counts a test failure unless a > b. '''
77         return _check(a > b, '%s > %s' % (repr(a), repr(b)))
78
79     def WVPASSGE(a, b):
80         ''' Counts a test failure unless a >= b. '''
81         return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
82
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.
88         '''
89         try:
90             func(*args, **kwargs)
91         except etype, e:
92             return _check(True, 'EXCEPT(%s)' % _code())
93         except:
94             _check(False, 'EXCEPT(%s)' % _code())
95             raise
96         else:
97             return _check(False, 'EXCEPT(%s)' % _code())
98
99 else:  # we're the main program
100     # NOTE
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.
113     #
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.
116     import wvtest
117
118     def _runtest(modname, fname, f):
119         print
120         print 'Testing "%s" in %s.py:' % (fname, modname)
121         sys.stdout.flush()
122         try:
123             f()
124         except Exception, e:
125             print
126             print traceback.format_exc()
127             tb = sys.exc_info()[2]
128             wvtest._result(e, traceback.extract_tb(tb)[1],
129                            'EXCEPTION')
130
131     # main code
132     for modname in sys.argv[1:]:
133         if not os.path.exists(modname):
134             print 'Skipping: %s' % modname
135             continue
136         if modname.endswith('.py'):
137             modname = modname[:-3]
138         print 'Importing: %s' % modname
139         wvtest._registered = []
140         oldwd = os.getcwd()
141         oldpath = sys.path
142         try:
143             modpath = os.path.abspath(modname).split('/')[:-1]
144             os.chdir('/'.join(modpath))
145             sys.path += ['/'.join(modpath),
146                          '/'.join(modpath[:-1])]
147             mod = __import__(modname.replace('/', '.'), None, None, [])
148             for t in wvtest._registered:
149                 _runtest(modname, t.func_name, t)
150                 print
151         finally:
152             os.chdir(oldwd)
153             sys.path = oldpath
154
155     print
156     print 'WvTest: %d tests, %d failures.' % (wvtest._tests, wvtest._fails)