summaryrefslogtreecommitdiff
path: root/test/test_coverage.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_coverage.py')
-rw-r--r--test/test_coverage.py601
1 files changed, 206 insertions, 395 deletions
diff --git a/test/test_coverage.py b/test/test_coverage.py
index 093065f8..27bfffca 100644
--- a/test/test_coverage.py
+++ b/test/test_coverage.py
@@ -1,30 +1,111 @@
"""Tests for Coverage."""
-# Copyright 2004-2009, Ned Batchelder
# http://nedbatchelder.com/code/coverage
-import os, sys, unittest
+import os, sys
import coverage
coverage.use_cache(0)
+from coverage.misc import CoverageException
+
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
+class TestCoverageTest(CoverageTest):
+ """Make sure our complex self.check_coverage method works."""
+
+ def test_successful_coverage(self):
+ # The simplest run possible.
+ self.check_coverage("""\
+ a = 1
+ b = 2
+ """,
+ [1,2]
+ )
+ # You can provide a list of possible statement matches.
+ self.check_coverage("""\
+ a = 1
+ b = 2
+ """,
+ ([100], [1,2], [1723,47]),
+ )
+ # You can specify missing lines.
+ self.check_coverage("""\
+ a = 1
+ if a == 2:
+ a = 3
+ """,
+ [1,2,3],
+ missing="3",
+ )
+ # You can specify a list of possible missing lines.
+ self.check_coverage("""\
+ a = 1
+ if a == 2:
+ a = 3
+ """,
+ [1,2,3],
+ missing=("47-49", "3", "100,102")
+ )
+
+ def test_failed_coverage(self):
+ # If the lines are wrong, the message shows right and wrong.
+ self.assertRaisesRegexp(AssertionError,
+ r"\[1, 2] != \[1]",
+ self.check_coverage, """\
+ a = 1
+ b = 2
+ """,
+ [1]
+ )
+ # If the list of lines possibilities is wrong, the msg shows right.
+ self.assertRaisesRegexp(AssertionError,
+ r"None of the lines choices matched \[1, 2]",
+ self.check_coverage, """\
+ a = 1
+ b = 2
+ """,
+ ([1], [2])
+ )
+ # If the missing lines are wrong, the message shows right and wrong.
+ self.assertRaisesRegexp(AssertionError,
+ r"'3' != '37'",
+ self.check_coverage, """\
+ a = 1
+ if a == 2:
+ a = 3
+ """,
+ [1,2,3],
+ missing="37",
+ )
+ # If the missing lines possibilities are wrong, the msg shows right.
+ self.assertRaisesRegexp(AssertionError,
+ r"None of the missing choices matched '3'",
+ self.check_coverage, """\
+ a = 1
+ if a == 2:
+ a = 3
+ """,
+ [1,2,3],
+ missing=("37", "4-10"),
+ )
+
+
class BasicCoverageTest(CoverageTest):
"""The simplest tests, for quick smoke testing of fundamental changes."""
-
+
def testSimple(self):
self.check_coverage("""\
a = 1
b = 2
-
+
c = 4
# Nothing here
d = 6
""",
- [1,2,4,6], report="4 4 100%")
-
+ [1,2,4,6], report="4 0 100%")
+
def testIndentationWackiness(self):
# Partial final lines are OK.
self.check_coverage("""\
@@ -55,11 +136,11 @@ class BasicCoverageTest(CoverageTest):
assert l == [12, 14, 16, 18]
""",
[1,5], "")
-
+
class SimpleStatementTest(CoverageTest):
"""Testing simple single-line statements."""
-
+
def testExpression(self):
self.check_coverage("""\
1 + 2
@@ -71,7 +152,7 @@ class SimpleStatementTest(CoverageTest):
def testAssert(self):
self.check_coverage("""\
assert (1 + 2)
- assert (1 +
+ assert (1 +
2)
assert (1 + 2), 'the universe is broken'
assert (1 +
@@ -98,7 +179,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 7 and b == 8 and c == 9
""",
[1,2,3], "")
-
+
def testAttributeAssignment(self):
# Attribute assignment
self.check_coverage("""\
@@ -111,7 +192,7 @@ class SimpleStatementTest(CoverageTest):
1
""",
[1,2,3,4,6], "")
-
+
def testListofAttributeAssignment(self):
self.check_coverage("""\
class obj: pass
@@ -125,7 +206,7 @@ class SimpleStatementTest(CoverageTest):
2
""",
[1,2,3,4,7], "")
-
+
def testAugmentedAssignment(self):
self.check_coverage("""\
a = 1
@@ -151,7 +232,7 @@ class SimpleStatementTest(CoverageTest):
'''
c = len('''
long expression
- ''' +
+ ''' +
'''
on many
lines.
@@ -195,7 +276,7 @@ class SimpleStatementTest(CoverageTest):
Foo().foo()
""",
([1,2,4,5], [1,2,5]), "")
-
+
def testDel(self):
self.check_coverage("""\
d = { 'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1 }
@@ -210,7 +291,7 @@ class SimpleStatementTest(CoverageTest):
""",
[1,2,3,6,9], "")
- if sys.hexversion < 0x03000000: # Print statement is gone in Py3k.
+ if sys.version_info < (3, 0): # Print statement is gone in Py3k.
def testPrint(self):
self.check_coverage("""\
print "hello, world!"
@@ -223,7 +304,7 @@ class SimpleStatementTest(CoverageTest):
print "goodbye",
""",
[1,2,4,5,6,8], "")
-
+
def testRaise(self):
self.check_coverage("""\
try:
@@ -251,7 +332,7 @@ class SimpleStatementTest(CoverageTest):
return (
a +
1)
-
+
x = fn()
assert(x == 2)
""",
@@ -262,7 +343,7 @@ class SimpleStatementTest(CoverageTest):
return (a,
a + 1,
a + 2)
-
+
x,y,z = fn()
assert x == 1 and y == 2 and z == 3
""",
@@ -282,7 +363,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 1 and b == 9 and c == (1,2)
""",
[1,2,3,4,7,9,10], "")
-
+
def testBreak(self):
self.check_coverage("""\
for x in range(10):
@@ -292,7 +373,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 2
""",
[1,2,3,4,5], "4")
-
+
def testContinue(self):
self.check_coverage("""\
for x in range(10):
@@ -302,7 +383,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 11
""",
[1,2,3,4,5], "4")
-
+
if 0:
# Peephole optimization of jumps to jumps can mean that some statements
# never hit the line tracer. The behavior is different in different
@@ -319,7 +400,7 @@ class SimpleStatementTest(CoverageTest):
b += 1
c += 1
assert a == 50 and b == 50 and c == 50
-
+
a = b = c = 0
for n in range(100):
if n % 2:
@@ -332,7 +413,7 @@ class SimpleStatementTest(CoverageTest):
assert a == 33 and b == 50 and c == 50
""",
[1,2,3,4,5,6,8,9,10, 12,13,14,15,16,17,19,20,21], "")
-
+
def testImport(self):
self.check_coverage("""\
import string
@@ -379,7 +460,7 @@ class SimpleStatementTest(CoverageTest):
assert len(path) > 0
""",
[1,3], "")
-
+
def testGlobal(self):
self.check_coverage("""\
g = h = i = 1
@@ -401,7 +482,7 @@ class SimpleStatementTest(CoverageTest):
""",
[1,2,3,4,5], "")
- if sys.hexversion < 0x03000000:
+ if sys.version_info < (3, 0):
# In Python 2.x, exec is a statement.
def testExec(self):
self.check_coverage("""\
@@ -486,24 +567,24 @@ class SimpleStatementTest(CoverageTest):
class CompoundStatementTest(CoverageTest):
"""Testing coverage of multi-line compound statements."""
-
+
def testStatementList(self):
self.check_coverage("""\
a = 1;
b = 2; c = 3
d = 4; e = 5;
-
+
assert (a,b,c,d,e) == (1,2,3,4,5)
""",
[1,2,3,5], "")
-
+
def testIf(self):
self.check_coverage("""\
a = 1
if a == 1:
x = 3
assert x == 3
- if (a ==
+ if (a ==
1):
x = 7
assert x == 7
@@ -539,7 +620,7 @@ class CompoundStatementTest(CoverageTest):
assert x == 4
""",
[1,2,3,4,6,8,9], "6-8")
-
+
def testElif(self):
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -551,7 +632,7 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert x == 3
""",
- [1,2,3,4,5,7,8], "4-7", report="7 4 57% 4-7")
+ [1,2,3,4,5,7,8], "4-7", report="7 3 57% 4-7")
self.check_coverage("""\
a = 1; b = 2; c = 3;
if a != 1:
@@ -562,7 +643,7 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert y == 5
""",
- [1,2,3,4,5,7,8], "3, 7", report="7 5 71% 3, 7")
+ [1,2,3,4,5,7,8], "3, 7", report="7 2 71% 3, 7")
self.check_coverage("""\
a = 1; b = 2; c = 3;
if a != 1:
@@ -573,7 +654,7 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert z == 7
""",
- [1,2,3,4,5,7,8], "3, 5", report="7 5 71% 3, 5")
+ [1,2,3,4,5,7,8], "3, 5", report="7 2 71% 3, 5")
def testElifNoElse(self):
self.check_coverage("""\
@@ -584,7 +665,7 @@ class CompoundStatementTest(CoverageTest):
y = 5
assert x == 3
""",
- [1,2,3,4,5,6], "4-5", report="6 4 66% 4-5")
+ [1,2,3,4,5,6], "4-5", report="6 2 66% 4-5")
self.check_coverage("""\
a = 1; b = 2; c = 3;
if a != 1:
@@ -593,7 +674,7 @@ class CompoundStatementTest(CoverageTest):
y = 5
assert y == 5
""",
- [1,2,3,4,5,6], "3", report="6 5 83% 3")
+ [1,2,3,4,5,6], "3", report="6 1 83% 3")
def testElifBizarre(self):
self.check_coverage("""\
@@ -653,7 +734,7 @@ class CompoundStatementTest(CoverageTest):
assert z == 7
""",
[1,2,4,5,7,9,10], "4, 7")
-
+
def testPathologicalSplitIf(self):
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -700,7 +781,7 @@ class CompoundStatementTest(CoverageTest):
assert z == 7
""",
[1,2,5,6,9,11,12], "5, 9")
-
+
def testAbsurdSplitIf(self):
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -786,7 +867,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 2 and b == 1
""",
[1,2,3,4,5,6,8,9], "6-8")
-
+
def testSplitWhile(self):
self.check_coverage("""\
a = 3; b = 0
@@ -834,7 +915,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 1
""",
[1,2,3,4,5,6], "5")
-
+
def testForElse(self):
self.check_coverage("""\
a = 0
@@ -856,7 +937,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 1
""",
[1,2,3,4,5,7,8], "5-7")
-
+
def testSplitFor(self):
self.check_coverage("""\
a = 0
@@ -876,7 +957,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 15
""",
[1,2,6,7], "")
-
+
def testTryExcept(self):
self.check_coverage("""\
a = 0
@@ -946,7 +1027,7 @@ class CompoundStatementTest(CoverageTest):
assert a == 99
""",
[1,2,3,4,5,6,8,9], "8")
-
+
def testTryFinally(self):
self.check_coverage("""\
a = 0
@@ -978,7 +1059,7 @@ class CompoundStatementTest(CoverageTest):
''' docstring
'''
return 1
-
+
a = foo()
assert a == 1
""",
@@ -991,7 +1072,7 @@ class CompoundStatementTest(CoverageTest):
''' docstring
'''
return a+b
-
+
x = foo(17, 23)
assert x == 40
""",
@@ -1007,7 +1088,7 @@ class CompoundStatementTest(CoverageTest):
''' docstring
'''
return a+b
-
+
x = foo()
assert x == 22
""",
@@ -1023,19 +1104,31 @@ class CompoundStatementTest(CoverageTest):
def __init__(self):
''' Another docstring. '''
self.a = 1
-
+
def foo(self):
return self.a
-
+
x = theClass().foo()
assert x == 1
""",
- [2,6,8,10,11,13,14], "")
+ [2,6,8,10,11,13,14], "")
class ExcludeTest(CoverageTest):
"""Tests of the exclusion feature to mark lines as not covered."""
-
+
+ def testDefault(self):
+ # A number of forms of pragma comment are accepted.
+ self.check_coverage("""\
+ a = 1
+ b = 2 # pragma: no cover
+ c = 3
+ d = 4 #pragma NOCOVER
+ e = 5
+ """,
+ [1,3,5]
+ )
+
def testSimple(self):
self.check_coverage("""\
a = 1; b = 2
@@ -1056,7 +1149,7 @@ class ExcludeTest(CoverageTest):
assert a == 1 and b == 2
""",
[1,3,5,7], "5", ['-cc', '-xx'])
-
+
def testExcludingIfSuite(self):
self.check_coverage("""\
a = 1; b = 2
@@ -1083,7 +1176,7 @@ class ExcludeTest(CoverageTest):
assert a == 8 and b == 9
""",
[1,8,9,10], "", ['if 0:'])
-
+
def testExcludingElseSuite(self):
self.check_coverage("""\
a = 1; b = 2
@@ -1105,14 +1198,14 @@ class ExcludeTest(CoverageTest):
a = 4
b = 5
c = 6
-
+
# Lots of comments to confuse the else handler.
# more.
-
+
else: #pragma: NO COVER
# Comments here too.
-
+
a = 8
b = 9
assert a == 4 and b == 5 and c == 6
@@ -1130,7 +1223,7 @@ class ExcludeTest(CoverageTest):
elif 1==0: #pragma: NO COVER
a = 8
b = 9
- else:
+ else:
a = 11
b = 12
assert a == 4 and b == 5 and c == 6
@@ -1143,7 +1236,7 @@ class ExcludeTest(CoverageTest):
a = 2
if 0: x = 3 # no cover
b = 4
-
+
foo()
""",
[1,2,4,6], "", ["no cover"])
@@ -1154,11 +1247,11 @@ class ExcludeTest(CoverageTest):
l = list(range(10))
a = l[:3] # no cover
b = 4
-
+
foo()
""",
[1,2,4,6], "", ["no cover"])
-
+
def testExcludingForSuite(self):
self.check_coverage("""\
a = 0
@@ -1186,7 +1279,7 @@ class ExcludeTest(CoverageTest):
assert a == 1
""",
[1,7], "", ['#pragma: NO COVER'])
-
+
def testExcludingForElse(self):
self.check_coverage("""\
a = 0
@@ -1199,7 +1292,7 @@ class ExcludeTest(CoverageTest):
assert a == 1
""",
[1,2,3,4,5,8], "5", ['#pragma: NO COVER'])
-
+
def testExcludingWhile(self):
self.check_coverage("""\
a = 3; b = 0
@@ -1290,7 +1383,7 @@ class ExcludeTest(CoverageTest):
assert a == 99
""",
[1,2,3,4,5,6,9], "", ['#pragma: NO COVER'])
-
+
def testExcludingTryExceptPass(self):
self.check_coverage("""\
a = 0
@@ -1336,7 +1429,7 @@ class ExcludeTest(CoverageTest):
assert a == 99
""",
[1,2,3,4,5,6,9], "", ['#pragma: NO COVER'])
-
+
def testExcludingIfPass(self):
# From a comment on the coverage page by Michael McNeil Forbes:
self.check_coverage("""\
@@ -1345,18 +1438,18 @@ class ExcludeTest(CoverageTest):
pass # This line still reported as missing
if False: # pragma: no cover
x = 1 # Now it is skipped.
-
+
f()
""",
[1,7], "", ["no cover"])
-
+
def testExcludingFunction(self):
self.check_coverage("""\
def fn(foo): #pragma: NO COVER
a = 1
b = 2
c = 3
-
+
x = 1
assert x == 1
""",
@@ -1367,71 +1460,47 @@ class ExcludeTest(CoverageTest):
class Fooey:
def __init__(self):
self.a = 1
-
+
def foo(self): #pragma: NO COVER
return self.a
-
+
x = Fooey()
assert x.a == 1
""",
[1,2,3,8,9], "", ['#pragma: NO COVER'])
-
+
def testExcludingClass(self):
self.check_coverage("""\
class Fooey: #pragma: NO COVER
def __init__(self):
self.a = 1
-
+
def foo(self):
return self.a
-
+
x = 1
assert x == 1
""",
[8,9], "", ['#pragma: NO COVER'])
-class ThreadingTest(CoverageTest):
- """Tests of the threading support."""
-
- def testThreading(self):
- self.check_coverage("""\
- import time, threading
-
- def fromMainThread():
- return "called from main thread"
-
- def fromOtherThread():
- return "called from other thread"
-
- def neverCalled():
- return "no one calls me"
-
- other = threading.Thread(target=fromOtherThread)
- other.start()
- fromMainThread()
- other.join()
- """,
- [1,3,4,6,7,9,10,12,13,14,15], "10")
-
-
-if sys.hexversion >= 0x020400f0:
+if sys.version_info >= (2, 4):
class Py24Test(CoverageTest):
"""Tests of new syntax in Python 2.4."""
-
+
def testFunctionDecorators(self):
self.check_coverage("""\
def require_int(func):
def wrapper(arg):
assert isinstance(arg, int)
return func(arg)
-
+
return wrapper
-
+
@require_int
def p1(arg):
return arg*2
-
+
assert p1(10) == 20
""",
[1,2,3,4,6,8,10,12], "")
@@ -1444,11 +1513,11 @@ if sys.hexversion >= 0x020400f0:
return extra*func(arg)
return wrapper
return decorator
-
+
@boost_by(10)
def boosted(arg):
return arg*2
-
+
assert boosted(10) == 200
""",
[1,2,3,4,5,6,8,10,12], "")
@@ -1467,45 +1536,45 @@ if sys.hexversion >= 0x020400f0:
return extra*func(arg)
return wrapper
return decorator
-
+
@require_int
@boost_by(10)
def boosted1(arg):
return arg*2
-
+
assert boosted1(10) == 200
@boost_by(10)
@require_int
def boosted2(arg):
return arg*2
-
+
assert boosted2(10) == 200
""",
([1,2,3,4,5,7,8,9,10,11,12,14,15,17,19,21,22,24,26],
[1,2,3,4,5,7,8,9,10,11,12,14, 17,19,21, 24,26]), "")
-if sys.hexversion >= 0x020500f0:
+if sys.version_info >= (2, 5):
class Py25Test(CoverageTest):
"""Tests of new syntax in Python 2.5."""
def testWithStatement(self):
self.check_coverage("""\
from __future__ import with_statement
-
+
class Managed:
def __enter__(self):
desc = "enter"
-
+
def __exit__(self, type, value, tb):
desc = "exit"
-
+
m = Managed()
with m:
desc = "block1a"
desc = "block1b"
-
+
try:
with m:
desc = "block2"
@@ -1514,7 +1583,7 @@ if sys.hexversion >= 0x020500f0:
desc = "caught"
""",
[1,3,4,5,7,8,10,11,12,13,15,16,17,18,19,20], "")
-
+
def testTryExceptFinally(self):
self.check_coverage("""\
a = 0; b = 0
@@ -1596,7 +1665,7 @@ if sys.hexversion >= 0x020500f0:
assert a == 99 and b == 2
""",
[1,2,3,4,5,6,8,10,11], "8")
-
+
class ModuleTest(CoverageTest):
"""Tests for the module-level behavior of the `coverage` module."""
@@ -1607,287 +1676,29 @@ class ModuleTest(CoverageTest):
coverage.coverage()
-class ProcessTest(CoverageTest):
- """Tests of the per-process behavior of coverage.py."""
-
- def testSaveOnExit(self):
- self.make_file("mycode.py", """\
- h = "Hello"
- w = "world"
- """)
-
- self.assert_(not os.path.exists(".coverage"))
- self.run_command("coverage -x mycode.py")
- self.assert_(os.path.exists(".coverage"))
-
- def testEnvironment(self):
- # Checks that we can import modules from the test directory at all!
- self.make_file("mycode.py", """\
- import covmod1
- import covmodzip1
- a = 1
- print ('done')
- """)
-
- self.assert_(not os.path.exists(".coverage"))
- out = self.run_command("coverage -x mycode.py")
- self.assert_(os.path.exists(".coverage"))
- self.assertEqual(out, 'done\n')
-
- def testCombineParallelData(self):
- self.make_file("b_or_c.py", """\
- import sys
- a = 1
- if sys.argv[1] == 'b':
- b = 1
- else:
- c = 1
- d = 1
- print ('done')
- """)
-
- out = self.run_command("coverage -x -p b_or_c.py b")
- self.assertEqual(out, 'done\n')
- self.assert_(not os.path.exists(".coverage"))
-
- out = self.run_command("coverage -x -p b_or_c.py c")
- self.assertEqual(out, 'done\n')
- self.assert_(not os.path.exists(".coverage"))
-
- # After two -p runs, there should be two .coverage.machine.123 files.
- self.assertEqual(
- len([f for f in os.listdir('.') if f.startswith('.coverage.')]),
- 2)
-
- # Combine the parallel coverage data files into .coverage .
- self.run_command("coverage -c")
- self.assert_(os.path.exists(".coverage"))
-
- # Read the coverage file and see that b_or_c.py has all 7 lines
- # executed.
- data = coverage.CoverageData()
- data.read_file(".coverage")
- self.assertEqual(data.summary()['b_or_c.py'], 7)
-
- def test_missing_source_file(self):
- # Check what happens if the source is missing when reporting happens.
- self.make_file("fleeting.py", """\
- s = 'goodbye, cruel world!'
- """)
-
- self.run_command("coverage run fleeting.py")
- os.remove("fleeting.py")
- out = self.run_command("coverage html -d htmlcov")
- self.assert_matches(out, "No source for code: '.*fleeting.py'")
- self.assert_("Traceback" not in out)
-
- # It happens that the code paths are different for *.py and other
- # files, so try again with no extension.
- self.make_file("fleeting", """\
- s = 'goodbye, cruel world!'
- """)
-
- self.run_command("coverage run fleeting")
- os.remove("fleeting")
- out = self.run_command("coverage html -d htmlcov")
- self.assert_matches(out, "No source for code: '.*fleeting'")
- self.assert_("Traceback" not in out)
-
- def test_running_missing_file(self):
- out = self.run_command("coverage run xyzzy.py")
- self.assert_matches(out, "No file to run: .*xyzzy.py")
- self.assert_("Traceback" not in out)
-
-
-class RecursionTest(CoverageTest):
- """Check what happens when recursive code gets near limits."""
-
- def testShortRecursion(self):
- # We can definitely get close to 500 stack frames.
- self.check_coverage("""\
- def recur(n):
- if n == 0:
- return 0
- else:
- return recur(n-1)+1
-
- recur(495) # We can get at least this many stack frames.
- """,
- [1,2,3,5,7], "")
-
- def testLongRecursion(self):
- # We can't finish a very deep recursion, but we don't crash.
- self.assertRaises(RuntimeError, self.check_coverage,
- """\
- def recur(n):
- if n == 0:
- return 0
- else:
- return recur(n-1)+1
-
- recur(100000) # This is definitely too many frames.
- """,
- [1,2,3,5,7], "")
-
-
-class PyexpatTest(CoverageTest):
- """Pyexpat screws up tracing. Make sure we've counter-defended properly."""
-
- def testPyexpat(self):
- # pyexpat calls the trace function explicitly (inexplicably), and does
- # it wrong for exceptions. Parsing a DOCTYPE for some reason throws
- # an exception internally, and triggers its wrong behavior. This test
- # checks that our fake PyTrace_RETURN hack in tracer.c works. It will
- # also detect if the pyexpat bug is fixed unbeknownst to us, meaning
- # we'd see two RETURNs where there should only be one.
-
- self.make_file("trydom.py", """\
- import xml.dom.minidom
-
- XML = '''\\
- <!DOCTYPE fooey SYSTEM "http://www.example.com/example.dtd">
- <root><child/><child/></root>
- '''
-
- def foo():
- dom = xml.dom.minidom.parseString(XML)
- assert len(dom.getElementsByTagName('child')) == 2
- a = 11
-
- foo()
- """)
-
- self.make_file("outer.py", "\n"*100 + "import trydom\na = 102\n")
-
- cov = coverage.coverage()
- cov.erase()
-
- # Import the python file, executing it.
- cov.start()
- self.import_module("outer")
- cov.stop()
-
- _, statements, missing, _ = cov.analysis("trydom.py")
- self.assertEqual(statements, [1,3,8,9,10,11,13])
- self.assertEqual(missing, [])
-
- _, statements, missing, _ = cov.analysis("outer.py")
- self.assertEqual(statements, [101,102])
- 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.make_file("oops.py", """\
- def oops(args):
- a = 2
- raise Exception("oops")
- a = 4
- """)
-
- self.make_file("fly.py", "\n"*100 + """\
- def fly(calls):
- a = 2
- calls[0](calls[1:])
- a = 4
- """)
-
- self.make_file("catch.py", "\n"*200 + """\
- def catch(calls):
- try:
- a = 3
- calls[0](calls[1:])
- a = 5
- except:
- a = 7
- """)
-
- self.make_file("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.import_module(mod)
-
- # Each run nests the functions differently to get different
- # combinations of catching exceptions and letting them fly.
- runs = [
- ("doit fly oops", {
- 'doit.py': [302,303,304,305],
- 'fly.py': [102,103],
- 'oops.py': [2,3],
- }),
- ("doit catch oops", {
- 'doit.py': [302,303],
- 'catch.py': [202,203,204,206,207],
- 'oops.py': [2,3],
- }),
- ("doit fly catch oops", {
- 'doit.py': [302,303],
- 'fly.py': [102,103,104],
- 'catch.py': [202,203,204,206,207],
- 'oops.py': [2,3],
- }),
- ("doit 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:
-
- # Make the list of functions we'll call for this test.
- calls = [getattr(sys.modules[cn], cn) for cn in callnames.split()]
-
- cov = coverage.coverage()
- cov.start()
- # Call our list of functions: invoke the first, with the rest as
- # an argument.
- calls[0](calls[1:])
- 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()
-
-
-# TODO: split "and" conditions across lines, and detect not running lines.
-# (Can't be done: trace function doesn't get called for each line
-# in an expression!)
-# TODO: Generator comprehensions?
-# TODO: Constant if tests ("if 1:"). Py 2.4 doesn't execute them.
-# TODO: There are no tests for analysis2 directly.
+class ReportingTest(CoverageTest):
+ """Tests of some reporting behavior."""
+
+ def test_no_data_to_report_on_annotate(self):
+ # Reporting with no data produces a nice message and no output dir.
+ self.assertRaisesRegexp(
+ CoverageException, "No data to report.",
+ self.command_line, "annotate -d ann"
+ )
+ self.assertFalse(os.path.exists("ann"))
+
+ def test_no_data_to_report_on_html(self):
+ # Reporting with no data produces a nice message and no output dir.
+ self.assertRaisesRegexp(
+ CoverageException, "No data to report.",
+ self.command_line, "html -d htmlcov"
+ )
+ self.assertFalse(os.path.exists("htmlcov"))
+
+ def test_no_data_to_report_on_xml(self):
+ # Reporting with no data produces a nice message.
+ self.assertRaisesRegexp(
+ CoverageException, "No data to report.",
+ self.command_line, "xml"
+ )
+ # Currently, this leaves an empty coverage.xml file... :(