Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(781)

Unified Diff: tools/telemetry/third_party/coverage/coverage/results.py

Issue 1366913004: Add coverage Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/third_party/coverage/coverage/results.py
diff --git a/third_party/pycoverage/coverage/results.py b/tools/telemetry/third_party/coverage/coverage/results.py
similarity index 62%
copy from third_party/pycoverage/coverage/results.py
copy to tools/telemetry/third_party/coverage/coverage/results.py
index db6df0d30b7e389319de83ebaaf11fa4c7806e22..9627373d253b6fef3f2da3f5e195c107134c7f83 100644
--- a/third_party/pycoverage/coverage/results.py
+++ b/tools/telemetry/third_party/coverage/coverage/results.py
@@ -1,47 +1,44 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
"""Results of coverage measurement."""
-import os
+import collections
-from coverage.backward import iitems, set, sorted # pylint: disable=W0622
-from coverage.misc import format_lines, join_regex, NoSource
-from coverage.parser import CodeParser
+from coverage.backward import iitems
+from coverage.misc import format_lines
class Analysis(object):
- """The results of analyzing a code unit."""
-
- def __init__(self, cov, code_unit):
- self.coverage = cov
- self.code_unit = code_unit
-
- self.filename = self.code_unit.filename
- actual_filename, source = self.find_source(self.filename)
+ """The results of analyzing a FileReporter."""
- self.parser = CodeParser(
- text=source, filename=actual_filename,
- exclude=self.coverage._exclude_regex('exclude')
- )
- self.statements, self.excluded = self.parser.parse_source()
+ def __init__(self, data, file_reporter):
+ self.data = data
+ self.file_reporter = file_reporter
+ self.filename = self.file_reporter.filename
+ self.statements = self.file_reporter.lines()
+ self.excluded = self.file_reporter.excluded_lines()
# Identify missing statements.
- executed = self.coverage.data.executed_lines(self.filename)
- exec1 = self.parser.first_lines(executed)
- self.missing = self.statements - exec1
-
- if self.coverage.data.has_arcs():
- self.no_branch = self.parser.lines_matching(
- join_regex(self.coverage.config.partial_list),
- join_regex(self.coverage.config.partial_always_list)
- )
+ executed = self.data.lines(self.filename) or []
+ executed = self.file_reporter.translate_lines(executed)
+ self.missing = self.statements - executed
+
+ if self.data.has_arcs():
+ self._arc_possibilities = sorted(self.file_reporter.arcs())
+ self.exit_counts = self.file_reporter.exit_counts()
+ self.no_branch = self.file_reporter.no_branch_lines()
n_branches = self.total_branches()
mba = self.missing_branch_arcs()
n_partial_branches = sum(
- [len(v) for k,v in iitems(mba) if k not in self.missing]
+ 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)])
+ n_missing_branches = sum(len(v) for k,v in iitems(mba))
else:
- n_branches = n_partial_branches = n_missing_branches = 0
+ self._arc_possibilities = []
+ self.exit_counts = {}
self.no_branch = set()
+ n_branches = n_partial_branches = n_missing_branches = 0
self.numbers = Numbers(
n_files=1,
@@ -53,44 +50,6 @@ class Analysis(object):
n_missing_branches=n_missing_branches,
)
- def find_source(self, filename):
- """Find the source for `filename`.
-
- Returns two values: the actual filename, and the source.
-
- The source returned depends on which of these cases holds:
-
- * The filename seems to be a non-source file: returns None
-
- * The filename is a source file, and actually exists: returns None.
-
- * The filename is a source file, and is in a zip file or egg:
- returns the source.
-
- * The filename is a source file, but couldn't be found: raises
- `NoSource`.
-
- """
- source = None
-
- base, ext = os.path.splitext(filename)
- TRY_EXTS = {
- '.py': ['.py', '.pyw'],
- '.pyw': ['.pyw'],
- }
- try_exts = TRY_EXTS.get(ext)
- if not try_exts:
- return filename, None
-
- for try_ext in try_exts:
- try_filename = base + try_ext
- if os.path.exists(try_filename):
- return try_filename, None
- source = self.coverage.file_locator.get_zip_data(try_filename)
- if source:
- return try_filename, source
- raise NoSource("No source for code: '%s'" % filename)
-
def missing_formatted(self):
"""The missing line numbers, formatted nicely.
@@ -101,31 +60,47 @@ class Analysis(object):
def has_arcs(self):
"""Were arcs measured in this result?"""
- return self.coverage.data.has_arcs()
+ return self.data.has_arcs()
def arc_possibilities(self):
"""Returns a sorted list of the arcs in the code."""
- arcs = self.parser.arcs()
- return arcs
+ return self._arc_possibilities
def arcs_executed(self):
"""Returns a sorted list of the arcs actually executed in the code."""
- executed = self.coverage.data.executed_arcs(self.filename)
- m2fl = self.parser.first_line
- executed = [(m2fl(l1), m2fl(l2)) for (l1,l2) in executed]
+ executed = self.data.arcs(self.filename) or []
+ executed = self.file_reporter.translate_arcs(executed)
return sorted(executed)
def arcs_missing(self):
"""Returns a sorted list of the arcs in the code not executed."""
possible = self.arc_possibilities()
executed = self.arcs_executed()
- missing = [
+ missing = (
p for p in possible
if p not in executed
and p[0] not in self.no_branch
- ]
+ )
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->%d' % (line, ex))
+ return ', '.join(pairs)
+
def arcs_unpredicted(self):
"""Returns a sorted list of the executed arcs missing from the code."""
possible = self.arc_possibilities()
@@ -133,22 +108,23 @@ class Analysis(object):
# Exclude arcs here which connect a line to itself. They can occur
# in executed data in some cases. This is where they can cause
# trouble, and here is where it's the least burden to remove them.
- unpredicted = [
+ # Also, generators can somehow cause arcs from "enter" to "exit", so
+ # make sure we have at least one positive value.
+ unpredicted = (
e for e in executed
if e not in possible
and e[0] != e[1]
- ]
+ and (e[0] > 0 or e[1] > 0)
+ )
return sorted(unpredicted)
def branch_lines(self):
"""Returns a list of line numbers that have more than one exit."""
- exit_counts = self.parser.exit_counts()
- return [l1 for l1,count in iitems(exit_counts) if count > 1]
+ return [l1 for l1,count in iitems(self.exit_counts) if count > 1]
def total_branches(self):
"""How many total branches are there?"""
- exit_counts = self.parser.exit_counts()
- return sum([count for count in exit_counts.values() if count > 1])
+ return sum(count for count in self.exit_counts.values() if count > 1)
def missing_branch_arcs(self):
"""Return arcs that weren't executed from branch lines.
@@ -158,11 +134,9 @@ class Analysis(object):
"""
missing = self.arcs_missing()
branch_lines = set(self.branch_lines())
- mba = {}
+ mba = collections.defaultdict(list)
for l1, l2 in missing:
if l1 in branch_lines:
- if l1 not in mba:
- mba[l1] = []
mba[l1].append(l2)
return mba
@@ -173,11 +147,10 @@ class Analysis(object):
(total_exits, taken_exits).
"""
- exit_counts = self.parser.exit_counts()
missing_arcs = self.missing_branch_arcs()
stats = {}
for lnum in self.branch_lines():
- exits = exit_counts[lnum]
+ exits = self.exit_counts[lnum]
try:
missing = len(missing_arcs[lnum])
except KeyError:
@@ -210,35 +183,43 @@ class Numbers(object):
self.n_partial_branches = n_partial_branches
self.n_missing_branches = n_missing_branches
+ def init_args(self):
+ """Return a list for __init__(*args) to recreate this object."""
+ return [
+ self.n_files, self.n_statements, self.n_excluded, self.n_missing,
+ self.n_branches, self.n_partial_branches, self.n_missing_branches,
+ ]
+
+ @classmethod
def set_precision(cls, precision):
"""Set the number of decimal places used to report percentages."""
assert 0 <= precision < 10
cls._precision = precision
cls._near0 = 1.0 / 10**precision
cls._near100 = 100.0 - cls._near0
- set_precision = classmethod(set_precision)
- def _get_n_executed(self):
+ @property
+ def 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):
+ @property
+ def 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):
+ @property
+ def pc_covered(self):
"""Returns a single percentage value for coverage."""
if self.n_statements > 0:
- pc_cov = (100.0 * (self.n_executed + self.n_executed_branches) /
- (self.n_statements + self.n_branches))
+ numerator, denominator = self.ratio_covered
+ pc_cov = (100.0 * numerator) / denominator
else:
pc_cov = 100.0
return pc_cov
- pc_covered = property(_get_pc_covered)
- def _get_pc_covered_str(self):
+ @property
+ def pc_covered_str(self):
"""Returns the percent covered, as a string, without a percent sign.
Note that "0" is only returned when the value is truly zero, and "100"
@@ -254,15 +235,21 @@ class Numbers(object):
else:
pc = round(pc, self._precision)
return "%.*f" % (self._precision, pc)
- pc_covered_str = property(_get_pc_covered_str)
+ @classmethod
def pc_str_width(cls):
"""How many characters wide can pc_covered_str be?"""
width = 3 # "100"
if cls._precision > 0:
width += 1 + cls._precision
return width
- pc_str_width = classmethod(pc_str_width)
+
+ @property
+ def ratio_covered(self):
+ """Return a numerator and denominator for the coverage ratio."""
+ numerator = self.n_executed + self.n_executed_branches
+ denominator = self.n_statements + self.n_branches
+ return numerator, denominator
def __add__(self, other):
nums = Numbers()
« no previous file with comments | « tools/telemetry/third_party/coverage/coverage/report.py ('k') | tools/telemetry/third_party/coverage/coverage/summary.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698