diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2012-11-19 21:58:40 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2012-11-19 21:58:40 -0500 |
commit | dc438780abf10e5257bb177728066e16201e3916 (patch) | |
tree | 172dc6b0d7929fb0fade8562e2e7734c985de532 | |
parent | c405d15412a1e8f2d14ee0ecea9c5d4fe55641de (diff) | |
download | python-coveragepy-git-dc438780abf10e5257bb177728066e16201e3916.tar.gz |
Branch coverage is computed more accurately, #156.
-rw-r--r-- | CHANGES.txt | 6 | ||||
-rw-r--r-- | coverage/html.py | 3 | ||||
-rw-r--r-- | coverage/htmlfiles/index.html | 4 | ||||
-rw-r--r-- | coverage/htmlfiles/pyfile.html | 2 | ||||
-rw-r--r-- | coverage/results.py | 17 | ||||
-rw-r--r-- | coverage/summary.py | 2 | ||||
-rw-r--r-- | test/test_api.py | 3 | ||||
-rw-r--r-- | test/test_summary.py | 36 |
8 files changed, 53 insertions, 20 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index e129a910..695b4155 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -27,6 +27,11 @@ Version 3.6b1 - Embarrassingly, the `[xml] output=' setting in the .coveragerc file simply didn't work. Now it does. +- Coverage percentage metrics are computed slightly differently under branch + coverage. This means that completely unexecuted files will now correctly + have 0% coverage, fixing `issue 156`_. This also means that your total + coverage numbers will be lower in general if you are using branch coverage. + - When installing, now in addition to creating a "coverage" command, two new aliases are also installed. A "coverage2" or "coverage3" command will be created, depending on whether you are installing in Python 2.x or 3.x. @@ -69,6 +74,7 @@ Version 3.6b1 .. _issue 139: https://bitbucket.org/ned/coveragepy/issue/139/easy-check-for-a-certain-coverage-in-tests .. _issue 143: https://bitbucket.org/ned/coveragepy/issue/143/omit-doesnt-seem-to-work-in-coverage .. _issue 153: https://bitbucket.org/ned/coveragepy/issue/153/non-existent-filename-triggers +.. _issue 156: https://bitbucket.org/ned/coveragepy/issue/156/a-completely-unexecuted-file-shows-14 .. _issue 163: https://bitbucket.org/ned/coveragepy/issue/163/problem-with-include-and-omit-filename .. _issue 171: https://bitbucket.org/ned/coveragepy/issue/171/how-to-contribute-and-run-tests .. _issue 193: https://bitbucket.org/ned/coveragepy/issue/193/unicodedecodeerror-on-htmlpy diff --git a/coverage/html.py b/coverage/html.py index 6a6c648e..ed8920f2 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -162,7 +162,6 @@ class HtmlReporter(Reporter): nums = analysis.numbers missing_branch_arcs = analysis.missing_branch_arcs() - n_par = 0 # accumulated below. arcs = self.arcs # These classes determine which lines are highlighted by default. @@ -187,7 +186,6 @@ class HtmlReporter(Reporter): line_class.append(c_mis) elif self.arcs and lineno in missing_branch_arcs: line_class.append(c_par) - n_par += 1 annlines = [] for b in missing_branch_arcs[lineno]: if b < 0: @@ -234,7 +232,6 @@ class HtmlReporter(Reporter): # Save this file's information for the index file. index_info = { 'nums': nums, - 'par': n_par, 'html_filename': html_filename, 'name': cu.name, } diff --git a/coverage/htmlfiles/index.html b/coverage/htmlfiles/index.html index 5a7c8c2e..c649a83c 100644 --- a/coverage/htmlfiles/index.html +++ b/coverage/htmlfiles/index.html @@ -69,7 +69,7 @@ <td>{{totals.n_excluded}}</td> {% if arcs %} <td>{{totals.n_branches}}</td> - <td>{{totals.n_missing_branches}}</td> + <td>{{totals.n_partial_branches}}</td> {% endif %} <td class='right'>{{totals.pc_covered_str}}%</td> </tr> @@ -83,7 +83,7 @@ <td>{{file.nums.n_excluded}}</td> {% if arcs %} <td>{{file.nums.n_branches}}</td> - <td>{{file.nums.n_missing_branches}}</td> + <td>{{file.nums.n_partial_branches}}</td> {% endif %} <td class='right'>{{file.nums.pc_covered_str}}%</td> </tr> diff --git a/coverage/htmlfiles/pyfile.html b/coverage/htmlfiles/pyfile.html index 490fad86..525939f8 100644 --- a/coverage/htmlfiles/pyfile.html +++ b/coverage/htmlfiles/pyfile.html @@ -32,7 +32,7 @@ <span class='{{c_mis}} shortkey_m button_toggle_mis'>{{nums.n_missing}} missing</span> <span class='{{c_exc}} shortkey_x button_toggle_exc'>{{nums.n_excluded}} excluded</span> {% if arcs %} - <span class='{{c_par}} shortkey_p button_toggle_par'>{{n_par}} partial</span> + <span class='{{c_par}} shortkey_p button_toggle_par'>{{nums.n_partial_branches}} partial</span> {% endif %} </h2> </div> diff --git a/coverage/results.py b/coverage/results.py index b39966ca..ae22e1c3 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -41,11 +41,12 @@ class Analysis(object): ) n_branches = self.total_branches() mba = self.missing_branch_arcs() - n_missing_branches = sum( + n_partial_branches = sum( [len(v) for k,v in iitems(mba) if k not in self.missing] ) + n_missing_branches = sum([len(v) for k,v in iitems(mba)]) else: - n_branches = n_missing_branches = 0 + n_branches = n_partial_branches = n_missing_branches = 0 self.no_branch = set() self.numbers = Numbers( @@ -54,6 +55,7 @@ class Analysis(object): n_excluded=len(self.excluded), n_missing=len(self.missing), n_branches=n_branches, + n_partial_branches=n_partial_branches, n_missing_branches=n_missing_branches, ) @@ -166,13 +168,14 @@ class Numbers(object): _near100 = 99.0 def __init__(self, n_files=0, n_statements=0, n_excluded=0, n_missing=0, - n_branches=0, n_missing_branches=0 + n_branches=0, n_partial_branches=0, n_missing_branches=0 ): self.n_files = n_files self.n_statements = n_statements self.n_excluded = n_excluded self.n_missing = n_missing self.n_branches = n_branches + self.n_partial_branches = n_partial_branches self.n_missing_branches = n_missing_branches def set_precision(cls, precision): @@ -236,8 +239,12 @@ class Numbers(object): nums.n_excluded = self.n_excluded + other.n_excluded nums.n_missing = self.n_missing + other.n_missing nums.n_branches = self.n_branches + other.n_branches - nums.n_missing_branches = (self.n_missing_branches + - other.n_missing_branches) + nums.n_partial_branches = ( + self.n_partial_branches + other.n_partial_branches + ) + nums.n_missing_branches = ( + self.n_missing_branches + other.n_missing_branches + ) return nums def __radd__(self, other): diff --git a/coverage/summary.py b/coverage/summary.py index 03648e5f..4b1cd14e 100644 --- a/coverage/summary.py +++ b/coverage/summary.py @@ -29,7 +29,7 @@ class SummaryReporter(Reporter): header = (fmt_name % "Name") + " Stmts Miss" fmt_coverage = fmt_name + "%6d %6d" if self.branches: - header += " Branch BrPart" + header += " Branch BrMiss" fmt_coverage += " %6d %6d" width100 = Numbers.pc_str_width() header += "%*s" % (width100+4, "Cover") diff --git a/test/test_api.py b/test/test_api.py index e2ebc656..c15db5ed 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -511,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_summary.py b/test/test_summary.py index 644aa9dd..933bcbe5 100644 --- a/test/test_summary.py +++ b/test/test_summary.py @@ -118,7 +118,7 @@ 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% @@ -179,18 +179,40 @@ 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 + 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() - - repout = StringIO() - cov.report(file=repout, show_missing=False) - report = repout.getvalue().replace('\\', '/') - report = re.sub(r"\s+", " ", report) - return report + return self.get_report(cov) def test_bug_203_mixed_case_listed_twice_with_rc(self): self.make_file("TheCode.py", "a = 1\n") |