diff options
Diffstat (limited to 'test/test_coverage.py')
-rw-r--r-- | test/test_coverage.py | 601 |
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... :( |