blob: bec1a0f401f51b401b766f0a93528e0f1b9c97fc [file] [log] [blame]
Brett Cannonf1cfb622003-05-04 21:15:27 +00001"""Supporting definitions for the Python regression tests."""
Guido van Rossum3bead091992-01-27 17:00:37 +00002
Barry Warsaw408b6d32002-07-30 23:27:12 +00003if __name__ != 'test.test_support':
4 raise ImportError, 'test_support must be imported from the test package'
5
Fred Drakecd1b1dd2001-03-21 18:26:33 +00006import sys
7
Fred Drake1790dd42000-07-24 06:55:00 +00008class Error(Exception):
Fred Drake004d5e62000-10-23 17:22:08 +00009 """Base class for regression test exceptions."""
Fred Drake1790dd42000-07-24 06:55:00 +000010
11class TestFailed(Error):
Fred Drake004d5e62000-10-23 17:22:08 +000012 """Test failed."""
Fred Drake1790dd42000-07-24 06:55:00 +000013
14class TestSkipped(Error):
Fred Drake004d5e62000-10-23 17:22:08 +000015 """Test skipped.
Fred Drake1790dd42000-07-24 06:55:00 +000016
Fred Drake004d5e62000-10-23 17:22:08 +000017 This can be raised to indicate that a test was deliberatly
18 skipped, but not because a feature wasn't available. For
19 example, if some resource can't be used, such as the network
20 appears to be unavailable, this should be raised instead of
21 TestFailed.
Fred Drake004d5e62000-10-23 17:22:08 +000022 """
Fred Drake1790dd42000-07-24 06:55:00 +000023
Fred Drake9a0db072003-02-03 15:19:30 +000024class ResourceDenied(TestSkipped):
25 """Test skipped because it requested a disallowed resource.
26
27 This is raised when a test calls requires() for a resource that
28 has not be enabled. It is used to distinguish between expected
29 and unexpected skips.
30 """
31
Barry Warsawc0fb6052001-08-20 22:29:23 +000032verbose = 1 # Flag set to 0 by regrtest.py
Guido van Rossumfe3f6962001-09-06 16:09:41 +000033use_resources = None # Flag set to [] by regrtest.py
Guido van Rossum531661c1996-12-20 02:58:22 +000034
Tim Peters8dee8092001-09-25 20:05:11 +000035# _original_stdout is meant to hold stdout at the time regrtest began.
36# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever.
37# The point is to have some flavor of stdout the user can actually see.
38_original_stdout = None
39def record_original_stdout(stdout):
40 global _original_stdout
41 _original_stdout = stdout
42
43def get_original_stdout():
44 return _original_stdout or sys.stdout
45
Guido van Rossum3bead091992-01-27 17:00:37 +000046def unload(name):
Fred Drake004d5e62000-10-23 17:22:08 +000047 try:
48 del sys.modules[name]
49 except KeyError:
50 pass
Guido van Rossum3bead091992-01-27 17:00:37 +000051
52def forget(modname):
Brett Cannonf1cfb622003-05-04 21:15:27 +000053 '''"Forget" a module was ever imported by removing it from sys.modules and
54 deleting any .pyc and .pyo files.'''
Fred Drake004d5e62000-10-23 17:22:08 +000055 unload(modname)
Fred Drakecd1b1dd2001-03-21 18:26:33 +000056 import os
Fred Drake004d5e62000-10-23 17:22:08 +000057 for dirname in sys.path:
58 try:
Martin v. Löwisa94568a2003-05-10 07:36:56 +000059 os.unlink(os.path.join(dirname, modname + os.extsep + 'pyc'))
Fred Drake004d5e62000-10-23 17:22:08 +000060 except os.error:
61 pass
Brett Cannonf1cfb622003-05-04 21:15:27 +000062 # Deleting the .pyo file cannot be within the 'try' for the .pyc since
63 # the chance exists that there is no .pyc (and thus the 'try' statement
64 # is exited) but there is a .pyo file.
65 try:
Martin v. Löwisa94568a2003-05-10 07:36:56 +000066 os.unlink(os.path.join(dirname, modname + os.extsep + 'pyo'))
Brett Cannonf1cfb622003-05-04 21:15:27 +000067 except os.error:
68 pass
Guido van Rossum3bead091992-01-27 17:00:37 +000069
Tim Petersb4ee4eb2002-12-04 03:26:57 +000070def is_resource_enabled(resource):
Brett Cannonf1cfb622003-05-04 21:15:27 +000071 """Test whether a resource is enabled. Known resources are set by
72 regrtest.py."""
Tim Petersb4ee4eb2002-12-04 03:26:57 +000073 return use_resources is not None and resource in use_resources
74
Barry Warsawc0fb6052001-08-20 22:29:23 +000075def requires(resource, msg=None):
Brett Cannonf1cfb622003-05-04 21:15:27 +000076 """Raise ResourceDenied if the specified resource is not available.
77
78 If the caller's module is __main__ then automatically return True. The
79 possibility of False being returned occurs when regrtest.py is executing."""
Skip Montanarod839ecd2003-04-24 19:06:57 +000080 # see if the caller's module is __main__ - if so, treat as if
81 # the resource was set
82 if sys._getframe().f_back.f_globals.get("__name__") == "__main__":
83 return
Tim Petersb4ee4eb2002-12-04 03:26:57 +000084 if not is_resource_enabled(resource):
Barry Warsawc0fb6052001-08-20 22:29:23 +000085 if msg is None:
86 msg = "Use of the `%s' resource not enabled" % resource
Fred Drake9a0db072003-02-03 15:19:30 +000087 raise ResourceDenied(msg)
Barry Warsawc0fb6052001-08-20 22:29:23 +000088
Guido van Rossum35fb82a1993-01-26 13:04:43 +000089FUZZ = 1e-6
90
91def fcmp(x, y): # fuzzy comparison function
Fred Drake004d5e62000-10-23 17:22:08 +000092 if type(x) == type(0.0) or type(y) == type(0.0):
93 try:
94 x, y = coerce(x, y)
95 fuzz = (abs(x) + abs(y)) * FUZZ
96 if abs(x-y) <= fuzz:
97 return 0
98 except:
99 pass
100 elif type(x) == type(y) and type(x) in (type(()), type([])):
101 for i in range(min(len(x), len(y))):
102 outcome = fcmp(x[i], y[i])
Fred Drake132dce22000-12-12 23:11:42 +0000103 if outcome != 0:
Fred Drake004d5e62000-10-23 17:22:08 +0000104 return outcome
105 return cmp(len(x), len(y))
106 return cmp(x, y)
Guido van Rossum35fb82a1993-01-26 13:04:43 +0000107
Martin v. Löwis339d0f72001-08-17 18:39:25 +0000108try:
109 unicode
110 have_unicode = 1
111except NameError:
112 have_unicode = 0
113
Finn Bock57bc5fa2002-11-01 18:02:03 +0000114is_jython = sys.platform.startswith('java')
115
Guido van Rossuma8f7e592001-03-13 09:31:07 +0000116import os
Barry Warsaw559f6682001-03-23 18:04:02 +0000117# Filename used for testing
118if os.name == 'java':
119 # Jython disallows @ in module names
120 TESTFN = '$test'
Martin v. Löwisa94568a2003-05-10 07:36:56 +0000121elif os.name == 'riscos':
122 TESTFN = 'testfile'
123else:
Barry Warsaw559f6682001-03-23 18:04:02 +0000124 TESTFN = '@test'
Mark Hammondef8b6542001-05-13 08:04:26 +0000125 # Unicode name only used if TEST_FN_ENCODING exists for the platform.
Martin v. Löwis339d0f72001-08-17 18:39:25 +0000126 if have_unicode:
Mark Hammondb337dd92003-12-03 01:27:23 +0000127 # Assuming sys.getfilesystemencoding()!=sys.getdefaultencoding()
128 # TESTFN_UNICODE is a filename that can be encoded using the
129 # file system encoding, but *not* with the default (ascii) encoding
Martin v. Löwis2411a2d2002-11-09 19:57:26 +0000130 if isinstance('', unicode):
131 # python -U
132 # XXX perhaps unicode() should accept Unicode strings?
Tim Petersc6c5ece2003-12-04 05:39:43 +0000133 TESTFN_UNICODE = "@test-\xe0\xf2"
Martin v. Löwis2411a2d2002-11-09 19:57:26 +0000134 else:
Tim Petersc6c5ece2003-12-04 05:39:43 +0000135 # 2 latin characters.
136 TESTFN_UNICODE = unicode("@test-\xe0\xf2", "latin-1")
137 TESTFN_ENCODING = sys.getfilesystemencoding()
138 # TESTFN_UNICODE_UNENCODEABLE is a filename that should *not* be
Mark Hammondb337dd92003-12-03 01:27:23 +0000139 # able to be encoded by *either* the default or filesystem encoding.
Tim Petersc6c5ece2003-12-04 05:39:43 +0000140 # This test really only makes sense on Windows NT platforms
Mark Hammond2e8624c2003-12-03 22:16:47 +0000141 # which have special Unicode support in posixmodule.
Tim Petersc6c5ece2003-12-04 05:39:43 +0000142 if (not hasattr(sys, "getwindowsversion") or
143 sys.getwindowsversion()[3] < 2): # 0=win32s or 1=9x/ME
Tim Peters58eb11c2004-01-18 20:29:55 +0000144 TESTFN_UNICODE_UNENCODEABLE = None
Mark Hammondb337dd92003-12-03 01:27:23 +0000145 else:
Mark Hammond2e8624c2003-12-03 22:16:47 +0000146 # Japanese characters (I think - from bug 846133)
Martin v. Löwise2713be2005-03-08 15:03:08 +0000147 TESTFN_UNICODE_UNENCODEABLE = eval('u"@test-\u5171\u6709\u3055\u308c\u308b"')
Mark Hammond2e8624c2003-12-03 22:16:47 +0000148 try:
149 # XXX - Note - should be using TESTFN_ENCODING here - but for
Tim Petersc6c5ece2003-12-04 05:39:43 +0000150 # Windows, "mbcs" currently always operates as if in
Mark Hammond2e8624c2003-12-03 22:16:47 +0000151 # errors=ignore' mode - hence we get '?' characters rather than
152 # the exception. 'Latin1' operates as we expect - ie, fails.
153 # See [ 850997 ] mbcs encoding ignores errors
154 TESTFN_UNICODE_UNENCODEABLE.encode("Latin1")
155 except UnicodeEncodeError:
156 pass
157 else:
158 print \
159 'WARNING: The filename %r CAN be encoded by the filesystem. ' \
160 'Unicode filename tests may not be effective' \
161 % TESTFN_UNICODE_UNENCODEABLE
Neal Norwitz26a1eef2002-11-03 00:35:53 +0000162
163# Make sure we can write to TESTFN, try in /tmp if we can't
164fp = None
165try:
166 fp = open(TESTFN, 'w+')
167except IOError:
168 TMP_TESTFN = os.path.join('/tmp', TESTFN)
169 try:
170 fp = open(TMP_TESTFN, 'w+')
171 TESTFN = TMP_TESTFN
172 del TMP_TESTFN
173 except IOError:
Tim Peters3de75262002-11-09 05:26:15 +0000174 print ('WARNING: tests will fail, unable to write to: %s or %s' %
Neal Norwitz26a1eef2002-11-03 00:35:53 +0000175 (TESTFN, TMP_TESTFN))
176if fp is not None:
177 fp.close()
178 try:
179 os.unlink(TESTFN)
180 except:
181 pass
182del os, fp
Guido van Rossuma8f7e592001-03-13 09:31:07 +0000183
Guido van Rossum3bead091992-01-27 17:00:37 +0000184from os import unlink
Guido van Rossume26132c1998-04-23 20:13:30 +0000185
186def findfile(file, here=__file__):
Brett Cannonf1cfb622003-05-04 21:15:27 +0000187 """Try to find a file on sys.path and the working directory. If it is not
188 found the argument passed to the function is returned (this does not
189 necessarily signal failure; could still be the legitimate path)."""
Fred Drake004d5e62000-10-23 17:22:08 +0000190 import os
191 if os.path.isabs(file):
192 return file
Fred Drake004d5e62000-10-23 17:22:08 +0000193 path = sys.path
194 path = [os.path.dirname(here)] + path
195 for dn in path:
196 fn = os.path.join(dn, file)
197 if os.path.exists(fn): return fn
198 return file
Marc-André Lemburg36619082001-01-17 19:11:13 +0000199
200def verify(condition, reason='test failed'):
Guido van Rossuma1374e42001-01-19 19:01:56 +0000201 """Verify that condition is true. If not, raise TestFailed.
Marc-André Lemburg36619082001-01-17 19:11:13 +0000202
Skip Montanaroc955f892001-01-20 19:12:54 +0000203 The optional argument reason can be given to provide
Tim Peters983874d2001-01-19 05:59:21 +0000204 a better error text.
Tim Petersd2bf3b72001-01-18 02:22:22 +0000205 """
Tim Peters983874d2001-01-19 05:59:21 +0000206
Tim Petersd2bf3b72001-01-18 02:22:22 +0000207 if not condition:
Guido van Rossuma1374e42001-01-19 19:01:56 +0000208 raise TestFailed(reason)
Jeremy Hylton47793992001-02-19 15:35:26 +0000209
Tim Petersc2fe6182001-10-30 23:20:46 +0000210def vereq(a, b):
Tim Peters77902972001-12-29 17:34:57 +0000211 """Raise TestFailed if a == b is false.
212
213 This is better than verify(a == b) because, in case of failure, the
214 error message incorporates repr(a) and repr(b) so you can see the
215 inputs.
216
217 Note that "not (a == b)" isn't necessarily the same as "a != b"; the
218 former is tested.
219 """
220
Tim Petersc2fe6182001-10-30 23:20:46 +0000221 if not (a == b):
222 raise TestFailed, "%r == %r" % (a, b)
223
Tim Peters2f228e72001-05-13 00:19:31 +0000224def sortdict(dict):
225 "Like repr(dict), but in sorted order."
226 items = dict.items()
227 items.sort()
228 reprpairs = ["%r: %r" % pair for pair in items]
229 withcommas = ", ".join(reprpairs)
230 return "{%s}" % withcommas
231
Jeremy Hylton47793992001-02-19 15:35:26 +0000232def check_syntax(statement):
233 try:
234 compile(statement, '<string>', 'exec')
235 except SyntaxError:
236 pass
237 else:
238 print 'Missing SyntaxError: "%s"' % statement
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000239
Hye-Shik Changaaa2f1d2005-12-10 17:44:27 +0000240def open_urlresource(url):
241 import urllib, urlparse
242 import os.path
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000243
Hye-Shik Changaaa2f1d2005-12-10 17:44:27 +0000244 filename = urlparse.urlparse(url)[2].split('/')[-1] # '/': it's URL!
245
246 for path in [os.path.curdir, os.path.pardir]:
247 fn = os.path.join(path, filename)
248 if os.path.exists(fn):
249 return open(fn)
250
251 requires('urlfetch')
252 print >> get_original_stdout(), '\tfetching %s ...' % url
253 fn, _ = urllib.urlretrieve(url, filename)
254 return open(fn)
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000255
256#=======================================================================
257# Preliminary PyUNIT integration.
258
259import unittest
260
261
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000262class BasicTestRunner:
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000263 def run(self, test):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000264 result = unittest.TestResult()
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000265 test(result)
266 return result
267
268
Fred Drake26641032001-10-04 19:46:07 +0000269def run_suite(suite, testclass=None):
Barry Warsawc88425e2001-09-20 06:31:22 +0000270 """Run tests from a unittest.TestSuite-derived class."""
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000271 if verbose:
Fred Drake84a59342001-03-23 04:21:17 +0000272 runner = unittest.TextTestRunner(sys.stdout, verbosity=2)
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000273 else:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000274 runner = BasicTestRunner()
Fred Drakecd1b1dd2001-03-21 18:26:33 +0000275
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000276 result = runner.run(suite)
277 if not result.wasSuccessful():
Fred Drake14f6c182001-07-16 18:51:32 +0000278 if len(result.errors) == 1 and not result.failures:
279 err = result.errors[0][1]
280 elif len(result.failures) == 1 and not result.errors:
281 err = result.failures[0][1]
282 else:
Fred Drake26641032001-10-04 19:46:07 +0000283 if testclass is None:
284 msg = "errors occurred; run in verbose mode for details"
285 else:
286 msg = "errors occurred in %s.%s" \
287 % (testclass.__module__, testclass.__name__)
288 raise TestFailed(msg)
Tim Peters2d84f2c2001-09-08 03:37:56 +0000289 raise TestFailed(err)
Tim Petersa0a62222001-09-09 06:12:01 +0000290
Barry Warsawc10d6902001-09-20 06:30:41 +0000291
Walter Dörwald21d3a322003-05-01 17:45:56 +0000292def run_unittest(*classes):
293 """Run tests from unittest.TestCase-derived classes."""
Raymond Hettinger9dcbbea2003-04-27 07:54:23 +0000294 suite = unittest.TestSuite()
Walter Dörwald21d3a322003-05-01 17:45:56 +0000295 for cls in classes:
Raymond Hettingerf3590622003-07-16 04:29:42 +0000296 if isinstance(cls, (unittest.TestSuite, unittest.TestCase)):
Raymond Hettinger21d99872003-07-16 02:59:32 +0000297 suite.addTest(cls)
298 else:
299 suite.addTest(unittest.makeSuite(cls))
Walter Dörwald21d3a322003-05-01 17:45:56 +0000300 if len(classes)==1:
301 testclass = classes[0]
302 else:
303 testclass = None
304 run_suite(suite, testclass)
Raymond Hettinger9dcbbea2003-04-27 07:54:23 +0000305
Barry Warsawc10d6902001-09-20 06:30:41 +0000306
Tim Petersa0a62222001-09-09 06:12:01 +0000307#=======================================================================
308# doctest driver.
309
310def run_doctest(module, verbosity=None):
Tim Peters17111f32001-10-03 04:08:26 +0000311 """Run doctest on the given module. Return (#failures, #tests).
Tim Petersa0a62222001-09-09 06:12:01 +0000312
313 If optional argument verbosity is not specified (or is None), pass
Tim Petersbea3fb82001-09-10 01:39:21 +0000314 test_support's belief about verbosity on to doctest. Else doctest's
315 usual behavior is used (it searches sys.argv for -v).
Tim Petersa0a62222001-09-09 06:12:01 +0000316 """
317
318 import doctest
319
320 if verbosity is None:
321 verbosity = verbose
322 else:
323 verbosity = None
324
Tim Peters342ca752001-09-25 19:13:20 +0000325 # Direct doctest output (normally just errors) to real stdout; doctest
326 # output shouldn't be compared by regrtest.
327 save_stdout = sys.stdout
Tim Peters8dee8092001-09-25 20:05:11 +0000328 sys.stdout = get_original_stdout()
Tim Peters342ca752001-09-25 19:13:20 +0000329 try:
330 f, t = doctest.testmod(module, verbose=verbosity)
331 if f:
332 raise TestFailed("%d of %d doctests failed" % (f, t))
333 finally:
334 sys.stdout = save_stdout
Raymond Hettinger35b34bd2003-05-17 00:58:33 +0000335 if verbose:
Raymond Hettinger1ba24b42003-05-17 01:59:57 +0000336 print 'doctest (%s) ... %d tests with zero failures' % (module.__name__, t)
Raymond Hettinger35b34bd2003-05-17 00:58:33 +0000337 return f, t