summaryrefslogtreecommitdiff
path: root/coverage
diff options
context:
space:
mode:
Diffstat (limited to 'coverage')
-rw-r--r--coverage/html.py3
-rw-r--r--coverage/parser.py28
-rw-r--r--coverage/plugin.py8
-rw-r--r--coverage/python.py4
4 files changed, 33 insertions, 10 deletions
diff --git a/coverage/html.py b/coverage/html.py
index 9471db93..d4fb7516 100644
--- a/coverage/html.py
+++ b/coverage/html.py
@@ -190,6 +190,7 @@ class HtmlReporter(Reporter):
if self.has_arcs:
missing_branch_arcs = analysis.missing_branch_arcs()
+ arcs_executed = analysis.arcs_executed()
# These classes determine which lines are highlighted by default.
c_run = "run hide_run"
@@ -219,7 +220,7 @@ class HtmlReporter(Reporter):
shorts.append("exit")
else:
shorts.append(b)
- longs.append(fr.missing_arc_description(lineno, b))
+ longs.append(fr.missing_arc_description(lineno, b, arcs_executed))
# 202F is NARROW NO-BREAK SPACE.
# 219B is RIGHTWARDS ARROW WITH STROKE.
short_fmt = "%s ↛ %s"
diff --git a/coverage/parser.py b/coverage/parser.py
index f4dd02d4..8fb5d89b 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -21,8 +21,12 @@ from coverage.phystokens import compile_unicode, generate_tokens, neuter_encodin
class PythonParser(object):
- """Parse code to find executable lines, excluded lines, etc."""
+ """Parse code to find executable lines, excluded lines, etc.
+ This information is all based on static analysis: no code execution is
+ involved.
+
+ """
@contract(text='unicode|None')
def __init__(self, text=None, filename=None, exclude=None):
"""
@@ -304,11 +308,23 @@ class PythonParser(object):
return exit_counts
- def missing_arc_description(self, start, end):
+ def missing_arc_description(self, start, end, executed_arcs=None):
"""Provide an English sentence describing a missing arc."""
if self._missing_arc_fragments is None:
self._analyze_ast()
+ actual_start = start
+
+ if (
+ executed_arcs and
+ end < 0 and end == -start and
+ (end, start) not in executed_arcs and
+ (end, start) in self._missing_arc_fragments
+ ):
+ # It's a one-line callable, and we never even started it,
+ # and we have a message about not starting it.
+ start, end = end, start
+
fragment_pairs = self._missing_arc_fragments.get((start, end), [(None, None)])
msgs = []
@@ -325,9 +341,9 @@ class PythonParser(object):
emsg = "didn't jump to line {lineno}"
emsg = emsg.format(lineno=end)
- msg = "line {start} {emsg}".format(start=start, emsg=emsg)
+ msg = "line {start} {emsg}".format(start=actual_start, emsg=emsg)
if smsg is not None:
- msg += ", because {smsg}".format(smsg=smsg.format(lineno=start))
+ msg += ", because {smsg}".format(smsg=smsg.format(lineno=actual_start))
msgs.append(msg)
@@ -939,10 +955,10 @@ class AstArcAnalyzer(object):
"""A function to make methods for online callable _code_object__ methods."""
def _code_object__oneline_callable(self, node):
start = self.line_for_node(node)
- self.add_arc(-start, start)
+ self.add_arc(-start, start, None, "didn't run the {0} on line {1}".format(noun, start))
self.add_arc(
start, -start, None,
- "didn't run the {0} on line {1}".format(noun, start),
+ "didn't finish the {0} on line {1}".format(noun, start),
)
return _code_object__oneline_callable
diff --git a/coverage/plugin.py b/coverage/plugin.py
index 97d9c16e..a7b95466 100644
--- a/coverage/plugin.py
+++ b/coverage/plugin.py
@@ -329,9 +329,15 @@ class FileReporter(object):
"""
return {}
- def missing_arc_description(self, start, end):
+ def missing_arc_description(self, start, end, executed_arcs=None): # pylint: disable=unused-argument
"""Provide an English sentence describing a missing arc.
+ The `start` and `end` arguments are the line numbers of the missing
+ arc. Negative numbers indicate entering or exiting code objects.
+
+ The `executed_arcs` argument is a set of line number pairs, the arcs
+ that were executed in this file.
+
By default, this simply returns the string "Line {start} didn't jump
to {end}".
diff --git a/coverage/python.py b/coverage/python.py
index 0d2fb3b4..0cd2181c 100644
--- a/coverage/python.py
+++ b/coverage/python.py
@@ -165,8 +165,8 @@ class PythonFileReporter(FileReporter):
def exit_counts(self):
return self.parser.exit_counts()
- def missing_arc_description(self, start, end):
- return self.parser.missing_arc_description(start, end)
+ def missing_arc_description(self, start, end, executed_arcs=None):
+ return self.parser.missing_arc_description(start, end, executed_arcs)
@contract(returns='unicode')
def source(self):