Skip to content

Commit

Permalink
fix: next/prev links in HTML report don't link to skipped files.
Browse files Browse the repository at this point in the history
Previously, the next link might refer to a file that was skipped because it was
empty or 100% covered.  Now they do not.
  • Loading branch information
nedbat committed May 20, 2022
1 parent fa4e6d1 commit 78c0915
Showing 1 changed file with 61 additions and 63 deletions.
124 changes: 61 additions & 63 deletions coverage/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ def data_for_file(self, fr, analysis):
return file_data


class FileToReport:
"""A file we're considering reporting."""
def __init__(self, fr, analysis):
self.fr = fr
self.analysis = analysis
self.rootname = flat_rootname(fr.relative_filename())
self.html_filename = self.rootname + ".html"


class HtmlReporter:
"""HTML reporting."""

Expand Down Expand Up @@ -207,40 +216,50 @@ def report(self, morfs):
self.incr.check_global_data(self.config, self.pyfile_html_source)

# Process all the files. For each page we need to supply a link
# to the next page. Therefore in each iteration of the loop we
# work on the fr and analysis from the previous iteration. We
# also need a link to the preceding page (i.e. 2 before the
# current iteration).
analysis_to_report = get_analysis_to_report(self.coverage, morfs)
pluprev_fr, prev_fr = None, None
prev_analysis = None

for fr, analysis in analysis_to_report:
if prev_fr is not None:
self.html_file(prev_fr, prev_analysis, pluprev_fr, fr)
# to the next and previous page.
files_to_report = []

for fr, analysis in get_analysis_to_report(self.coverage, morfs):
ftr = FileToReport(fr, analysis)
should = self.should_report_file(ftr)
if should:
files_to_report.append(ftr)
else:
# This is the first file processed
self.first_fr = fr
pluprev_fr, prev_fr, prev_analysis = prev_fr, fr, analysis
file_be_gone(os.path.join(self.directory, ftr.html_filename))

# One more iteration for the final file. (Or not, if there are
# no files at all.)
if prev_fr is not None:
self.html_file(prev_fr, prev_analysis, pluprev_fr, None)
# This is the last file processed
self.final_fr = prev_fr
for i, ftr in enumerate(files_to_report):
if i == 0:
prev_html = "index.html"
else:
prev_html = files_to_report[i - 1].html_filename
if i == len(files_to_report) - 1:
next_html = "index.html"
else:
next_html = files_to_report[i + 1].html_filename
self.write_html_file(ftr, prev_html, next_html)

if not self.all_files_nums:
raise NoDataError("No data to report.")

self.totals = sum(self.all_files_nums)

# Write the index file.
self.index_file()
if files_to_report:
first_html = files_to_report[0].html_filename
final_html = files_to_report[-1].html_filename
else:
first_html = final_html = "index.html"
self.index_file(first_html, final_html)

self.make_local_static_report_files()
return self.totals.n_statements and self.totals.pc_covered

def make_directory(self):
"""Make sure our htmlcov directory exists."""
ensure_dir(self.directory)
if not os.listdir(self.directory):
self.directory_was_empty = True

def make_local_static_report_files(self):
"""Make local instances of static files for HTML report."""
# The files we provide must always be copied.
Expand All @@ -258,27 +277,10 @@ def make_local_static_report_files(self):
if self.extra_css:
shutil.copyfile(self.config.extra_css, os.path.join(self.directory, self.extra_css))

def html_file(self, fr, analysis, prev_fr, next_fr):
"""Generate an HTML file for one source file."""
rootname = flat_rootname(fr.relative_filename())
html_filename = rootname + ".html"
if prev_fr is not None:
prev_html = flat_rootname(prev_fr.relative_filename()) + ".html"
else:
prev_html = "index.html"

if next_fr is not None:
next_html = flat_rootname(next_fr.relative_filename()) + ".html"
else:
next_html = "index.html"

ensure_dir(self.directory)
if not os.listdir(self.directory):
self.directory_was_empty = True
html_path = os.path.join(self.directory, html_filename)

def should_report_file(self, ftr):
"""Determine if we'll report this file."""
# Get the numbers for this file.
nums = analysis.numbers
nums = ftr.analysis.numbers
self.all_files_nums.append(nums)

if self.skip_covered:
Expand All @@ -287,24 +289,28 @@ def html_file(self, fr, analysis, prev_fr, next_fr):
no_missing_branches = (nums.n_partial_branches == 0)
if no_missing_lines and no_missing_branches:
# If there's an existing file, remove it.
file_be_gone(html_path)
self.skipped_covered_count += 1
return
return False

if self.skip_empty:
# Don't report on empty files.
if nums.n_statements == 0:
file_be_gone(html_path)
self.skipped_empty_count += 1
return
return False

return True

def write_html_file(self, ftr, prev_html, next_html):
"""Generate an HTML file for one source file."""
self.make_directory()

# Find out if the file on disk is already correct.
if self.incr.can_skip_file(self.data, fr, rootname):
self.file_summaries.append(self.incr.index_info(rootname))
if self.incr.can_skip_file(self.data, ftr.fr, ftr.rootname):
self.file_summaries.append(self.incr.index_info(ftr.rootname))
return

# Write the HTML page for this file.
file_data = self.datagen.data_for_file(fr, analysis)
file_data = self.datagen.data_for_file(ftr.fr, ftr.analysis)
for ldata in file_data.lines:
# Build the HTML for the line.
html = []
Expand Down Expand Up @@ -348,6 +354,7 @@ def html_file(self, fr, analysis, prev_fr, next_fr):
css_classes.append(self.template_globals['category'][ldata.category])
ldata.css_class = ' '.join(css_classes) or "pln"

html_path = os.path.join(self.directory, ftr.html_filename)
html = self.source_tmpl.render({
**file_data.__dict__,
'prev_html': prev_html,
Expand All @@ -357,15 +364,16 @@ def html_file(self, fr, analysis, prev_fr, next_fr):

# Save this file's information for the index file.
index_info = {
'nums': nums,
'html_filename': html_filename,
'relative_filename': fr.relative_filename(),
'nums': ftr.analysis.numbers,
'html_filename': ftr.html_filename,
'relative_filename': ftr.fr.relative_filename(),
}
self.file_summaries.append(index_info)
self.incr.set_index_info(rootname, index_info)
self.incr.set_index_info(ftr.rootname, index_info)

def index_file(self):
def index_file(self, first_html, final_html):
"""Write the index.html file for this report."""
self.make_directory()
index_tmpl = Templite(read_data("index.html"), self.template_globals)

skipped_covered_msg = skipped_empty_msg = ""
Expand All @@ -376,16 +384,6 @@ def index_file(self):
n = self.skipped_empty_count
skipped_empty_msg = f"{n} empty file{plural(n)} skipped."

if self.first_fr is not None:
first_html = flat_rootname(self.first_fr.relative_filename()) + ".html"
else:
first_html = "index.html"

if self.final_fr is not None:
final_html = flat_rootname(self.final_fr.relative_filename()) + ".html"
else:
final_html = "index.html"

html = index_tmpl.render({
'files': self.file_summaries,
'totals': self.totals,
Expand Down

0 comments on commit 78c0915

Please sign in to comment.