summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/backtest.py2
-rw-r--r--test/backunittest.py32
-rw-r--r--test/test_api.py14
-rw-r--r--test/test_arcs.py25
-rw-r--r--test/test_cmdline.py40
-rw-r--r--test/test_config.py20
-rw-r--r--test/test_files.py2
-rw-r--r--test/test_html.py103
-rw-r--r--test/test_misc.py51
-rw-r--r--test/test_oddball.py1
-rw-r--r--test/test_phystokens.py4
-rw-r--r--test/test_process.py95
-rw-r--r--test/test_summary.py136
-rw-r--r--test/test_testing.py42
-rw-r--r--test/test_xml.py89
15 files changed, 547 insertions, 109 deletions
diff --git a/test/backtest.py b/test/backtest.py
index c54171d3..b17aa242 100644
--- a/test/backtest.py
+++ b/test/backtest.py
@@ -31,7 +31,7 @@ else:
stderr=subprocess.STDOUT
)
output, _ = proc.communicate()
- status = proc.returncode
+ status = proc.returncode # pylint: disable=E1101
# Get the output, and canonicalize it to strings with newlines.
if not isinstance(output, str):
diff --git a/test/backunittest.py b/test/backunittest.py
index c1685e0c..30da78eb 100644
--- a/test/backunittest.py
+++ b/test/backunittest.py
@@ -29,6 +29,27 @@ class TestCase(unittest.TestCase):
if exp:
self.fail(msg)
+ if _need('assertIn'):
+ def assertIn(self, member, container, msg=None):
+ """Assert that `member` is in `container`."""
+ if member not in container:
+ msg = msg or ('%r not found in %r' % (member, container))
+ self.fail(msg)
+
+ if _need('assertNotIn'):
+ def assertNotIn(self, member, container, msg=None):
+ """Assert that `member` is not in `container`."""
+ if member in container:
+ msg = msg or ('%r found in %r' % (member, container))
+ self.fail(msg)
+
+ if _need('assertGreater'):
+ def assertGreater(self, a, b, msg=None):
+ """Assert that `a` is greater than `b`."""
+ if not a > b:
+ msg = msg or ('%r not greater than %r' % (a, b))
+ self.fail(msg)
+
if _need('assertRaisesRegexp'):
def assertRaisesRegexp(self, excClass, regexp, callobj, *args, **kw):
""" Just like unittest.TestCase.assertRaises,
@@ -46,7 +67,7 @@ class TestCase(unittest.TestCase):
# Message provided, and it didn't match: fail!
raise self.failureException(
"Right exception, wrong message: "
- "'%s' doesn't match '%s'" % (excMsg, regexp)
+ "%r doesn't match %r" % (excMsg, regexp)
)
# No need to catch other exceptions: They'll fail the test all by
# themselves!
@@ -66,11 +87,12 @@ class TestCase(unittest.TestCase):
self.assertEqual(set(s1), set(s2))
if _need('assertRegexpMatches'):
- def assertRegexpMatches(self, s, regex):
- """Assert that `s` matches `regex`."""
- m = re.search(regex, s)
+ def assertRegexpMatches(self, text, regex, msg=None):
+ """Assert that `text` matches `regex`."""
+ m = re.search(regex, text)
if not m:
- raise self.failureException("%r doesn't match %r" % (s, regex))
+ msg = msg or ("%r doesn't match %r" % (text, regex))
+ raise self.failureException(msg)
if _need('assertMultiLineEqual'):
def assertMultiLineEqual(self, first, second, msg=None):
diff --git a/test/test_api.py b/test/test_api.py
index aa0e726b..c15db5ed 100644
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -84,7 +84,7 @@ class SingletonApiTest(CoverageTest):
self.do_report_work("mycode4")
coverage.report()
rpt = re.sub(r"\s+", " ", self.stdout())
- self.assertTrue("mycode4 7 3 57% 4-6" in rpt)
+ self.assertIn("mycode4 7 3 57% 4-6", rpt)
class ApiTest(CoverageTest):
@@ -366,16 +366,12 @@ class OmitIncludeTestsMixin(UsingModulesMixin):
def filenames_in(self, summary, filenames):
"""Assert the `filenames` are in the keys of `summary`."""
for filename in filenames.split():
- self.assert_(filename in summary,
- "%s should be in %r" % (filename, summary)
- )
+ self.assertIn(filename, summary)
def filenames_not_in(self, summary, filenames):
"""Assert the `filenames` are not in the keys of `summary`."""
for filename in filenames.split():
- self.assert_(filename not in summary,
- "%s should not be in %r" % (filename, summary)
- )
+ self.assertNotIn(filename, summary)
def test_nothing_specified(self):
result = self.coverage_usepkgs()
@@ -433,6 +429,7 @@ class SourceOmitIncludeTest(OmitIncludeTestsMixin, CoverageTest):
cov.start()
import usepkgs # pylint: disable=F0401,W0612
cov.stop()
+ cov._harvest_data() # private! sshhh...
summary = cov.data.summary()
for k, v in list(summary.items()):
assert k.endswith(".py")
@@ -514,4 +511,5 @@ class AnalysisTest(CoverageTest):
self.assertEqual(nums.n_excluded, 1)
self.assertEqual(nums.n_missing, 3)
self.assertEqual(nums.n_branches, 2)
- self.assertEqual(nums.n_missing_branches, 0)
+ self.assertEqual(nums.n_partial_branches, 0)
+ self.assertEqual(nums.n_missing_branches, 2)
diff --git a/test/test_arcs.py b/test/test_arcs.py
index ce550042..a9f7470b 100644
--- a/test/test_arcs.py
+++ b/test/test_arcs.py
@@ -450,18 +450,19 @@ class ExceptionArcTest(CoverageTest):
arcz=".1 12 23 34 3D 45 56 67 68 7A 8A A3 AB AD BC CD D.",
arcz_missing="3D AB BC CD", arcz_unpredicted="")
- def xxx_xest_finally_in_loop_2(self):
- self.check_coverage("""\
- for i in range(5):
- try:
- j = 3
- finally:
- f = 5
- g = 6
- h = 7
- """,
- arcz=".1 12 23 35 56 61 17 7.",
- arcz_missing="", arcz_unpredicted="")
+ if 0:
+ def test_finally_in_loop_2(self):
+ self.check_coverage("""\
+ for i in range(5):
+ try:
+ j = 3
+ finally:
+ f = 5
+ g = 6
+ h = 7
+ """,
+ arcz=".1 12 23 35 56 61 17 7.",
+ arcz_missing="", arcz_unpredicted="")
if sys.version_info >= (2, 5):
# Try-except-finally was new in 2.5
diff --git a/test/test_cmdline.py b/test/test_cmdline.py
index d4cc763d..eb7fe0f5 100644
--- a/test/test_cmdline.py
+++ b/test/test_cmdline.py
@@ -251,35 +251,35 @@ class ClassicCmdLineTest(CmdLineTest):
def test_html_report(self):
# coverage -b -d DIR [-i] [-o DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("-b", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -d dir1", self.INIT_LOAD + """\
- .html_report(directory="dir1", ignore_errors=None,
+ .html_report(directory="dir1", ignore_errors=None, title=None,
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -i", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=True,
+ .html_report(directory=None, ignore_errors=True, title=None,
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -o fooey", """\
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=["fooey"], include=None, morfs=[])
""")
self.cmd_executes("-b -o fooey,booey", """\
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=["fooey", "booey"], include=None, morfs=[])
""")
self.cmd_executes("-b mod1", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=None, include=None, morfs=["mod1"])
""")
self.cmd_executes("-b mod1 mod2 mod3", self.INIT_LOAD + """\
- .html_report(directory=None, ignore_errors=None,
+ .html_report(directory=None, ignore_errors=None, title=None,
omit=None, include=None, morfs=["mod1", "mod2", "mod3"])
""")
@@ -447,6 +447,14 @@ class NewCmdLineTest(CmdLineTest):
self.cmd_executes_same("html --omit f,b", "-b --omit f,b")
self.cmd_executes_same("html m1", "-b m1")
self.cmd_executes_same("html m1 m2 m3", "-b m1 m2 m3")
+ self.cmd_executes("html", self.INIT_LOAD + """\
+ .html_report(ignore_errors=None, omit=None, include=None, morfs=[],
+ directory=None, title=None)
+ """)
+ self.cmd_executes("html --title=Hello_there", self.INIT_LOAD + """\
+ .html_report(ignore_errors=None, omit=None, include=None, morfs=[],
+ directory=None, title='Hello_there')
+ """)
def test_report(self):
self.cmd_executes_same("report", "-r")
@@ -553,11 +561,11 @@ class NewCmdLineTest(CmdLineTest):
# coverage xml [-i] [--omit DIR,...] [FILE1 FILE2 ...]
self.cmd_executes("xml", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None, morfs=[],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml -i", self.INIT_LOAD + """\
.xml_report(ignore_errors=True, omit=None, include=None, morfs=[],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml -o myxml.foo", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None, morfs=[],
@@ -571,21 +579,21 @@ class NewCmdLineTest(CmdLineTest):
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
.xml_report(ignore_errors=None, omit=["fooey"], include=None, morfs=[],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml --omit fooey,booey", """\
.coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
.xml_report(ignore_errors=None, omit=["fooey", "booey"], include=None,
- morfs=[], outfile="coverage.xml")
+ morfs=[], outfile=None)
""")
self.cmd_executes("xml mod1", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None, morfs=["mod1"],
- outfile="coverage.xml")
+ outfile=None)
""")
self.cmd_executes("xml mod1 mod2 mod3", self.INIT_LOAD + """\
.xml_report(ignore_errors=None, omit=None, include=None,
- morfs=["mod1", "mod2", "mod3"], outfile="coverage.xml")
+ morfs=["mod1", "mod2", "mod3"], outfile=None)
""")
def test_no_arguments_at_all(self):
@@ -604,6 +612,12 @@ class CmdLineStdoutTest(CmdLineTest):
assert "Code coverage for Python." in out
assert out.count("\n") < 4
+ def test_version(self):
+ self.command_line("--version")
+ out = self.stdout()
+ assert "ersion " in out
+ assert out.count("\n") < 4
+
def test_help(self):
self.command_line("help")
out = self.stdout()
diff --git a/test/test_config.py b/test/test_config.py
index 4fc658f4..19e37ab9 100644
--- a/test/test_config.py
+++ b/test/test_config.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
"""Test the config file handling for coverage.py"""
import os, sys
@@ -139,6 +140,7 @@ class ConfigFileTest(CoverageTest):
directory = c:\\tricky\\dir.somewhere
extra_css=something/extra.css
+ title = Title & nums # nums!
[xml]
output=mycov.xml
@@ -159,7 +161,7 @@ class ConfigFileTest(CoverageTest):
self.assertTrue(cov.config.parallel)
self.assertEqual(cov.get_exclude_list(),
- ["if 0:", "pragma:?\s+no cover", "another_tab"]
+ ["if 0:", r"pragma:?\s+no cover", "another_tab"]
)
self.assertTrue(cov.config.ignore_errors)
self.assertEqual(cov.config.include, ["a/", "b/"])
@@ -169,7 +171,7 @@ class ConfigFileTest(CoverageTest):
self.assertEqual(cov.config.precision, 3)
self.assertEqual(cov.config.partial_list,
- ["pragma:?\s+no branch"]
+ [r"pragma:?\s+no branch"]
)
self.assertEqual(cov.config.partial_always_list,
["if 0:", "while True:"]
@@ -177,6 +179,7 @@ class ConfigFileTest(CoverageTest):
self.assertTrue(cov.config.show_missing)
self.assertEqual(cov.config.html_dir, r"c:\tricky\dir.somewhere")
self.assertEqual(cov.config.extra_css, "something/extra.css")
+ self.assertEqual(cov.config.html_title, "Title & nums # nums!")
self.assertEqual(cov.config.xml_output, "mycov.xml")
@@ -184,3 +187,16 @@ class ConfigFileTest(CoverageTest):
'source': ['.', '/home/ned/src/'],
'other': ['other', '/home/ned/other', 'c:\\Ned\\etc']
})
+
+ if sys.version_info[:2] != (3,1):
+ def test_one(self):
+ # This sample file tries to use lots of variation of syntax...
+ self.make_file(".coveragerc", """\
+ [html]
+ title = tabblo & «ταБЬℓσ» # numbers
+ """)
+ cov = coverage.coverage()
+
+ self.assertEqual(cov.config.html_title,
+ "tabblo & «ταБЬℓσ» # numbers"
+ )
diff --git a/test/test_files.py b/test/test_files.py
index 207274a2..5692699c 100644
--- a/test/test_files.py
+++ b/test/test_files.py
@@ -38,7 +38,7 @@ class FileLocatorTest(CoverageTest):
self.assertEqual(fl.relative_filename(a2), a2)
def test_filepath_contains_absolute_prefix_twice(self):
- # https://bitbucket.org/ned/coveragepy/issue/194/filelocatorrelative_filename-could-mangle
+ # https://bitbucket.org/ned/coveragepy/issue/194
# Build a path that has two pieces matching the absolute path prefix.
# Technically, this test doesn't do that on Windows, but drive
# letters make that impractical to acheive.
diff --git a/test/test_html.py b/test/test_html.py
index 1877a30d..d33dd1f3 100644
--- a/test/test_html.py
+++ b/test/test_html.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
"""Tests that HTML generation is awesome."""
import os.path, sys
@@ -7,19 +8,8 @@ from coverage.misc import NotPython
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
-class HtmlTest(CoverageTest):
- """HTML!"""
-
- def setUp(self):
- super(HtmlTest, self).setUp()
-
- # At least one of our tests monkey-patches the version of coverage,
- # so grab it here to restore it later.
- self.real_coverage_version = coverage.__version__
-
- def tearDown(self):
- coverage.__version__ = self.real_coverage_version
- super(HtmlTest, self).tearDown()
+class HtmlTestHelpers(CoverageTest):
+ """Methods that help with HTML tests."""
def create_initial_files(self):
"""Create the source files we need to run these tests."""
@@ -38,14 +28,14 @@ class HtmlTest(CoverageTest):
print("x is %d" % x)
""")
- def run_coverage(self, **kwargs):
+ def run_coverage(self, covargs=None, htmlargs=None):
"""Run coverage on main_file.py, and create an HTML report."""
self.clean_local_file_imports()
- cov = coverage.coverage(**kwargs)
+ cov = coverage.coverage(**(covargs or {}))
cov.start()
self.import_local_file("main_file")
cov.stop()
- cov.html_report()
+ cov.html_report(**(htmlargs or {}))
def remove_html_files(self):
"""Remove the HTML files created as part of the HTML report."""
@@ -54,6 +44,23 @@ class HtmlTest(CoverageTest):
os.remove("htmlcov/helper1.html")
os.remove("htmlcov/helper2.html")
+
+class HtmlDeltaTest(HtmlTestHelpers, CoverageTest):
+ """Tests of the HTML delta speed-ups."""
+
+ def setUp(self):
+ super(HtmlDeltaTest, self).setUp()
+
+ # At least one of our tests monkey-patches the version of coverage,
+ # so grab it here to restore it later.
+ self.real_coverage_version = coverage.__version__
+
+ self.maxDiff = None
+
+ def tearDown(self):
+ coverage.__version__ = self.real_coverage_version
+ super(HtmlDeltaTest, self).tearDown()
+
def test_html_created(self):
# Test basic HTML generation: files should be created.
self.create_initial_files()
@@ -118,11 +125,11 @@ class HtmlTest(CoverageTest):
# In this case, everything changes because the coverage settings have
# changed.
self.create_initial_files()
- self.run_coverage(timid=False)
+ self.run_coverage(covargs=dict(timid=False))
index1 = open("htmlcov/index.html").read()
self.remove_html_files()
- self.run_coverage(timid=True)
+ self.run_coverage(covargs=dict(timid=True))
# All the files have been reported again.
self.assert_exists("htmlcov/index.html")
@@ -156,6 +163,56 @@ class HtmlTest(CoverageTest):
self.assertMultiLineEqual(index1, fixed_index2)
+class HtmlTitleTests(HtmlTestHelpers, CoverageTest):
+ """Tests of the HTML title support."""
+
+ def test_default_title(self):
+ self.create_initial_files()
+ self.run_coverage()
+ index = open("htmlcov/index.html").read()
+ self.assertIn("<title>Coverage report</title>", index)
+ self.assertIn("<h1>Coverage report:", index)
+
+ def test_title_set_in_config_file(self):
+ self.create_initial_files()
+ self.make_file(".coveragerc", "[html]\ntitle = Metrics & stuff!\n")
+ self.run_coverage()
+ index = open("htmlcov/index.html").read()
+ self.assertIn("<title>Metrics &amp; stuff!</title>", index)
+ self.assertIn("<h1>Metrics &amp; stuff!:", index)
+
+ if sys.version_info[:2] != (3,1):
+ def test_non_ascii_title_set_in_config_file(self):
+ self.create_initial_files()
+ self.make_file(".coveragerc",
+ "[html]\ntitle = «ταБЬℓσ» numbers"
+ )
+ self.run_coverage()
+ index = open("htmlcov/index.html").read()
+ self.assertIn(
+ "<title>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " numbers", index
+ )
+ self.assertIn(
+ "<h1>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " numbers", index
+ )
+
+ def test_title_set_in_args(self):
+ self.create_initial_files()
+ self.make_file(".coveragerc", "[html]\ntitle = Good title\n")
+ self.run_coverage(htmlargs=dict(title="«ταБЬℓσ» & stüff!"))
+ index = open("htmlcov/index.html").read()
+ self.assertIn(
+ "<title>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " &amp; st&#252;ff!</title>", index
+ )
+ self.assertIn(
+ "<h1>&#171;&#964;&#945;&#1041;&#1068;&#8467;&#963;&#187;"
+ " &amp; st&#252;ff!:", index
+ )
+
+
class HtmlWithUnparsableFilesTest(CoverageTest):
"""Test the behavior when measuring unparsable files."""
@@ -197,13 +254,9 @@ class HtmlWithUnparsableFilesTest(CoverageTest):
self.assertEqual(output.strip(), "No data to report.")
def test_execed_liar_ignored(self):
- """
- Jinja2 sets __file__ to be a non-Python file, and then execs code.
-
- If that file contains non-Python code, a TokenError shouldn't
- have been raised when writing the HTML report.
-
- """
+ # Jinja2 sets __file__ to be a non-Python file, and then execs code.
+ # If that file contains non-Python code, a TokenError shouldn't
+ # have been raised when writing the HTML report.
if sys.version_info < (3, 0):
source = "exec compile('','','exec') in {'__file__': 'liar.html'}"
else:
diff --git a/test/test_misc.py b/test/test_misc.py
index eb73cc81..ac53cddb 100644
--- a/test/test_misc.py
+++ b/test/test_misc.py
@@ -2,7 +2,8 @@
import os, sys
-from coverage.misc import Hasher
+from coverage.misc import Hasher, file_be_gone
+from coverage import __version__, __url__
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
@@ -25,3 +26,51 @@ class HasherTest(CoverageTest):
h2 = Hasher()
h2.update({'b': 23, 'a': 17})
self.assertEqual(h1.digest(), h2.digest())
+
+
+class RemoveFileTest(CoverageTest):
+ """Tests of misc.file_be_gone."""
+
+ def test_remove_nonexistent_file(self):
+ # it's ok to try to remove a file that doesn't exist.
+ file_be_gone("not_here.txt")
+
+ def test_remove_actual_file(self):
+ # it really does remove a file that does exist.
+ self.make_file("here.txt", "We are here, we are here, we are here!")
+ file_be_gone("here.txt")
+ self.assert_doesnt_exist("here.txt")
+
+ def test_actual_errors(self):
+ # Errors can still happen.
+ # ". is a directory" on Unix, or "Access denied" on Windows
+ self.assertRaises(OSError, file_be_gone, ".")
+
+
+class SetupPyTest(CoverageTest):
+ """Tests of setup.py"""
+
+ run_in_temp_dir = False
+
+ def test_metadata(self):
+ status, output = self.run_command_status(
+ "python setup.py --description --version --url --author"
+ )
+ self.assertEqual(status, 0)
+ out = output.splitlines()
+ self.assertIn("measurement", out[0])
+ self.assertEqual(out[1], __version__)
+ self.assertEqual(out[2], __url__)
+ self.assertIn("Ned Batchelder", out[3])
+
+ def test_more_metadata(self):
+ from setup import setup_args
+
+ classifiers = setup_args['classifiers']
+ self.assertGreater(len(classifiers), 7)
+ self.assertTrue(classifiers[-1].startswith("Development Status ::"))
+
+ long_description = setup_args['long_description'].splitlines()
+ self.assertGreater(len(long_description), 7)
+ self.assertNotEqual(long_description[0].strip(), "")
+ self.assertNotEqual(long_description[-1].strip(), "")
diff --git a/test/test_oddball.py b/test/test_oddball.py
index 1a3bd22f..a8c243de 100644
--- a/test/test_oddball.py
+++ b/test/test_oddball.py
@@ -307,6 +307,7 @@ class ExceptionTest(CoverageTest):
# Clean the line data and compare to expected results.
# The filenames are absolute, so keep just the base.
+ cov._harvest_data() # private! sshhh...
lines = cov.data.line_data()
clean_lines = {}
for f, llist in lines.items():
diff --git a/test/test_phystokens.py b/test/test_phystokens.py
index 0e778510..d4e417e8 100644
--- a/test/test_phystokens.py
+++ b/test/test_phystokens.py
@@ -37,8 +37,8 @@ class PhysTokensTest(CoverageTest):
# source_token_lines doesn't preserve trailing spaces, so trim all that
# before comparing.
source = source.replace('\r\n', '\n')
- source = re.sub("(?m)[ \t]+$", "", source)
- tokenized = re.sub("(?m)[ \t]+$", "", tokenized)
+ source = re.sub(r"(?m)[ \t]+$", "", source)
+ tokenized = re.sub(r"(?m)[ \t]+$", "", tokenized)
self.assertMultiLineEqual(source, tokenized)
def check_file_tokenization(self, fname):
diff --git a/test/test_process.py b/test/test_process.py
index f8d1b8d1..2d926038 100644
--- a/test/test_process.py
+++ b/test/test_process.py
@@ -175,8 +175,8 @@ class ProcessTest(CoverageTest):
data.read_file(".coverage")
summary = data.summary(fullpath=True)
self.assertEqual(len(summary), 1)
- actual = os.path.abspath(list(summary.keys())[0])
- expected = os.path.abspath('src/x.py')
+ actual = os.path.normcase(os.path.abspath(list(summary.keys())[0]))
+ expected = os.path.normcase(os.path.abspath('src/x.py'))
self.assertEqual(actual, expected)
self.assertEqual(list(summary.values())[0], 6)
@@ -190,7 +190,7 @@ class ProcessTest(CoverageTest):
os.remove("fleeting.py")
out = self.run_command("coverage html -d htmlcov")
self.assertRegexpMatches(out, "No source for code: '.*fleeting.py'")
- self.assertFalse("Traceback" in out)
+ self.assertNotIn("Traceback", out)
# It happens that the code paths are different for *.py and other
# files, so try again with no extension.
@@ -202,13 +202,13 @@ class ProcessTest(CoverageTest):
os.remove("fleeting")
status, out = self.run_command_status("coverage html -d htmlcov", 1)
self.assertRegexpMatches(out, "No source for code: '.*fleeting'")
- self.assertFalse("Traceback" in out)
+ self.assertNotIn("Traceback", out)
self.assertEqual(status, 1)
def test_running_missing_file(self):
status, out = self.run_command_status("coverage run xyzzy.py", 1)
self.assertRegexpMatches(out, "No file to run: .*xyzzy.py")
- self.assertFalse("Traceback" in out)
+ self.assertNotIn("Traceback", out)
self.assertEqual(status, 1)
def test_code_throws(self):
@@ -233,9 +233,9 @@ class ProcessTest(CoverageTest):
self.assertMultiLineEqual(out, out2)
# But also make sure that the output is what we expect.
- self.assertTrue('File "throw.py", line 5, in f2' in out)
- self.assertTrue('raise Exception("hey!")' in out)
- self.assertFalse('coverage' in out)
+ self.assertIn('File "throw.py", line 5, in f2', out)
+ self.assertIn('raise Exception("hey!")', out)
+ self.assertNotIn('coverage', out)
self.assertEqual(status, 1)
def test_code_exits(self):
@@ -290,6 +290,15 @@ class ProcessTest(CoverageTest):
out2 = self.run_command("python -m test.try_execfile")
self.assertMultiLineEqual(out, out2)
+ if 0:
+ # For https://bitbucket.org/ned/coveragepy/issue/207
+ def test_coverage_run_dashm_is_like_python_dashm_with__main__(self):
+ self.make_file("package/__init__.py") # empty
+ self.make_file("package/__main__.py", "#\n") # empty
+ out = self.run_command("coverage run -m package")
+ out2 = self.run_command("python -m package")
+ self.assertMultiLineEqual(out, out2)
+
if hasattr(os, 'fork'):
def test_fork(self):
self.make_file("fork.py", """\
@@ -337,25 +346,27 @@ class ProcessTest(CoverageTest):
""")
out = self.run_command("coverage run --source=sys,xyzzy,quux hello.py")
- self.assertTrue("Hello\n" in out)
- self.assertTrue(textwrap.dedent("""\
+ self.assertIn("Hello\n", out)
+ self.assertIn(textwrap.dedent("""\
Coverage.py warning: Module sys has no Python source.
Coverage.py warning: Module xyzzy was never imported.
Coverage.py warning: Module quux was never imported.
Coverage.py warning: No data was collected.
- """) in out)
+ """), out)
def test_warnings_if_never_run(self):
out = self.run_command("coverage run i_dont_exist.py")
- self.assertTrue("No file to run: 'i_dont_exist.py'" in out)
- self.assertTrue("warning" not in out)
+ self.assertIn("No file to run: 'i_dont_exist.py'", out)
+ self.assertNotIn("warning", out)
+ self.assertNotIn("Exception", out)
out = self.run_command("coverage run -m no_such_module")
self.assertTrue(
("No module named no_such_module" in out) or
("No module named 'no_such_module'" in out)
)
- self.assertTrue("warning" not in out)
+ self.assertNotIn("warning", out)
+ self.assertNotIn("Exception", out)
if sys.version_info >= (3, 0): # This only works on 3.x for now.
# It only works with the C tracer.
@@ -382,3 +393,59 @@ class ProcessTest(CoverageTest):
# imported is 120 or so. Just running os.getenv executes
# about 5.
self.assertGreater(data.summary()['os.py'], 50)
+
+
+class AliasedCommandTests(CoverageTest):
+ """Tests of the version-specific command aliases."""
+
+ def test__major_version_works(self):
+ # "coverage2" works on py2
+ cmd = "coverage%d" % sys.version_info[0]
+ out = self.run_command(cmd)
+ self.assertIn("Code coverage for Python", out)
+
+ def test_wrong_alias_doesnt_work(self):
+ # "coverage3" doesn't work on py2
+ badcmd = "coverage%d" % (5 - sys.version_info[0])
+ out = self.run_command(badcmd)
+ self.assertNotIn("Code coverage for Python", out)
+
+ def test_specific_alias_works(self):
+ # "coverage-2.7" works on py2.7
+ cmd = "coverage-%d.%d" % sys.version_info[:2]
+ out = self.run_command(cmd)
+ self.assertIn("Code coverage for Python", out)
+
+
+class FailUnderTest(CoverageTest):
+ """Tests of the --fail-under switch."""
+
+ def setUp(self):
+ super(FailUnderTest, self).setUp()
+ self.make_file("fifty.py", """\
+ # I have 50% coverage!
+ a = 1
+ if a > 2:
+ b = 3
+ c = 4
+ """)
+ st, _ = self.run_command_status("coverage run fifty.py", 0)
+ self.assertEqual(st, 0)
+
+ def test_report(self):
+ st, _ = self.run_command_status("coverage report --fail-under=50", 0)
+ self.assertEqual(st, 0)
+ st, _ = self.run_command_status("coverage report --fail-under=51", 2)
+ self.assertEqual(st, 2)
+
+ def test_html_report(self):
+ st, _ = self.run_command_status("coverage html --fail-under=50", 0)
+ self.assertEqual(st, 0)
+ st, _ = self.run_command_status("coverage html --fail-under=51", 2)
+ self.assertEqual(st, 2)
+
+ def test_xml_report(self):
+ st, _ = self.run_command_status("coverage xml --fail-under=50", 0)
+ self.assertEqual(st, 0)
+ st, _ = self.run_command_status("coverage xml --fail-under=51", 2)
+ self.assertEqual(st, 2)
diff --git a/test/test_summary.py b/test/test_summary.py
index 71fbb1a6..b460c2dc 100644
--- a/test/test_summary.py
+++ b/test/test_summary.py
@@ -25,7 +25,7 @@ class SummaryTest(CoverageTest):
def report_from_command(self, cmd):
"""Return the report from the `cmd`, with some convenience added."""
report = self.run_command(cmd).replace('\\', '/')
- self.assertFalse("error" in report.lower())
+ self.assertNotIn("error", report.lower())
return report
def line_count(self, report):
@@ -51,10 +51,10 @@ class SummaryTest(CoverageTest):
# ---------------------------------------------------------------------
# TOTAL 8 0 100%
- self.assertFalse("/coverage/__init__/" in report)
- self.assertTrue("/test/modules/covmod1 " in report)
- self.assertTrue("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/__init__/", report)
+ self.assertIn("/test/modules/covmod1 ", report)
+ self.assertIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "TOTAL 8 0 100%")
def test_report_just_one(self):
@@ -67,10 +67,10 @@ class SummaryTest(CoverageTest):
# mycode 4 0 100%
self.assertEqual(self.line_count(report), 3)
- self.assertFalse("/coverage/" in report)
- self.assertFalse("/test/modules/covmod1 " in report)
- self.assertFalse("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/", report)
+ self.assertNotIn("/test/modules/covmod1 ", report)
+ self.assertNotIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "mycode 4 0 100%")
def test_report_omitting(self):
@@ -84,10 +84,10 @@ class SummaryTest(CoverageTest):
# mycode 4 0 100%
self.assertEqual(self.line_count(report), 3)
- self.assertFalse("/coverage/" in report)
- self.assertFalse("/test/modules/covmod1 " in report)
- self.assertFalse("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/", report)
+ self.assertNotIn("/test/modules/covmod1 ", report)
+ self.assertNotIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "mycode 4 0 100%")
def test_report_including(self):
@@ -100,10 +100,10 @@ class SummaryTest(CoverageTest):
# mycode 4 0 100%
self.assertEqual(self.line_count(report), 3)
- self.assertFalse("/coverage/" in report)
- self.assertFalse("/test/modules/covmod1 " in report)
- self.assertFalse("/test/zipmods.zip/covmodzip1 " in report)
- self.assertTrue("mycode " in report)
+ self.assertNotIn("/coverage/", report)
+ self.assertNotIn("/test/modules/covmod1 ", report)
+ self.assertNotIn("/test/zipmods.zip/covmodzip1 ", report)
+ self.assertIn("mycode ", report)
self.assertEqual(self.last_line_squeezed(report), "mycode 4 0 100%")
def test_report_branches(self):
@@ -118,12 +118,12 @@ class SummaryTest(CoverageTest):
self.assertEqual(out, 'x\n')
report = self.report_from_command("coverage report")
- # Name Stmts Miss Branch BrPart Cover
+ # Name Stmts Miss Branch BrMiss Cover
# --------------------------------------------
# mybranch 5 0 2 1 85%
self.assertEqual(self.line_count(report), 3)
- self.assertTrue("mybranch " in report)
+ self.assertIn("mybranch ", report)
self.assertEqual(self.last_line_squeezed(report),
"mybranch 5 0 2 1 86%")
@@ -135,15 +135,16 @@ class SummaryTest(CoverageTest):
self.make_file("mycode.py", "This isn't python at all!")
report = self.report_from_command("coverage -r mycode.py")
+ # pylint: disable=C0301
# Name Stmts Miss Cover
# ----------------------------
# mycode NotPython: Couldn't parse '/tmp/test_cover/63354509363/mycode.py' as Python source: 'invalid syntax' at line 1
last = self.last_line_squeezed(report)
# The actual file name varies run to run.
- last = re.sub("parse '.*mycode.py", "parse 'mycode.py", last)
+ last = re.sub(r"parse '.*mycode.py", "parse 'mycode.py", last)
# The actual error message varies version to version
- last = re.sub(": '.*' at", ": 'error' at", last)
+ last = re.sub(r": '.*' at", ": 'error' at", last)
self.assertEqual(last,
"mycode NotPython: "
"Couldn't parse 'mycode.py' as Python source: "
@@ -178,6 +179,58 @@ class SummaryTest(CoverageTest):
self.assertEqual(self.line_count(report), 2)
+ def get_report(self, cov):
+ """Get the report from `cov`, and canonicalize it."""
+ repout = StringIO()
+ cov.report(file=repout, show_missing=False)
+ report = repout.getvalue().replace('\\', '/')
+ report = re.sub(r" +", " ", report)
+ return report
+
+ def test_bug_156_file_not_run_should_be_zero(self):
+ # https://bitbucket.org/ned/coveragepy/issue/156
+ self.make_file("mybranch.py", """\
+ def branch(x):
+ if x:
+ print("x")
+ return x
+ branch(1)
+ """)
+ self.make_file("main.py", """\
+ print("y")
+ """)
+ cov = coverage.coverage(branch=True, source=["."])
+ cov.start()
+ import main # pylint: disable=F0401,W0612
+ cov.stop()
+ report = self.get_report(cov).splitlines()
+ self.assertIn("mybranch 5 5 2 2 0%", report)
+
+ def run_TheCode_and_report_it(self):
+ """A helper for the next few tests."""
+ cov = coverage.coverage()
+ cov.start()
+ import TheCode # pylint: disable=F0401,W0612
+ cov.stop()
+ return self.get_report(cov)
+
+ def test_bug_203_mixed_case_listed_twice_with_rc(self):
+ self.make_file("TheCode.py", "a = 1\n")
+ self.make_file(".coveragerc", "[run]\nsource = .\n")
+
+ report = self.run_TheCode_and_report_it()
+
+ self.assertIn("TheCode", report)
+ self.assertNotIn("thecode", report)
+
+ def test_bug_203_mixed_case_listed_twice(self):
+ self.make_file("TheCode.py", "a = 1\n")
+
+ report = self.run_TheCode_and_report_it()
+
+ self.assertIn("TheCode", report)
+ self.assertNotIn("thecode", report)
+
class SummaryTest2(CoverageTest):
"""Another bunch of summary tests."""
@@ -207,5 +260,42 @@ class SummaryTest2(CoverageTest):
report = repout.getvalue().replace('\\', '/')
report = re.sub(r"\s+", " ", report)
- self.assert_("test/modules/pkg1/__init__ 1 0 100%" in report)
- self.assert_("test/modules/pkg2/__init__ 0 0 100%" in report)
+ self.assertIn("test/modules/pkg1/__init__ 1 0 100%", report)
+ self.assertIn("test/modules/pkg2/__init__ 0 0 100%", report)
+
+
+class ReportingReturnValue(CoverageTest):
+ """Tests of reporting functions returning values."""
+
+ def run_coverage(self):
+ """Run coverage on doit.py and return the coverage object."""
+ self.make_file("doit.py", """\
+ a = 1
+ b = 2
+ c = 3
+ d = 4
+ if a > 10:
+ f = 6
+ g = 7
+ """)
+
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("doit")
+ cov.stop()
+ return cov
+
+ def test_report(self):
+ cov = self.run_coverage()
+ val = cov.report(include="*/doit.py")
+ self.assertAlmostEqual(val, 85.7, 1)
+
+ def test_html(self):
+ cov = self.run_coverage()
+ val = cov.html_report(include="*/doit.py")
+ self.assertAlmostEqual(val, 85.7, 1)
+
+ def test_xml(self):
+ cov = self.run_coverage()
+ val = cov.xml_report(include="*/doit.py")
+ self.assertAlmostEqual(val, 85.7, 1)
diff --git a/test/test_testing.py b/test/test_testing.py
index 316dbc1b..9943b65c 100644
--- a/test/test_testing.py
+++ b/test/test_testing.py
@@ -1,7 +1,9 @@
+# -*- coding: utf-8 -*-
"""Tests that our test infrastructure is really working!"""
import os, sys
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
+from coverage.backward import to_bytes
from backunittest import TestCase
from coveragetest import CoverageTest
@@ -92,6 +94,34 @@ class TestingTest(TestCase):
self.assertFalse(False)
self.assertRaises(AssertionError, self.assertFalse, True)
+ def test_assert_in(self):
+ self.assertIn("abc", "hello abc")
+ self.assertIn("abc", ["xyz", "abc", "foo"])
+ self.assertIn("abc", {'abc': 1, 'xyz': 2})
+ self.assertRaises(AssertionError, self.assertIn, "abc", "xyz")
+ self.assertRaises(AssertionError, self.assertIn, "abc", ["x", "xabc"])
+ self.assertRaises(AssertionError, self.assertIn, "abc", {'x':'abc'})
+
+ def test_assert_not_in(self):
+ self.assertRaises(AssertionError, self.assertNotIn, "abc", "hello abc")
+ self.assertRaises(AssertionError,
+ self.assertNotIn, "abc", ["xyz", "abc", "foo"]
+ )
+ self.assertRaises(AssertionError,
+ self.assertNotIn, "abc", {'abc': 1, 'xyz': 2}
+ )
+ self.assertNotIn("abc", "xyz")
+ self.assertNotIn("abc", ["x", "xabc"])
+ self.assertNotIn("abc", {'x':'abc'})
+
+ def test_assert_greater(self):
+ self.assertGreater(10, 9)
+ self.assertGreater("xyz", "abc")
+ self.assertRaises(AssertionError, self.assertGreater, 9, 10)
+ self.assertRaises(AssertionError, self.assertGreater, 10, 10)
+ self.assertRaises(AssertionError, self.assertGreater, "abc", "xyz")
+ self.assertRaises(AssertionError, self.assertGreater, "xyz", "xyz")
+
class CoverageTestTest(CoverageTest):
"""Test the methods in `CoverageTest`."""
@@ -122,10 +152,18 @@ class CoverageTestTest(CoverageTest):
self.make_file("mac.txt", "Hello\n", newline="\r")
self.assertEqual(self.file_text("mac.txt"), "Hello\r")
+ def test_make_file_non_ascii(self):
+ self.make_file("unicode.txt", "tabblo: «ταБЬℓσ»")
+ self.assertEqual(
+ open("unicode.txt", "rb").read(),
+ to_bytes("tabblo: «ταБЬℓσ»")
+ )
+
def test_file_exists(self):
self.make_file("whoville.txt", "We are here!")
self.assert_exists("whoville.txt")
self.assert_doesnt_exist("shadow.txt")
- self.assertRaises(AssertionError, self.assert_doesnt_exist,
- "whoville.txt")
+ self.assertRaises(
+ AssertionError, self.assert_doesnt_exist, "whoville.txt"
+ )
self.assertRaises(AssertionError, self.assert_exists, "shadow.txt")
diff --git a/test/test_xml.py b/test/test_xml.py
new file mode 100644
index 00000000..6542dcac
--- /dev/null
+++ b/test/test_xml.py
@@ -0,0 +1,89 @@
+"""Tests for XML reports from coverage.py."""
+
+import os, re, sys
+import coverage
+
+sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
+from coveragetest import CoverageTest
+
+class XmlReportTest(CoverageTest):
+ """Tests of the XML reports from coverage.py."""
+
+ def run_mycode(self):
+ """Run mycode.py, so we can report on it."""
+ self.make_file("mycode.py", "print('hello')\n")
+ self.run_command("coverage run mycode.py")
+
+ def test_default_file_placement(self):
+ self.run_mycode()
+ self.run_command("coverage xml")
+ self.assert_exists("coverage.xml")
+
+ def test_argument_affects_xml_placement(self):
+ self.run_mycode()
+ self.run_command("coverage xml -o put_it_there.xml")
+ self.assert_doesnt_exist("coverage.xml")
+ self.assert_exists("put_it_there.xml")
+
+ def test_config_affects_xml_placement(self):
+ self.run_mycode()
+ self.make_file(".coveragerc", "[xml]\noutput = xml.out\n")
+ self.run_command("coverage xml")
+ self.assert_doesnt_exist("coverage.xml")
+ self.assert_exists("xml.out")
+
+ def test_no_data(self):
+ # https://bitbucket.org/ned/coveragepy/issue/210
+ self.run_command("coverage xml")
+ self.assert_doesnt_exist("coverage.xml")
+
+ def test_no_source(self):
+ # Written while investigating a bug, might as well keep it.
+ # https://bitbucket.org/ned/coveragepy/issue/208
+ self.make_file("innocuous.py", "a = 1")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("innocuous")
+ cov.stop()
+ os.remove("innocuous.py")
+ cov.xml_report(ignore_errors=True)
+ self.assert_exists("coverage.xml")
+
+ def run_doit(self):
+ """Construct a simple sub-package."""
+ self.make_file("sub/__init__.py")
+ self.make_file("sub/doit.py", "print('doit!')")
+ self.make_file("main.py", "import sub.doit")
+ cov = coverage.coverage()
+ cov.start()
+ self.import_local_file("main")
+ cov.stop()
+ return cov
+
+ def test_filename_format_showing_everything(self):
+ cov = self.run_doit()
+ cov.xml_report(outfile="-")
+ xml = self.stdout()
+ doit_line = re_line(xml, "class.*doit")
+ self.assertIn('filename="sub/doit.py"', doit_line)
+
+ def test_filename_format_including_filename(self):
+ cov = self.run_doit()
+ cov.xml_report(["sub/doit.py"], outfile="-")
+ xml = self.stdout()
+ doit_line = re_line(xml, "class.*doit")
+ self.assertIn('filename="sub/doit.py"', doit_line)
+
+ def test_filename_format_including_module(self):
+ cov = self.run_doit()
+ import sub.doit
+ cov.xml_report([sub.doit], outfile="-")
+ xml = self.stdout()
+ doit_line = re_line(xml, "class.*doit")
+ self.assertIn('filename="sub/doit.py"', doit_line)
+
+
+def re_line(text, pat):
+ """Return the one line in `text` that matches regex `pat`."""
+ lines = [l for l in text.splitlines() if re.search(pat, l)]
+ return lines[0]