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