diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-11-08 13:45:20 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-11-08 13:45:20 -0500 |
commit | 824ca447ec8a5f803bc4bf6aa0d80cc90f1cf3df (patch) | |
tree | d4b979ab12279e51d6ef3c5066b2ec2ec91bacf5 | |
parent | 68cb3e52214c74cec6b94283972db7162f28c8cf (diff) | |
download | python-coveragepy-git-824ca447ec8a5f803bc4bf6aa0d80cc90f1cf3df.tar.gz |
Added branch stats to results, and the summary report includes them.
-rw-r--r-- | TODO.txt | 1 | ||||
-rw-r--r-- | coverage/results.py | 33 | ||||
-rw-r--r-- | coverage/summary.py | 38 | ||||
-rw-r--r-- | test/test_summary.py | 60 |
4 files changed, 95 insertions, 37 deletions
@@ -8,6 +8,7 @@ Coverage TODO - while TRUE claims to be partial?
+ Analysis class should do rolling up of stats also (actually Numbers)
- Update docs for --branch.
+- self.coverage.data.has_arcs is ugly.
* Speed
diff --git a/coverage/results.py b/coverage/results.py index 2374d3af..138782e6 100644 --- a/coverage/results.py +++ b/coverage/results.py @@ -35,11 +35,20 @@ class Analysis(object): exec1 = self.parser.first_lines(executed) self.missing = sorted(set(self.statements) - set(exec1)) + if self.coverage.data.has_arcs(): + n_branches = self.total_branches() + mba = self.missing_branch_arcs() + n_missing_branches = sum([len(v) for v in mba.values()]) + else: + n_branches = n_missing_branches = 0 + self.numbers = Numbers( n_files=1, n_statements=len(self.statements), n_excluded=len(self.excluded), n_missing=len(self.missing), + n_branches=n_branches, + n_missing_branches=n_missing_branches, ) def missing_formatted(self): @@ -95,6 +104,15 @@ class Analysis(object): return [l1 for l1,count in exit_counts.items() if count > 1] + def total_branches(self): + exit_counts = {} + for l1,l2 in self.arc_possibilities(): + if l1 not in exit_counts: + exit_counts[l1] = 0 + exit_counts[l1] += 1 + + return sum([count for count in exit_counts.values() if count > 1]) + def missing_branch_arcs(self): """Return arcs that weren't executed from branch lines. @@ -119,21 +137,30 @@ class Numbers(object): up statistics across files. """ - def __init__(self, n_files=0, n_statements=0, n_excluded=0, n_missing=0): + def __init__(self, n_files=0, n_statements=0, n_excluded=0, n_missing=0, + n_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_missing_branches = n_missing_branches def _get_n_executed(self): """Returns the number of executed statements.""" return self.n_statements - self.n_missing n_executed = property(_get_n_executed) + def _get_n_executed_branches(self): + """Returns the number of executed branches.""" + return self.n_branches - self.n_missing_branches + n_executed_branches = property(_get_n_executed_branches) + def _get_pc_covered(self): """Returns a single percentage value for coverage.""" if self.n_statements > 0: - pc_cov = 100.0 * self.n_executed / self.n_statements + pc_cov = 100.0 * (self.n_executed + self.n_executed_branches) / (self.n_statements + self.n_branches) else: pc_cov = 100.0 return pc_cov @@ -145,6 +172,8 @@ class Numbers(object): nums.n_statements = self.n_statements + other.n_statements 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 return nums def __radd__(self, other): diff --git a/coverage/summary.py b/coverage/summary.py index 00e4af87..e0e9eba7 100644 --- a/coverage/summary.py +++ b/coverage/summary.py @@ -12,6 +12,7 @@ class SummaryReporter(Reporter): def __init__(self, coverage, show_missing=True, ignore_errors=False): super(SummaryReporter, self).__init__(coverage, ignore_errors) self.show_missing = show_missing + self.branches = coverage.data.has_arcs() def report(self, morfs, omit_prefixes=None, outfile=None): """Writes a report summarizing coverage statistics per module.""" @@ -22,12 +23,19 @@ class SummaryReporter(Reporter): max_name = max([len(cu.name) for cu in self.code_units] + [5]) fmt_name = "%%- %ds " % max_name fmt_err = "%s %s: %s\n" - header = fmt_name % "Name" + " Stmts Exec Cover\n" - fmt_coverage = fmt_name + "% 6d % 6d % 5d%%\n" + header = (fmt_name % "Name") + " Stmts Exec" + fmt_coverage = fmt_name + "%6d %6d" + if self.branches: + header += " Branch BrExec" + fmt_coverage += " %6d %6d" + header += " Cover" + fmt_coverage += " %5d%%" if self.show_missing: - header = header.replace("\n", " Missing\n") - fmt_coverage = fmt_coverage.replace("\n", " %s\n") - rule = "-" * (len(header)-1) + "\n" + header += " Missing" + fmt_coverage += " %s" + rule = "-" * len(header) + "\n" + header += "\n" + fmt_coverage += "\n" if not outfile: outfile = sys.stdout @@ -42,12 +50,12 @@ class SummaryReporter(Reporter): try: analysis = self.coverage._analyze(cu) nums = analysis.numbers - args = ( - cu.name, nums.n_statements, nums.n_executed, - nums.pc_covered - ) + args = (cu.name, nums.n_statements, nums.n_executed) + if self.branches: + args += (nums.n_branches, nums.n_executed_branches) + args += (nums.pc_covered,) if self.show_missing: - args = args + (analysis.missing_formatted(),) + args += (analysis.missing_formatted(),) outfile.write(fmt_coverage % args) total += nums except KeyboardInterrupt: #pragma: no cover @@ -59,10 +67,10 @@ class SummaryReporter(Reporter): if total.n_files > 1: outfile.write(rule) - args = ( - "TOTAL", total.n_statements, total.n_executed, - total.pc_covered - ) + args = ("TOTAL", total.n_statements, total.n_executed) + if self.branches: + args += (total.n_branches, total.n_executed_branches) + args += (total.pc_covered,) if self.show_missing: - args = args + ("",) + args += ("",) outfile.write(fmt_coverage % args) diff --git a/test/test_summary.py b/test/test_summary.py index 1612777d..bbf5f026 100644 --- a/test/test_summary.py +++ b/test/test_summary.py @@ -36,7 +36,7 @@ class SummaryTest(CoverageTest): def test_report(self): out = self.run_command("coverage -x mycode.py") self.assertEqual(out, 'done\n') - report1 = self.report_from_command("coverage -r") + report = self.report_from_command("coverage -r") # Name Stmts Exec Cover # --------------------------------------------------------------------- @@ -46,41 +46,61 @@ class SummaryTest(CoverageTest): # --------------------------------------------------------------------- # TOTAL 8 8 100% - self.assert_("/coverage/__init__/" not in report1) - self.assert_("/test/modules/covmod1 " in report1) - self.assert_("/test/zipmods.zip/covmodzip1 " in report1) - self.assert_("mycode " in report1) - self.assertEqual(self.last_line_squeezed(report1), "TOTAL 8 8 100%") + self.assert_("/coverage/__init__/" not in report) + self.assert_("/test/modules/covmod1 " in report) + self.assert_("/test/zipmods.zip/covmodzip1 " in report) + self.assert_("mycode " in report) + self.assertEqual(self.last_line_squeezed(report), "TOTAL 8 8 100%") def test_report_just_one(self): # Try reporting just one module self.run_command("coverage -x mycode.py") - report2 = self.report_from_command("coverage -r mycode.py") + report = self.report_from_command("coverage -r mycode.py") # Name Stmts Exec Cover # ---------------------------- # mycode 4 4 100% - self.assertEqual(self.line_count(report2), 3) - self.assert_("/coverage/" not in report2) - self.assert_("/test/modules/covmod1 " not in report2) - self.assert_("/test/zipmods.zip/covmodzip1 " not in report2) - self.assert_("mycode " in report2) - self.assertEqual(self.last_line_squeezed(report2), "mycode 4 4 100%") + self.assertEqual(self.line_count(report), 3) + self.assert_("/coverage/" not in report) + self.assert_("/test/modules/covmod1 " not in report) + self.assert_("/test/zipmods.zip/covmodzip1 " not in report) + self.assert_("mycode " in report) + self.assertEqual(self.last_line_squeezed(report), "mycode 4 4 100%") def test_report_omitting(self): # Try reporting while omitting some modules prefix = os.path.split(__file__)[0] self.run_command("coverage -x mycode.py") - report3 = self.report_from_command("coverage -r -o %s" % prefix) + report = self.report_from_command("coverage -r -o %s" % prefix) # Name Stmts Exec Cover # ---------------------------- # mycode 4 4 100% - self.assertEqual(self.line_count(report3), 3) - self.assert_("/coverage/" not in report3) - self.assert_("/test/modules/covmod1 " not in report3) - self.assert_("/test/zipmods.zip/covmodzip1 " not in report3) - self.assert_("mycode " in report3) - self.assertEqual(self.last_line_squeezed(report3), "mycode 4 4 100%") + self.assertEqual(self.line_count(report), 3) + self.assert_("/coverage/" not in report) + self.assert_("/test/modules/covmod1 " not in report) + self.assert_("/test/zipmods.zip/covmodzip1 " not in report) + self.assert_("mycode " in report) + self.assertEqual(self.last_line_squeezed(report), "mycode 4 4 100%") + + def test_report_branches(self): + self.make_file("mybranch.py", """\ + def branch(x): + if x: + print("x") + return x + branch(1) + """) + out = self.run_command("coverage run --branch mybranch.py") + self.assertEqual(out, 'x\n') + report = self.report_from_command("coverage -r") + + # Name Stmts Exec Branch BrExec Cover + # -------------------------------------------- + # mybranch 5 5 4 3 88% + + self.assertEqual(self.line_count(report), 3) + self.assert_("mybranch " in report) + self.assertEqual(self.last_line_squeezed(report), "mybranch 5 5 4 3 88%") |