summaryrefslogtreecommitdiff
path: root/test/test_coverage.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2009-07-03 22:08:02 -0400
committerNed Batchelder <ned@nedbatchelder.com>2009-07-03 22:08:02 -0400
commitfee9f33351329a3d9fa449e380e9e77973c3102e (patch)
tree1bce89926371e4b15598cae697943cf34ab6f893 /test/test_coverage.py
parent531ba0365f75a459dc28f997999c48dceb546a3e (diff)
downloadpython-coveragepy-git-fee9f33351329a3d9fa449e380e9e77973c3102e.tar.gz
Add a test that proves 2.3 has problems measuring exceptions. Now to figure out what to do about it...
Diffstat (limited to 'test/test_coverage.py')
-rw-r--r--test/test_coverage.py101
1 files changed, 101 insertions, 0 deletions
diff --git a/test/test_coverage.py b/test/test_coverage.py
index 3575f378..d0b2f9bc 100644
--- a/test/test_coverage.py
+++ b/test/test_coverage.py
@@ -1749,6 +1749,107 @@ class PyexpatTest(CoverageTest):
self.assertEqual(missing, [])
+class ExceptionTest(CoverageTest):
+ """I suspect different versions of Python deal with exceptions differently
+ in the trace function.
+ """
+
+ def testException(self):
+ # Python 2.3's trace function doesn't get called with "return" if the
+ # scope is exiting due to an exception. This confounds our trace
+ # function which relies on scope announcements to track which files to
+ # trace.
+ #
+ # This test is designed to sniff this out. Each function in the call
+ # stack is in a different file, to try to trip up the tracer. Each
+ # file has active lines in a different range so we'll see if the lines
+ # get attributed to the wrong file.
+
+ self.makeFile("oops.py", """\
+ def oops(args):
+ a = 2
+ raise Exception("oops")
+ a = 4
+ """)
+
+ self.makeFile("fly.py", "\n"*100 + """\
+ def fly(calls):
+ a = 2
+ calls[0](calls[1:])
+ a = 4
+ """)
+
+ self.makeFile("catch.py", "\n"*200 + """\
+ def catch(calls):
+ try:
+ a = 3
+ calls[0](calls[1:])
+ a = 5
+ except:
+ a = 7
+ """)
+
+ self.makeFile("doit.py", "\n"*300 + """\
+ def doit(calls):
+ try:
+ calls[0](calls[1:])
+ except:
+ a = 5
+ """)
+
+ # Import all the modules before starting coverage, so the def lines
+ # won't be in all the results.
+ for mod in "oops fly catch doit".split():
+ self.importModule(mod)
+
+ # Each run nests the functions differently to get different combinations
+ # of catching exceptions and letting them fly.
+ runs = [
+ ("fly oops", {
+ 'doit.py': [302,303,304,305],
+ 'fly.py': [102,103],
+ 'oops.py': [2,3],
+ }),
+ ("catch oops", {
+ 'doit.py': [302,303],
+ 'catch.py': [202,203,204,206,207],
+ 'oops.py': [2,3],
+ }),
+ ("fly catch oops", {
+ 'doit.py': [302,303],
+ 'fly.py': [102,103,104],
+ 'catch.py': [202,203,204,206,207],
+ 'oops.py': [2,3],
+ }),
+ ("catch fly oops", {
+ 'doit.py': [302,303],
+ 'catch.py': [202,203,204,206,207],
+ 'fly.py': [102,103],
+ 'oops.py': [2,3],
+ }),
+ ]
+
+ for callnames, lines_expected in runs:
+ cov = coverage.coverage()
+
+ # Import the python file, executing it.
+ cov.start()
+ calls = [getattr(sys.modules[cn], cn) for cn in callnames.split()]
+ getattr(sys.modules['doit'], 'doit')(calls)
+ cov.stop()
+
+ # Clean the line data and compare to expected results.
+ # The filenames are absolute, so keep just the base.
+ lines = cov.data.line_data()
+ clean_lines = {}
+ for f, llist in lines.items():
+ if f == __file__:
+ # ignore this file.
+ continue
+ clean_lines[os.path.basename(f)] = llist
+ self.assertEqual(clean_lines, lines_expected)
+
+
if __name__ == '__main__':
print "Testing under Python version: %s" % sys.version
unittest.main()