Speed up the regression tests.
[svnrdump.git] / svntest / testcase.py
blobabb82f4f74e29f8cfb753e6a9f026b62264497cd
1 #!/usr/bin/env python
3 # testcase.py: Control of test case execution.
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
7 #
8 # ====================================================================
9 # Copyright (c) 2000-2003 CollabNet. All rights reserved.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://subversion.tigris.org/license-1.html.
14 # If newer versions of this license are posted there, you may use a
15 # newer version instead, at your option.
17 ######################################################################
19 import os, sys, string
20 import traceback # for print_exc()
22 import svntest
24 __all__ = ['TestCase', 'XFail', 'Skip']
27 class SVNTestStatusCodeError(Exception):
28 'Test driver returned a status code.'
29 pass
32 class _Predicate:
33 """A general-purpose predicate that encapsulates a test case (function),
34 a condition for its execution and a set of display properties for test
35 lists and test log output."""
37 def __init__(self, func):
38 if isinstance(func, _Predicate):
39 # Whee, this is better than blessing objects in Perl!
40 # For the unenlightened: What we're doing here is adopting the
41 # identity *and class* of 'func'
42 self.__dict__ = func.__dict__
43 self.__class__ = func.__class__
44 else:
45 self.func = func
46 self.cond = 0
47 self.text = ['PASS: ', 'FAIL: ', 'SKIP: ', '']
48 assert type(self.func) is type(lambda x: 0)
50 def list_mode(self):
51 return self.text[3]
53 def skip_text(self):
54 return self.text[2]
56 def run_text(self, error):
57 if error: return self.text[1]
58 else: return self.text[0]
60 def convert_error(self, error):
61 return error
64 class TestCase:
65 """Encapsulate a single test case (predicate), including logic for
66 runing the test and test list output."""
68 def __init__(self, func, index):
69 self.pred = _Predicate(func)
70 self.index = index
72 def _check_name(self):
73 name = self.pred.func.__doc__
74 if len(name) > 50:
75 print 'WARNING: Test docstring exceeds 50 characters'
76 if name[-1] == '.':
77 print 'WARNING: Test docstring ends in a period (.)'
78 if not string.lower(name[0]) == name[0]:
79 print 'WARNING: Test docstring is capitalized'
81 def func_code(self):
82 return self.pred.func.func_code
84 def list(self):
85 print " %2d %-5s %s" % (self.index,
86 self.pred.list_mode(),
87 self.pred.func.__doc__)
88 self._check_name()
90 def _print_name(self):
91 print os.path.basename(sys.argv[0]), str(self.index) + ":", \
92 self.pred.func.__doc__
93 self._check_name()
95 def run(self, args):
96 error = 0
97 if self.pred.cond:
98 print self.pred.skip_text(),
99 else:
100 try:
101 rc = apply(self.pred.func, args)
102 if rc is not None:
103 error = rc
104 raise SVNTestStatusCodeError
105 except SVNTestStatusCodeError, ex:
106 print "STYLE ERROR in",
107 self._print_name()
108 print ex.__doc__
109 sys.exit(255)
110 except svntest.Failure, ex:
111 error = 1
112 # We captured Failure and its subclasses. We don't want to print
113 # anything for plain old Failure since that just indicates test
114 # failure, rather than relevant information. However, if there
115 # *is* information in the exception's arguments, then print it.
116 if ex.__class__ != svntest.Failure or ex.args:
117 ex_args = str(ex)
118 if ex_args:
119 print 'EXCEPTION: %s: %s' % (ex.__class__.__name__, ex_args)
120 else:
121 print 'EXCEPTION:', ex.__class__.__name__
122 except KeyboardInterrupt:
123 print 'Interrupted'
124 sys.exit(0)
125 except SystemExit, ex:
126 print 'EXCEPTION: SystemExit(%d), skipping cleanup' % ex.code
127 print ex.code and 'FAIL: ' or 'PASS: ',
128 self._print_name()
129 raise
130 except:
131 error = 1
132 print 'UNEXPECTED EXCEPTION:'
133 traceback.print_exc(file=sys.stdout)
134 print self.pred.run_text(error),
135 error = self.pred.convert_error(error)
136 self._print_name()
137 sys.stdout.flush()
138 return error
141 class XFail(_Predicate):
142 "A test that is expected to fail."
144 def __init__(self, func):
145 _Predicate.__init__(self, func)
146 self.text[0] = 'XPASS:'
147 self.text[1] = 'XFAIL:'
148 if self.text[3] == '':
149 self.text[3] = 'XFAIL'
150 def convert_error(self, error):
151 # Conditions are reversed here: a failure expected, therefore it
152 # isn't an error; a pass is an error.
153 return not error
155 class Skip(_Predicate):
156 "A test that will be skipped when a condition is true."
158 def __init__(self, func, cond):
159 _Predicate.__init__(self, func)
160 self.cond = cond
161 if self.cond:
162 self.text[3] = 'SKIP'
165 ### End of file.