test_support.py revision 0a07639779beb496f3d68021fef28e77dbe13af9
1"""Supporting definitions for the Python regression test.""" 2 3import sys 4 5class Error(Exception): 6 """Base class for regression test exceptions.""" 7 8class TestFailed(Error): 9 """Test failed.""" 10 11class TestSkipped(Error): 12 """Test skipped. 13 14 This can be raised to indicate that a test was deliberatly 15 skipped, but not because a feature wasn't available. For 16 example, if some resource can't be used, such as the network 17 appears to be unavailable, this should be raised instead of 18 TestFailed. 19 """ 20 21verbose = 1 # Flag set to 0 by regrtest.py 22use_resources = None # Flag set to [] by regrtest.py 23 24# _output_comparison controls whether regrtest will try to compare stdout 25# with an expected-output file. For straight regrtests, it should. 26# The doctest driver resets this flag by calling deny_output_comparison(). 27# Note that this control is in addition to verbose mode: output will be 28# compared if and only if _output_comparison is true and verbose mode is 29# not in effect. 30_output_comparison = 1 31 32def deny_output_comparison(): 33 global _output_comparison 34 _output_comparison = 0 35 sys.stdout = sys.save_stdout 36 37# regrtest's interface to _output_comparison. 38def output_comparison_denied(): 39 global _output_comparison 40 denied = not _output_comparison 41 _output_comparison = 1 42 return denied 43 44def unload(name): 45 try: 46 del sys.modules[name] 47 except KeyError: 48 pass 49 50def forget(modname): 51 unload(modname) 52 import os 53 for dirname in sys.path: 54 try: 55 os.unlink(os.path.join(dirname, modname + '.pyc')) 56 except os.error: 57 pass 58 59def requires(resource, msg=None): 60 if use_resources is not None and resource not in use_resources: 61 if msg is None: 62 msg = "Use of the `%s' resource not enabled" % resource 63 raise TestSkipped(msg) 64 65FUZZ = 1e-6 66 67def fcmp(x, y): # fuzzy comparison function 68 if type(x) == type(0.0) or type(y) == type(0.0): 69 try: 70 x, y = coerce(x, y) 71 fuzz = (abs(x) + abs(y)) * FUZZ 72 if abs(x-y) <= fuzz: 73 return 0 74 except: 75 pass 76 elif type(x) == type(y) and type(x) in (type(()), type([])): 77 for i in range(min(len(x), len(y))): 78 outcome = fcmp(x[i], y[i]) 79 if outcome != 0: 80 return outcome 81 return cmp(len(x), len(y)) 82 return cmp(x, y) 83 84try: 85 unicode 86 have_unicode = 1 87except NameError: 88 have_unicode = 0 89 90import os 91# Filename used for testing 92if os.name == 'java': 93 # Jython disallows @ in module names 94 TESTFN = '$test' 95elif os.name != 'riscos': 96 TESTFN = '@test' 97 # Unicode name only used if TEST_FN_ENCODING exists for the platform. 98 if have_unicode: 99 TESTFN_UNICODE=unicode("@test-\xe0\xf2", "latin-1") # 2 latin characters. 100 if os.name=="nt": 101 TESTFN_ENCODING="mbcs" 102else: 103 TESTFN = 'test' 104del os 105 106from os import unlink 107 108def findfile(file, here=__file__): 109 import os 110 if os.path.isabs(file): 111 return file 112 path = sys.path 113 path = [os.path.dirname(here)] + path 114 for dn in path: 115 fn = os.path.join(dn, file) 116 if os.path.exists(fn): return fn 117 return file 118 119def verify(condition, reason='test failed'): 120 """Verify that condition is true. If not, raise TestFailed. 121 122 The optional argument reason can be given to provide 123 a better error text. 124 """ 125 126 if not condition: 127 raise TestFailed(reason) 128 129def sortdict(dict): 130 "Like repr(dict), but in sorted order." 131 items = dict.items() 132 items.sort() 133 reprpairs = ["%r: %r" % pair for pair in items] 134 withcommas = ", ".join(reprpairs) 135 return "{%s}" % withcommas 136 137def check_syntax(statement): 138 try: 139 compile(statement, '<string>', 'exec') 140 except SyntaxError: 141 pass 142 else: 143 print 'Missing SyntaxError: "%s"' % statement 144 145 146 147#======================================================================= 148# Preliminary PyUNIT integration. 149 150import unittest 151 152 153class BasicTestRunner: 154 def run(self, test): 155 result = unittest.TestResult() 156 test(result) 157 return result 158 159 160def run_suite(suite): 161 """Run tests from a unittest.TestSuite-derived class.""" 162 if verbose: 163 runner = unittest.TextTestRunner(sys.stdout, verbosity=2) 164 else: 165 runner = BasicTestRunner() 166 167 result = runner.run(suite) 168 if not result.wasSuccessful(): 169 if len(result.errors) == 1 and not result.failures: 170 err = result.errors[0][1] 171 elif len(result.failures) == 1 and not result.errors: 172 err = result.failures[0][1] 173 else: 174 raise TestFailed("errors occurred in %s.%s" 175 % (testclass.__module__, testclass.__name__)) 176 raise TestFailed(err) 177 178 179def run_unittest(testclass): 180 """Run tests from a unittest.TestCase-derived class.""" 181 run_suite(unittest.makeSuite(testclass)) 182 183 184#======================================================================= 185# doctest driver. 186 187def run_doctest(module, verbosity=None): 188 """Run doctest on the given module. 189 190 If optional argument verbosity is not specified (or is None), pass 191 test_support's belief about verbosity on to doctest. Else doctest's 192 usual behavior is used (it searches sys.argv for -v). 193 """ 194 195 import doctest 196 197 if verbosity is None: 198 verbosity = verbose 199 else: 200 verbosity = None 201 202 deny_output_comparison() 203 f, t = doctest.testmod(module, verbose=verbosity) 204 if f: 205 raise TestFailed("%d of %d doctests failed" % (f, t)) 206