diff options
-rw-r--r-- | coverage/control.py | 20 | ||||
-rw-r--r-- | tests/plugin2.py | 8 | ||||
-rw-r--r-- | tests/test_plugins.py | 72 |
3 files changed, 88 insertions, 12 deletions
diff --git a/coverage/control.py b/coverage/control.py index 2db58021..2c0d9edc 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 9d47d260..658ee221 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_plugins.py b/tests/test_plugins.py index 2d12a3cd..88c653c9 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.""" |