diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/backtest.py | 2 | ||||
-rw-r--r-- | test/backunittest.py | 32 | ||||
-rw-r--r-- | test/test_api.py | 14 | ||||
-rw-r--r-- | test/test_arcs.py | 25 | ||||
-rw-r--r-- | test/test_cmdline.py | 40 | ||||
-rw-r--r-- | test/test_config.py | 20 | ||||
-rw-r--r-- | test/test_files.py | 2 | ||||
-rw-r--r-- | test/test_html.py | 103 | ||||
-rw-r--r-- | test/test_misc.py | 51 | ||||
-rw-r--r-- | test/test_oddball.py | 1 | ||||
-rw-r--r-- | test/test_phystokens.py | 4 | ||||
-rw-r--r-- | test/test_process.py | 95 | ||||
-rw-r--r-- | test/test_summary.py | 136 | ||||
-rw-r--r-- | test/test_testing.py | 42 | ||||
-rw-r--r-- | test/test_xml.py | 89 |
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 & stuff!</title>", index) + self.assertIn("<h1>Metrics & 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>«ταБЬℓσ»" + " numbers", index + ) + self.assertIn( + "<h1>«ταБЬℓσ»" + " 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>«ταБЬℓσ»" + " & stüff!</title>", index + ) + self.assertIn( + "<h1>«ταБЬℓσ»" + " & stü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] |