diff options
| author | Ned Batchelder <ned@nedbatchelder.com> | 2015-02-22 21:55:45 -0500 |
|---|---|---|
| committer | Ned Batchelder <ned@nedbatchelder.com> | 2015-02-22 21:55:45 -0500 |
| commit | 7fd0385cfa5b776b4c7b10c4ff077296db005c49 (patch) | |
| tree | 37567b269a2491eed276dc725234fade3d2bb0f2 | |
| parent | 1b04c715aa30a2e2a4cf3f6c3d0b65b93363c83d (diff) | |
| parent | ae8870bf5732895c1e68c6f64268a775a617f403 (diff) | |
| download | python-coveragepy-7fd0385cfa5b776b4c7b10c4ff077296db005c49.tar.gz | |
Merge other work
| -rw-r--r-- | coverage/control.py | 20 | ||||
| -rw-r--r-- | tests/plugin2.py | 8 | ||||
| -rw-r--r-- | tests/test_concurrency.py | 7 | ||||
| -rw-r--r-- | tests/test_plugins.py | 72 |
4 files changed, 91 insertions, 16 deletions
diff --git a/coverage/control.py b/coverage/control.py index 2db5802..2c0d9ed 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -18,7 +18,7 @@ from coverage.data import CoverageData from coverage.debug import DebugControl from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher from coverage.files import PathAliases, find_python_files, prep_patterns -from coverage.files import ModuleMatcher +from coverage.files import ModuleMatcher, abs_file from coverage.html import HtmlReporter from coverage.misc import CoverageException, bool_or_none, join_regex from coverage.misc import file_be_gone, overrides @@ -837,12 +837,13 @@ class Coverage(object): plugin = None if isinstance(morf, string_class): - plugin_name = self.data.plugin_data().get(morf) + abs_morf = abs_file(morf) + plugin_name = self.data.plugin_data().get(abs_morf) if plugin_name: plugin = self.plugins.get(plugin_name) if plugin: - file_reporter = plugin.file_reporter(morf) + file_reporter = plugin.file_reporter(abs_morf) if file_reporter is None: raise CoverageException( "Plugin %r did not provide a file reporter for %r." % ( @@ -852,6 +853,13 @@ class Coverage(object): else: file_reporter = PythonFileReporter(morf, self) + # The FileReporter can have a name attribute, but if it doesn't, we'll + # supply it as the relative path to self.filename. + if not hasattr(file_reporter, "name"): + file_reporter.name = self.file_locator.relative_filename( + file_reporter.filename + ) + return file_reporter def _get_file_reporters(self, morfs=None): @@ -889,9 +897,9 @@ class Coverage(object): Each module in `morfs` is listed, with counts of statements, executed statements, missing statements, and a list of lines missed. - `include` is a list of filename patterns. Modules whose filenames - match those patterns will be included in the report. Modules matching - `omit` will not be included in the report. + `include` is a list of filename patterns. Files that match will be + included in the report. Files matching `omit` will not be included in + the report. Returns a float, the total percentage covered. diff --git a/tests/plugin2.py b/tests/plugin2.py index 9d47d26..658ee22 100644 --- a/tests/plugin2.py +++ b/tests/plugin2.py @@ -1,5 +1,7 @@ """A plugin for test_plugins.py to import.""" +import os.path + import coverage # pylint: disable=missing-docstring @@ -23,16 +25,16 @@ class RenderFileTracer(coverage.plugin.FileTracer): def dynamic_source_filename(self, filename, frame): if frame.f_code.co_name != "render": return None - return frame.f_locals['filename'] + return os.path.abspath(frame.f_locals['filename']) def line_number_range(self, frame): lineno = frame.f_locals['linenum'] - return lineno,lineno+1 + return lineno, lineno+1 class FileReporter(coverage.plugin.FileReporter): def statements(self): # Goofy test arrangement: claim that the file has as many lines as the # number in its name. - num = self.filename.split(".")[0].split("_")[1] + num = os.path.basename(self.filename).split(".")[0].split("_")[1] return set(range(1, int(num)+1)) diff --git a/tests/test_concurrency.py b/tests/test_concurrency.py index 9a82a0c..93809df 100644 --- a/tests/test_concurrency.py +++ b/tests/test_concurrency.py @@ -239,7 +239,7 @@ class MultiprocessingTest(CoverageTest): def func(x): # Need to pause, or the tasks go too quick, and some processes # in the pool don't get any work, and then don't record data. - time.sleep(0.01) + time.sleep(0.02) # Use different lines in different subprocesses. if x % 2: y = x*x @@ -249,7 +249,7 @@ class MultiprocessingTest(CoverageTest): if __name__ == "__main__": pool = multiprocessing.Pool(3) - inputs = range(20) + inputs = range(30) outputs = pool.imap_unordered(func, inputs) pids = set() total = 0 @@ -264,8 +264,7 @@ class MultiprocessingTest(CoverageTest): out = self.run_command( "coverage run --concurrency=multiprocessing multi.py" ) - os.system("cp .cov* /tmp") - total = sum(x*x if x%2 else x*x*x for x in range(20)) + total = sum(x*x if x%2 else x*x*x for x in range(30)) self.assertEqual(out.rstrip(), "3 pids, total = %d" % total) self.run_command("coverage combine") diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 2d12a3c..88c653c 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -316,9 +316,18 @@ class GoodPluginTest(FileTracerTest): # In Python 2, either kind of string should be OK. if sys.version_info[0] == 2: - assert render(u"unicode_3.html", 2) == "[unicode_3.html @ 2]" + assert render(u"uni_3.html", 2) == "[uni_3.html @ 2]" """) + # will try to read the actual source files, so make some + # source files. + def lines(n): + """Make a string with n lines of text.""" + return "".join("line %d\n" % i for i in range(n)) + + self.make_file("bar_4.html", lines(4)) + self.make_file("foo_7.html", lines(7)) + def test_plugin2(self): self.make_render_and_caller() @@ -345,10 +354,10 @@ class GoodPluginTest(FileTracerTest): self.assertNotIn("quux_5.html", cov.data.summary()) if env.PY2: - _, statements, missing, _ = cov.analysis("unicode_3.html") + _, statements, missing, _ = cov.analysis("uni_3.html") self.assertEqual(statements, [1, 2, 3]) self.assertEqual(missing, [1]) - self.assertIn("unicode_3.html", cov.data.summary()) + self.assertIn("uni_3.html", cov.data.summary()) def test_plugin2_with_branch(self): self.make_render_and_caller() @@ -371,6 +380,63 @@ class GoodPluginTest(FileTracerTest): self.assertEqual(analysis.missing, set([1, 2, 3, 6, 7])) + def test_plugin2_with_text_report(self): + self.make_render_and_caller() + + cov = coverage.Coverage(branch=True, omit=["*quux*"]) + cov.config["run:plugins"] = ["tests.plugin2"] + + self.start_import_stop(cov, "caller") + + repout = StringIO() + total = cov.report(file=repout, include=["*.html"], omit=["uni*.html"]) + report = repout.getvalue().splitlines() + expected = [ + 'Name Stmts Miss Branch BrPart Cover Missing', + '--------------------------------------------------------', + 'bar_4.html 4 2 0 0 50% 1, 4', + 'foo_7.html 7 5 0 0 29% 1-3, 6-7', + '--------------------------------------------------------', + 'TOTAL 11 7 0 0 36% ', + ] + self.assertEqual(report, expected) + self.assertAlmostEqual(total, 36.36, places=2) + + def test_plugin2_with_html_report(self): + self.make_render_and_caller() + + cov = coverage.Coverage(branch=True, omit=["*quux*"]) + cov.config["run:plugins"] = ["tests.plugin2"] + + self.start_import_stop(cov, "caller") + + total = cov.html_report(include=["*.html"], omit=["uni*.html"]) + self.assertAlmostEqual(total, 36.36, places=2) + + self.assert_exists("htmlcov/index.html") + self.assert_exists("htmlcov/bar_4_html.html") + self.assert_exists("htmlcov/foo_7_html.html") + + def test_plugin2_with_xml_report(self): + self.make_render_and_caller() + + cov = coverage.Coverage(branch=True, omit=["*quux*"]) + cov.config["run:plugins"] = ["tests.plugin2"] + + self.start_import_stop(cov, "caller") + + total = cov.xml_report(include=["*.html"], omit=["uni*.html"]) + self.assertAlmostEqual(total, 36.36, places=2) + + with open("coverage.xml") as fxml: + xml = fxml.read() + + for snip in [ + 'filename="bar_4.html" line-rate="0.5" name="bar_4.html"', + 'filename="foo_7.html" line-rate="0.2857" name="foo_7.html"', + ]: + self.assertIn(snip, xml) + class BadPluginTest(FileTracerTest): """Test error handling around plugins.""" |
