Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/stylesheets/application.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
//= require ./reset.css
//= require_directory ./plugins/
//= require ./screen.css
//= require ./screen.css
5 changes: 5 additions & 0 deletions assets/stylesheets/screen.css
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,8 @@ thead th {
.source_table .missed-branch:nth-child(even) {
background-color: #cc6e6e;
}

.t-missed-method-summary ul {
margin: 0;
padding-left: 2em;
}
47 changes: 34 additions & 13 deletions lib/simplecov-html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class HTMLFormatter
}.freeze

def initialize
@branchable_result = SimpleCov.branch_coverage?
@branch_coverage = SimpleCov.branch_coverage?
@method_coverage = SimpleCov.method_coverage?
@templates = {}
@inline_assets = !ENV["SIMPLECOV_INLINE_ASSETS"].nil?
@public_assets_dir = File.join(File.dirname(__FILE__), "../public/")
Expand All @@ -45,26 +46,36 @@ def format(result)

private

def branchable_result?
def branch_coverage?
# cached in initialize because we truly look it up a whole bunch of times
# and it's easier to cache here then in SimpleCov because there we might
# still enable/disable branch coverage criterion
@branchable_result
@branch_coverage
end

def method_coverage?
# cached in initialize because we truly look it up a whole bunch of times
# and it's easier to cache here then in SimpleCov because there we might
# still enable/disable branch coverage criterion
@method_coverage
end

def line_status?(source_file, line)
if branchable_result? && source_file.line_with_missed_branch?(line.number)
if branch_coverage? && source_file.line_with_missed_branch?(line.number)
"missed-branch"
else
line.status
end
end

def output_message(result)
output = "Coverage report generated for #{result.command_name} to #{output_path}."
output += "\nLine Coverage: #{result.covered_percent.round(2)}% (#{result.covered_lines} / #{result.total_lines})"
output += "\nBranch Coverage: #{result.coverage_statistics[:branch].percent.round(2)}% (#{result.covered_branches} / #{result.total_branches})" if branchable_result?
output
parts = []
parts << "Coverage report generated for #{result.command_name} to #{output_path}"
parts << "Line coverage: #{render_stats(result, :line)}"
parts << "Branch coverage: #{render_stats(result, :branch)}" if branch_coverage?
parts << "Method coverage: #{render_stats(result, :method)}" if method_coverage?

parts.join("\n")
end

# Returns the an erb instance for the template of given name
Expand All @@ -90,6 +101,10 @@ def assets_path(name)
File.join("./assets", SimpleCov::Formatter::HTMLFormatter::VERSION, name)
end

def to_id(value)
value.gsub(/^[^a-zA-Z]+/, "").gsub(/[^a-zA-Z0-9\-_]/, "")
end

def asset_inline(name)
path = File.join(@public_assets_dir, name)
# Equivalent to `Base64.strict_encode64(File.read(path))` but without depending on Base64
Expand All @@ -109,11 +124,6 @@ def formatted_source_file(source_file)

# Returns a table containing the given source files
def formatted_file_list(title, source_files)
title_id = title.gsub(/^[^a-zA-Z]+/, "").gsub(/[^a-zA-Z0-9\-_]/, "")
# Silence a warning by using the following variable to assign to itself:
# "warning: possibly useless use of a variable in void context"
# The variable is used by ERB via binding.
title_id = title_id # rubocop:disable Lint/SelfAssignment
template("file_list").result(binding)
end

