slather 2.6.1 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|