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.
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()
24 __all__
= ['TestCase', 'XFail', 'Skip']
27 class SVNTestStatusCodeError(Exception):
28 'Test driver returned a status code.'
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
__
47 self
.text
= ['PASS: ', 'FAIL: ', 'SKIP: ', '']
48 assert type(self
.func
) is type(lambda x
: 0)
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
):
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
)
72 def _check_name(self
):
73 name
= self
.pred
.func
.__doc
__
75 print 'WARNING: Test docstring exceeds 50 characters'
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'
82 return self
.pred
.func
.func_code
85 print " %2d %-5s %s" % (self
.index
,
86 self
.pred
.list_mode(),
87 self
.pred
.func
.__doc
__)
90 def _print_name(self
):
91 print os
.path
.basename(sys
.argv
[0]), str(self
.index
) + ":", \
92 self
.pred
.func
.__doc
__
98 print self
.pred
.skip_text(),
101 rc
= apply(self
.pred
.func
, args
)
104 raise SVNTestStatusCodeError
105 except SVNTestStatusCodeError
, ex
:
106 print "STYLE ERROR in",
110 except svntest
.Failure
, ex
:
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
:
119 print 'EXCEPTION: %s: %s' % (ex
.__class
__.__name
__, ex_args
)
121 print 'EXCEPTION:', ex
.__class
__.__name
__
122 except KeyboardInterrupt:
125 except SystemExit, ex
:
126 print 'EXCEPTION: SystemExit(%d), skipping cleanup' % ex
.code
127 print ex
.code
and 'FAIL: ' or 'PASS: ',
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
)
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.
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
)
162 self
.text
[3] = 'SKIP'