Expand Down Expand Up @@ -157,6 +167,17 @@ def shortened_filename(source_file)
def link_to_source_file(source_file)
%(<a href="##{id source_file}" class="src_link" title="#{shortened_filename source_file}">#{shortened_filename source_file}</a>)
end

def render_stats(result, criterion)
stats = result.coverage_statistics.fetch(criterion)

Kernel.format(
"%<covered>d / %<total>d (%<percent>.2f%%)",
covered: stats.covered,
total: stats.total,
percent: stats.percent
)
end
end
end
end
Expand Down
31 changes: 26 additions & 5 deletions views/file_list.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="file_list_container" id="<%= title_id %>">
<div class="file_list_container" id="<%= to_id(title) %>">
<h2>
<span class="group_name"><%= title %></span>
(<span class="covered_percent">
Expand All @@ -13,7 +13,7 @@
)
</h2>

<a name="<%= title_id %>"></a>
<a name="<%= to_id(title) %>"></a>

<div>
<b><%= source_files.length %></b> files in total.
Expand All @@ -26,7 +26,7 @@
(<%= covered_percent(source_files.covered_percent) %>)
</div>

<% if branchable_result? %>
<% if branch_coverage? %>
<div class="t-branch-summary">
<span><b><%= source_files.total_branches %></b> total branches, </span>
<span class="green"><b><%= source_files.covered_branches %></b> branches covered</span> and
Expand All @@ -35,6 +35,15 @@
</div>
<% end %>

<% if method_coverage? %>
<div class="t-method-summary">
<span><b><%= source_files.total_methods %></b> total methods, </span>
<span class="green"><b><%= source_files.covered_methods %></b> methods covered</span> and
<span class="red"><b><%= source_files.missed_methods %></b> methods missed.</span>
(<%= covered_percent(source_files.method_covered_percent) %>)
</div>
<% end %>

<div class="file_list--responsive">
<table class="file_list">
<thead>
Expand All @@ -46,12 +55,18 @@
<th class="cell--number">Lines covered</th>
<th class="cell--number">Lines missed</th>
<th class="cell--number">Avg. Hits / Line</th>
<% if branchable_result? %>
<% if branch_coverage? %>
<th class="cell--number">Branch Coverage</th>
<th class="cell--number">Branches</th>
<th class="cell--number">Covered branches</th>
<th class="cell--number">Missed branches </th>
<% end %>
<% if method_coverage? %>
<th class="cell--number">Method Coverage</th>
<th class="cell--number">Methods</th>
<th class="cell--number">Covered methods</th>
<th class="cell--number">Missed methods </th>
<% end %>
</tr>
</thead>
<tbody>
Expand All @@ -64,12 +79,18 @@
<td class="cell--number"><%= source_file.covered_lines.count %></td>
<td class="cell--number"><%= source_file.missed_lines.count %></td>
<td class="cell--number"><%= sprintf("%.2f", source_file.covered_strength.round(2)) %></td>
<% if branchable_result? %>
<% if branch_coverage? %>
<td class="<%= coverage_css_class(source_file.branches_coverage_percent) %> strong cell--number t-file__branch-coverage"><%= sprintf("%.2f", source_file.branches_coverage_percent.round(2)) %> %</td>
<td class="cell--number"><%= source_file.total_branches.count %></td>
<td class="cell--number"><%= source_file.covered_branches.count %></td>
<td class="cell--number"><%= source_file.missed_branches.count %></td>
<% end %>
<% if method_coverage? %>
<td class="<%= coverage_css_class(source_file.methods_coverage_percent) %> strong cell--number t-file__method-coverage"><%= sprintf("%.2f", source_file.methods_coverage_percent.round(2)) %> %</td>
<td class="cell--number"><%= source_file.total_methods.count %></td>
<td class="cell--number"><%= source_file.covered_methods.count %></td>
<td class="cell--number"><%= source_file.missed_methods.count %></td>
<% end %>
</tr>
<% end %>
</tbody>
Expand Down
2 changes: 1 addition & 1 deletion views/layout.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<link rel="icon" type="image/png" href="<%= assets_path("favicon_#{coverage_css_class(result.source_files.covered_percent)}.png") %>" />
</head>

<body<%= ' data-branch-coverage=true' if branchable_result? %>>
<body<%= ' data-branch-coverage=true' if branch_coverage? %>>
<div id="loading">
<img src="<%= assets_path('loading.gif') %>" alt="loading"/>
</div>
Expand Down
33 changes: 30 additions & 3 deletions views/source_file.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,54 @@
lines covered
</h4>

<% if branchable_result? %>
<% if branch_coverage? %>
<h4>
<%= covered_percent(source_file.branches_coverage_percent) %>
branches covered
</h4>
<% end %>

<% if method_coverage? %>
<h4>
<%= covered_percent(source_file.methods_coverage_percent) %>
methods covered
</h4>
<% end %>


<div class="t-line-summary">
<b><%= source_file.lines_of_code %></b> relevant lines.
<span class="green"><b><%= source_file.covered_lines.count %></b> lines covered</span> and
<span class="red"><b><%= source_file.missed_lines.count %></b> lines missed.</span>
</div>

<% if branchable_result? %>
<% if branch_coverage? %>
<div class="t-branch-summary">
<span><b><%= source_file.total_branches.count %></b> total branches, </span>
<span class="green"><b><%= source_file.covered_branches.count %></b> branches covered</span> and
<span class="red"><b><%= source_file.missed_branches.count %></b> branches missed.</span>
</div>
<% end %>

<% if method_coverage? %>
<div class="t-method-summary">
<span><b><%= source_file.total_methods.count %></b> total methods, </span>
<span class="green"><b><%= source_file.covered_methods.count %></b> methods covered</span> and
<span class="red"><b><%= source_file.missed_methods.count %></b> methods missed.</span>
</div>
<% end %>

<% if method_coverage? && source_file.missed_methods.any? %>
<div class="t-missed-method-summary">
<span>Missed methods:</span>
<ul>
<% source_file.missed_methods.each do |missed_method| %>
<li><tt><%= CGI.escapeHTML(missed_method.to_s) %></tt></li>
<% end %>
</ul>
</div>
<% end %>

</div>

<pre>
Expand All @@ -40,7 +67,7 @@
<span class="hits">skipped</span>
<% end %>

<% if branchable_result? %>
<% if branch_coverage? %>
<% source_file.branches_for_line(line.number).each do |branch_type, hit_count| %>
<span class="hits" title="<%= branch_type%> branch hit <%= hit_count %> times">
<%= branch_type %>: <%= hit_count %>
Expand Down