slather 2.6.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/assets/slather.css +2 -1
- data/lib/slather/coverage_service/html_output.rb +41 -2
- data/lib/slather/profdata_coverage_file.rb +42 -2
- data/lib/slather/project.rb +17 -3
- data/lib/slather/version.rb +1 -1
- data/spec/slather/coverage_service/html_output_spec.rb +2 -2
- data/spec/slather/profdata_coverage_spec.rb +12 -0
- data/spec/slather/project_spec.rb +4 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6388d4f62571f927f845978e5383f2508b98e7e3ba0205aaf546b5a54d465f5
|
4
|
+
data.tar.gz: 837f82512416a6f57cb9c4510dcc7bd9524a4aeeaa05f42bdd841f18cf4fa1d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b1af2387a7475860aeb3666883c5fd8d2e2b9be020680452140e71fa5bbb3ff057eb3b23b0ddb1c02d6fd55478aafceda18f5527ed2bd086b49d0d89a06e75b
|
7
|
+
data.tar.gz: 0b464fbffa5722ed27fa157e429427387889e9e5c641ed2d2d2663a90ccc6f815163e19687a21fac2078dbb6c9c8c8baf9745ff1b55266e38f220aed6258c66f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v2.7.0
|
4
|
+
|
5
|
+
* Add Branch Coverage data for ProfData coverage files
|
6
|
+
[hborawski](https://github.com/hborawski)
|
7
|
+
[#477](https://github.com/SlatherOrg/slather/pull/477)
|
8
|
+
|
9
|
+
* Fixed 'Argument list too long' when running 'xcrun llvm-cov'
|
10
|
+
[samuelsainz](https://github.com/samuelsainz)
|
11
|
+
[#476](https://github.com/SlatherOrg/slather/pull/476)
|
12
|
+
|
3
13
|
## v2.6.1
|
4
14
|
|
5
15
|
* Update nokogiri to 1.11
|
data/assets/slather.css
CHANGED
@@ -74,6 +74,7 @@ table.source_code {
|
|
74
74
|
table.source_code td {
|
75
75
|
padding-bottom: 0.3em;
|
76
76
|
}
|
77
|
+
code.missed { background-color: rgba(255, 73, 76, 0.3); }
|
77
78
|
table.source_code tr.missed td { background-color: rgba(248, 103, 105, 0.2); }
|
78
79
|
table.source_code tr.covered td { background-color: rgba(103, 207, 124, 0.2); }
|
79
80
|
table.source_code td.num {
|
@@ -124,7 +125,7 @@ footer p, footer a {
|
|
124
125
|
Syntax Highlighting using highlight.js (https://highlightjs.org)
|
125
126
|
------------------------------------------------------------- */
|
126
127
|
.hljs {
|
127
|
-
display: block;
|
128
|
+
display: inline-block;
|
128
129
|
overflow-x: auto;
|
129
130
|
-webkit-text-size-adjust: none;
|
130
131
|
}
|
@@ -70,9 +70,14 @@ module Slather
|
|
70
70
|
|
71
71
|
total_relevant_lines = 0
|
72
72
|
total_tested_lines = 0
|
73
|
+
total_relevant_branches = 0
|
74
|
+
total_branches_tested = 0
|
73
75
|
coverage_files.each { |coverage_file|
|
74
76
|
total_tested_lines += coverage_file.num_lines_tested
|
75
77
|
total_relevant_lines += coverage_file.num_lines_testable
|
78
|
+
|
79
|
+
total_relevant_branches += coverage_file.num_branches_testable
|
80
|
+
total_branches_tested += coverage_file.num_branches_tested
|
76
81
|
}
|
77
82
|
|
78
83
|
builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
|
@@ -84,6 +89,12 @@ module Slather
|
|
84
89
|
cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
|
85
90
|
}
|
86
91
|
|
92
|
+
cov.h4 {
|
93
|
+
percentage = (total_branches_tested / total_relevant_branches.to_f) * 100.0
|
94
|
+
cov.span "Total Branch Coverage : "
|
95
|
+
cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
|
96
|
+
}
|
97
|
+
|
87
98
|
cov.input(:class => "search", :placeholder => "Search")
|
88
99
|
|
89
100
|
cov.table(:class => "coverage_list", :cellspacing => 0, :cellpadding => 0) {
|
@@ -133,6 +144,7 @@ module Slather
|
|
133
144
|
filepath = coverage_file.source_file_pathname_relative_to_repo_root
|
134
145
|
filename = File.basename(filepath)
|
135
146
|
percentage = coverage_file.percentage_lines_tested
|
147
|
+
branch_percentage = coverage_file.rate_branches_tested * 100
|
136
148
|
|
137
149
|
cleaned_gcov_lines = coverage_file.cleaned_gcov_data.split("\n")
|
138
150
|
is_file_empty = (cleaned_gcov_lines.count <= 0)
|
@@ -142,7 +154,10 @@ module Slather
|
|
142
154
|
builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
|
143
155
|
cov.h2(:class => "cov_title") {
|
144
156
|
cov.span("Coverage for \"#{filename}\"" + (!is_file_empty ? " : " : ""))
|
157
|
+
cov.span("Lines: ") unless is_file_empty
|
145
158
|
cov.span("#{decimal_f(percentage)}%", :class => class_for_coverage_percentage(percentage)) unless is_file_empty
|
159
|
+
cov.span(" Branches: ") unless is_file_empty
|
160
|
+
cov.span("#{decimal_f(branch_percentage)}%", :class => class_for_coverage_percentage(branch_percentage)) unless is_file_empty
|
146
161
|
}
|
147
162
|
|
148
163
|
cov.h4("(#{coverage_file.num_lines_tested} of #{coverage_file.num_lines_testable} relevant lines covered)", :class => "cov_subtitle")
|
@@ -157,8 +172,9 @@ module Slather
|
|
157
172
|
|
158
173
|
cov.table(:class => "source_code") {
|
159
174
|
cleaned_gcov_lines.each do |line|
|
160
|
-
|
161
175
|
line_number = coverage_file.line_number_in_line(line)
|
176
|
+
missed_regions = coverage_file.branch_region_data[line_number]
|
177
|
+
hits = coverage_file.coverage_for_line(line)
|
162
178
|
next unless line_number > 0
|
163
179
|
|
164
180
|
line_source = line.split(line_number_separator, 3)[2]
|
@@ -171,7 +187,30 @@ module Slather
|
|
171
187
|
cov.td(line, :class => classes[idx])
|
172
188
|
else
|
173
189
|
cov.td(:class => classes[idx]) {
|
174
|
-
cov.pre {
|
190
|
+
cov.pre {
|
191
|
+
# If the line has coverage and missed regions, split up
|
192
|
+
# the line to show regions that weren't covered
|
193
|
+
if missed_regions != nil && hits != nil && hits > 0
|
194
|
+
regions = missed_regions.map do |region|
|
195
|
+
region_start, region_length = region
|
196
|
+
if region_length != nil
|
197
|
+
line[region_start, region_length]
|
198
|
+
else
|
199
|
+
line[region_start, line.length - region_start]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
current_line = line
|
203
|
+
regions.each do |region|
|
204
|
+
covered, remainder = current_line.split(region)
|
205
|
+
cov.code(covered, :class => "objc")
|
206
|
+
cov.code(region, :class => "objc missed")
|
207
|
+
current_line = remainder
|
208
|
+
end
|
209
|
+
cov.code(current_line, :class => "objc")
|
210
|
+
else
|
211
|
+
cov.code(line, :class => "objc")
|
212
|
+
end
|
213
|
+
}
|
175
214
|
}
|
176
215
|
end
|
177
216
|
}
|
@@ -8,7 +8,7 @@ module Slather
|
|
8
8
|
include CoverageInfo
|
9
9
|
include CoverallsCoverage
|
10
10
|
|
11
|
-
attr_accessor :project, :source, :line_numbers_first, :line_data
|
11
|
+
attr_accessor :project, :source, :segments, :line_numbers_first, :line_data
|
12
12
|
|
13
13
|
def initialize(project, source, line_numbers_first)
|
14
14
|
self.project = project
|
@@ -188,7 +188,47 @@ module Slather
|
|
188
188
|
|
189
189
|
def branch_coverage_data
|
190
190
|
@branch_coverage_data ||= begin
|
191
|
-
Hash.new
|
191
|
+
branch_coverage_data = Hash.new
|
192
|
+
|
193
|
+
self.segments.each do |segment|
|
194
|
+
line, col, hits, has_count, *rest = segment
|
195
|
+
next if !has_count
|
196
|
+
if branch_coverage_data.key?(line)
|
197
|
+
branch_coverage_data[line] = branch_coverage_data[line] + [hits]
|
198
|
+
else
|
199
|
+
branch_coverage_data[line] = [hits]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
branch_coverage_data
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def branch_region_data
|
208
|
+
@branch_region_data ||= begin
|
209
|
+
branch_region_data = Hash.new
|
210
|
+
region_start = nil
|
211
|
+
current_line = 0
|
212
|
+
@segments ||= []
|
213
|
+
@segments.each do |segment|
|
214
|
+
line, col, hits, has_count, *rest = segment
|
215
|
+
# Make column 0 based index
|
216
|
+
col = col - 1
|
217
|
+
if hits == 0 && has_count
|
218
|
+
current_line = line
|
219
|
+
region_start = col
|
220
|
+
elsif region_start != nil && hits > 0 && has_count
|
221
|
+
# if the region wrapped to a new line before ending, put nil to indicate it didnt end on this line
|
222
|
+
region_end = line == current_line ? col - region_start : nil
|
223
|
+
if branch_region_data.key?(current_line)
|
224
|
+
branch_region_data[current_line] = branch_region_data[current_line] + [region_start, region_end]
|
225
|
+
else
|
226
|
+
branch_region_data[current_line] = [[region_start, region_end]]
|
227
|
+
end
|
228
|
+
region_start = nil
|
229
|
+
end
|
230
|
+
end
|
231
|
+
branch_region_data
|
192
232
|
end
|
193
233
|
end
|
194
234
|
|
data/lib/slather/project.rb
CHANGED
@@ -135,7 +135,7 @@ module Slather
|
|
135
135
|
coverage_json = JSON.parse(coverage_json_string)
|
136
136
|
coverage_json["data"].reduce([]) do |result, chunk|
|
137
137
|
result.concat(chunk["files"].map do |file|
|
138
|
-
Pathname(file["filename"]).realpath
|
138
|
+
{"filename" => Pathname(file["filename"]).realpath, "segments" => file["segments"]}
|
139
139
|
end)
|
140
140
|
end
|
141
141
|
end
|
@@ -162,13 +162,24 @@ module Slather
|
|
162
162
|
end
|
163
163
|
private :create_coverage_files_for_binary
|
164
164
|
|
165
|
-
def create_coverage_files(binary_path,
|
165
|
+
def create_coverage_files(binary_path, path_objects)
|
166
166
|
line_numbers_first = Gem::Version.new(self.llvm_version) >= Gem::Version.new('8.1.0')
|
167
|
+
# get just file names from the path objects
|
168
|
+
pathnames = path_objects.map { |path_obj| path_obj["filename"] }.compact
|
169
|
+
# Map of path name => segment array
|
170
|
+
paths_to_segments = path_objects.reduce(Hash.new) do |hash, path_obj|
|
171
|
+
hash[path_obj["filename"]] = path_obj["segments"]
|
172
|
+
hash
|
173
|
+
end
|
167
174
|
files = create_profdata(binary_path, pathnames)
|
168
175
|
files.map do |source|
|
169
176
|
coverage_file = coverage_file_class.new(self, source, line_numbers_first)
|
170
177
|
# If a single source file is used, the resulting output does not contain the file name.
|
171
178
|
coverage_file.source_file_pathname = pathnames.first if pathnames.count == 1
|
179
|
+
# if there is segment data for the given path, add it to the coverage_file
|
180
|
+
if paths_to_segments.key?(coverage_file.source_file_pathname)
|
181
|
+
coverage_file.segments = paths_to_segments[coverage_file.source_file_pathname]
|
182
|
+
end
|
172
183
|
!coverage_file.ignored? ? coverage_file : nil
|
173
184
|
end.compact
|
174
185
|
end
|
@@ -277,7 +288,10 @@ module Slather
|
|
277
288
|
if self.arch
|
278
289
|
llvm_cov_args << "--arch" << self.arch
|
279
290
|
end
|
280
|
-
|
291
|
+
|
292
|
+
# POSIX systems have an ARG_MAX for the maximum total length of the command line, so the command may fail with an error message of "Argument list too long".
|
293
|
+
# Using the xargs command we can break the list of source_files into sublists small enough to be acceptable.
|
294
|
+
`printf '%s\\0' #{source_files.shelljoin} | xargs -0 xcrun llvm-cov #{llvm_cov_args.shelljoin}`
|
281
295
|
end
|
282
296
|
private :unsafe_profdata_llvm_cov_output
|
283
297
|
|
data/lib/slather/version.rb
CHANGED
@@ -185,8 +185,8 @@ describe Slather::CoverageService::HtmlOutput do
|
|
185
185
|
end
|
186
186
|
|
187
187
|
allow(fixtures_project).to receive(:input_format).and_return("profdata")
|
188
|
-
allow(fixtures_project).to receive(:
|
189
|
-
|
188
|
+
allow(fixtures_project).to receive(:pathnames_per_binary).and_return([{"filename" => Pathname.new("./spec/fixtures/fixtures/other_fixtures.m"), "segments" => []}])
|
189
|
+
allow(fixtures_project).to receive(:profdata_llvm_cov_output).and_return("1| |//
|
190
190
|
2| |// other_fixtures.m
|
191
191
|
3| |// fixtures
|
192
192
|
4| |//
|
@@ -157,6 +157,18 @@ describe Slather::ProfdataCoverageFile do
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
+
describe "#branch_coverage_data" do
|
161
|
+
it "should have branch data for line 19" do
|
162
|
+
# these segments correspond to the only statement on line 19
|
163
|
+
profdata_coverage_file.segments = [[19, 9, 0, true, false], [19, 20, 1, true, false]]
|
164
|
+
expect(profdata_coverage_file.branch_coverage_data[19]).to eq([0,1])
|
165
|
+
end
|
166
|
+
it "should have missing region data for line 19" do
|
167
|
+
profdata_coverage_file.segments = [[19, 9, 0, true, false], [19, 20, 1, true, false]]
|
168
|
+
expect(profdata_coverage_file.branch_region_data[19]).to eq([[8,11]])
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
160
172
|
describe "#ignored" do
|
161
173
|
|
162
174
|
before(:each) {
|
@@ -664,10 +664,12 @@ describe Slather::Project do
|
|
664
664
|
{
|
665
665
|
"files":[
|
666
666
|
{
|
667
|
-
"filename":"spec/fixtures/fixtures/fixtures.m"
|
667
|
+
"filename":"spec/fixtures/fixtures/fixtures.m",
|
668
|
+
"segments": []
|
668
669
|
},
|
669
670
|
{
|
670
|
-
"filename":"spec/fixtures/fixturesTwo/fixturesTwo.m"
|
671
|
+
"filename":"spec/fixtures/fixturesTwo/fixturesTwo.m",
|
672
|
+
"segments": []
|
671
673
|
}
|
672
674
|
]
|
673
675
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slather
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Larsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|