summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.rst4
-rw-r--r--coverage/results.py78
-rw-r--r--coverage/summary.py9
-rw-r--r--tests/test_coverage.py10
-rw-r--r--tests/test_results.py24
-rw-r--r--tests/test_summary.py2
6 files changed, 77 insertions, 50 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index b00d0f2b..ab49f22a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -19,6 +19,10 @@ Unreleased
- ``fail_under`` values more than 100 are reported as errors. Thanks to Mike
Fiedler for closing `issue 746`_.
+- The "missing" values in the text output are now sorted by line number, so
+ that missing branches are reported near the other lines they affect. The
+ values used to show all missing lines, and then all missing branches.
+
.. _issue 746: https://github.com/nedbat/coveragepy/issues/746
diff --git a/coverage/results.py b/coverage/results.py
index f7e0ae56..529899de 100644
--- a/coverage/results.py
+++ b/coverage/results.py
@@ -49,13 +49,20 @@ class Analysis(object):
n_missing_branches=n_missing_branches,
)
- def missing_formatted(self):
+ def missing_formatted(self, branches=False):
"""The missing line numbers, formatted nicely.
Returns a string like "1-2, 5-11, 13-14".
+ If `branches` is true, includes the missing branch arcs also.
+
"""
- return format_lines(self.statements, self.missing)
+ if branches and self.has_arcs():
+ arcs = iitems(self.missing_branch_arcs())
+ else:
+ arcs = None
+
+ return format_lines(self.statements, self.missing, arcs=arcs)
def has_arcs(self):
"""Were arcs measured in this result?"""
@@ -82,24 +89,6 @@ class Analysis(object):
)
return sorted(missing)
- def arcs_missing_formatted(self):
- """The missing branch arcs, formatted nicely.
-
- Returns a string like "1->2, 1->3, 16->20". Omits any mention of
- branches from missing lines, so if line 17 is missing, then 17->18
- won't be included.
-
- """
- arcs = self.missing_branch_arcs()
- missing = self.missing
- line_exits = sorted(iitems(arcs))
- pairs = []
- for line, exits in line_exits:
- for ex in sorted(exits):
- if line not in missing:
- pairs.append("%d->%s" % (line, (ex if ex > 0 else "exit")))
- return ', '.join(pairs)
-
def arcs_unpredicted(self):
"""Returns a sorted list of the executed arcs missing from the code."""
possible = self.arc_possibilities()
@@ -272,21 +261,8 @@ class Numbers(SimpleReprMixin):
return NotImplemented
-def format_lines(statements, lines):
- """Nicely format a list of line numbers.
-
- Format a list of line numbers for printing by coalescing groups of lines as
- long as the lines represent consecutive statements. This will coalesce
- even if there are gaps between statements.
-
- For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and
- `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14".
-
- Both `lines` and `statements` can be any iterable. All of the elements of
- `lines` must be in `statements`, and all of the values must be positive
- integers.
-
- """
+def _line_ranges(statements, lines):
+ """Produce a list of ranges for `format_lines`."""
statements = sorted(statements)
lines = sorted(lines)
@@ -306,7 +282,37 @@ def format_lines(statements, lines):
start = None
if start:
pairs.append((start, end))
- ret = ', '.join(map(nice_pair, pairs))
+ return pairs
+
+
+def format_lines(statements, lines, arcs=None):
+ """Nicely format a list of line numbers.
+
+ Format a list of line numbers for printing by coalescing groups of lines as
+ long as the lines represent consecutive statements. This will coalesce
+ even if there are gaps between statements.
+
+ For example, if `statements` is [1,2,3,4,5,10,11,12,13,14] and
+ `lines` is [1,2,5,10,11,13,14] then the result will be "1-2, 5-11, 13-14".
+
+ Both `lines` and `statements` can be any iterable. All of the elements of
+ `lines` must be in `statements`, and all of the values must be positive
+ integers.
+
+ If `arcs` is provided, they are (start,[end,end,end]) pairs that will be
+ included in the output as long as start isn't in `lines`.
+
+ """
+ line_items = [(pair[0], 0, nice_pair(pair)) for pair in _line_ranges(statements, lines)]
+ if arcs:
+ line_exits = sorted(arcs)
+ for line, exits in line_exits:
+ for ex in sorted(exits):
+ if line not in lines:
+ dest = (ex if ex > 0 else "exit")
+ line_items.append((line, 1, "%d->%s" % (line, dest)))
+
+ ret = ', '.join(t[-1] for t in sorted(line_items))
return ret
diff --git a/coverage/summary.py b/coverage/summary.py
index 95afbcf0..e79592b9 100644
--- a/coverage/summary.py
+++ b/coverage/summary.py
@@ -110,14 +110,7 @@ class SummaryReporter(Reporter):
args += (nums.n_branches, nums.n_partial_branches)
args += (nums.pc_covered_str,)
if self.config.show_missing:
- missing_fmtd = analysis.missing_formatted()
- if self.branches:
- branches_fmtd = analysis.arcs_missing_formatted()
- if branches_fmtd:
- if missing_fmtd:
- missing_fmtd += ", "
- missing_fmtd += branches_fmtd
- args += (missing_fmtd,)
+ args += (analysis.missing_formatted(branches=True),)
text = fmt_coverage % args
# Add numeric percent coverage so that sorting makes sense.
args += (nums.pc_covered,)
diff --git a/tests/test_coverage.py b/tests/test_coverage.py
index 947c5f1e..1b23f408 100644
--- a/tests/test_coverage.py
+++ b/tests/test_coverage.py
@@ -677,7 +677,7 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert x == 3
""",
- [1,2,3,4,5,7,8], "4-7", report="7 3 4 1 45% 4-7, 2->4",
+ [1,2,3,4,5,7,8], "4-7", report="7 3 4 1 45% 2->4, 4-7",
)
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -689,7 +689,7 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert y == 5
""",
- [1,2,3,4,5,7,8], "3, 7", report="7 2 4 2 64% 3, 7, 2->3, 4->7",
+ [1,2,3,4,5,7,8], "3, 7", report="7 2 4 2 64% 2->3, 3, 4->7, 7",
)
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -701,7 +701,7 @@ class CompoundStatementTest(CoverageTest):
z = 7
assert z == 7
""",
- [1,2,3,4,5,7,8], "3, 5", report="7 2 4 2 64% 3, 5, 2->3, 4->5",
+ [1,2,3,4,5,7,8], "3, 5", report="7 2 4 2 64% 2->3, 3, 4->5, 5",
)
def test_elif_no_else(self):
@@ -713,7 +713,7 @@ class CompoundStatementTest(CoverageTest):
y = 5
assert x == 3
""",
- [1,2,3,4,5,6], "4-5", report="6 2 4 1 50% 4-5, 2->4",
+ [1,2,3,4,5,6], "4-5", report="6 2 4 1 50% 2->4, 4-5",
)
self.check_coverage("""\
a = 1; b = 2; c = 3;
@@ -723,7 +723,7 @@ class CompoundStatementTest(CoverageTest):
y = 5
assert y == 5
""",
- [1,2,3,4,5,6], "3", report="6 1 4 2 70% 3, 2->3, 4->6",
+ [1,2,3,4,5,6], "3", report="6 1 4 2 70% 2->3, 3, 4->6",
)
def test_elif_bizarre(self):
diff --git a/tests/test_results.py b/tests/test_results.py
index 8acbcaec..41494e66 100644
--- a/tests/test_results.py
+++ b/tests/test_results.py
@@ -124,3 +124,27 @@ def test_should_fail_under_invalid_value():
])
def test_format_lines(statements, lines, result):
assert format_lines(statements, lines) == result
+
+
+@pytest.mark.parametrize("statements, lines, arcs, result", [
+ (
+ set([1,2,3,4,5,10,11,12,13,14]),
+ set([1,2,5,10,11,13,14]),
+ (),
+ "1-2, 5-11, 13-14"
+ ),
+ (
+ [1,2,3,4,5,10,11,12,13,14,98,99],
+ [1,2,5,10,11,13,14,99],
+ [(3, [4]), (98, [100, -1])],
+ "1-2, 3->4, 5-11, 13-14, 98->100, 98->exit, 99"
+ ),
+ (
+ [1,2,3,4,98,99,100,101,102,103,104],
+ [1,2,99,102,103,104],
+ [(3, [4]), (104, [-1])],
+ "1-2, 3->4, 99, 102-104"
+ ),
+])
+def test_format_lines_with_arcs(statements, lines, arcs, result):
+ assert format_lines(statements, lines, arcs) == result
diff --git a/tests/test_summary.py b/tests/test_summary.py
index 60a96e64..8dd56e64 100644
--- a/tests/test_summary.py
+++ b/tests/test_summary.py
@@ -263,7 +263,7 @@ class SummaryTest(UsingModulesMixin, CoverageTest):
'Name Stmts Miss Branch BrPart Cover Missing',
'---------------------------------------------------------',
'main.py 1 0 0 0 100%',
- 'mybranch.py 10 2 8 3 61% 7-8, 2->4, 4->6, 6->7',
+ 'mybranch.py 10 2 8 3 61% 2->4, 4->6, 6->7, 7-8',
'---------------------------------------------------------',
'TOTAL 11 2 8 3 63%',
]