slather 2.6.0 → 2.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +2 -0
- data/CHANGELOG.md +70 -0
- data/assets/slather.css +2 -1
- data/lib/slather/command/coverage_command.rb +1 -1
- data/lib/slather/coverage_file.rb +1 -1
- data/lib/slather/coverage_service/coveralls.rb +73 -6
- data/lib/slather/coverage_service/html_output.rb +51 -2
- data/lib/slather/profdata_coverage_file.rb +42 -2
- data/lib/slather/project.rb +38 -6
- data/lib/slather/version.rb +1 -1
- data/slather.gemspec +2 -2
- data/spec/fixtures/FixtureFramework/FixtureFramework.h +19 -0
- data/spec/fixtures/FixtureFramework/FlashExperiment.swift +7 -0
- data/spec/fixtures/FixtureFramework/Info.plist +24 -0
- data/spec/fixtures/FixtureFrameworkTests/FixtureFrameworkTests.swift +34 -0
- data/spec/fixtures/FixtureFrameworkTests/FlashExperimentTests.swift +9 -0
- data/spec/fixtures/FixtureFrameworkTests/Info.plist +22 -0
- data/spec/fixtures/cobertura.xml +157 -37
- data/spec/fixtures/fixtures.xcodeproj/project.pbxproj +222 -0
- data/spec/fixtures/fixtures.xcodeproj/xcshareddata/xcschemes/fixtures.xcscheme +21 -5
- data/spec/fixtures/fixtures.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- data/spec/slather/coverage_service/cobertura_xml_spec.rb +1 -1
- data/spec/slather/coverage_service/html_output_spec.rb +2 -2
- data/spec/slather/coverage_service/json_spec.rb +1 -1
- data/spec/slather/coverage_service/llvm_cov_spec.rb +1 -1
- data/spec/slather/coverage_service/sonarqube_xml_spec.rb +1 -1
- data/spec/slather/profdata_coverage_spec.rb +16 -0
- data/spec/slather/project_spec.rb +10 -6
- metadata +23 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b43954fd6f31e519f192e32ad881197d35830912e22158ca17cf333b86f97e0d
|
4
|
+
data.tar.gz: 97cf7f9b6eb50d2472aec42c3f698c3a299c38cfd8757cdb2a6e2dcad0933bc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f38c40172a16f8375b56cdc873e92339f1f275cef7848bc0d9947714073dd5ff93ba11dc1957781c69316eec59a213c079067b99cb48c134aeb24c20ae2cb945
|
7
|
+
data.tar.gz: 1a098f9ab86b11d5c65cea0c309a99a709de76dfdc0f1171f0e100784522a74613cdb3fb06346f4fb1d6e27825250f01ece561ac07bea6e59a489837c7c0c654
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,75 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v2.7.4
|
4
|
+
|
5
|
+
* Support Ruby 3.2.0
|
6
|
+
[crazymanish](https://github.com/crazymanish)
|
7
|
+
[#532](https://github.com/SlatherOrg/slather/pull/532)
|
8
|
+
|
9
|
+
## v2.7.3
|
10
|
+
|
11
|
+
* Support Coveralls parallel runs
|
12
|
+
[paulz](https://github.com/paulz)
|
13
|
+
[#523](https://github.com/SlatherOrg/slather/pull/523)
|
14
|
+
|
15
|
+
* Update nokogiri version
|
16
|
+
[anil291987](https://github.com/anil291987)
|
17
|
+
[#518](https://github.com/SlatherOrg/slather/pull/518)
|
18
|
+
[#524](https://github.com/SlatherOrg/slather/pull/524)
|
19
|
+
|
20
|
+
## v2.7.2
|
21
|
+
|
22
|
+
* Update xcodeproj version
|
23
|
+
[adamyanalunas](https://github.com/adamyanalunas)
|
24
|
+
[#502](https://github.com/SlatherOrg/slather/pull/502)
|
25
|
+
|
26
|
+
* Update nokogiri version
|
27
|
+
[jwelton](https://github.com/jwelton)
|
28
|
+
[#503](https://github.com/SlatherOrg/slather/pull/503)
|
29
|
+
|
30
|
+
* Support alternate CI systems in coveralls output
|
31
|
+
[fermoyadrop](https://github.com/fermoyadrop)
|
32
|
+
[#504](https://github.com/SlatherOrg/slather/pull/504)
|
33
|
+
|
34
|
+
* Add Bitrise support to coveralls output
|
35
|
+
[fermoyadrop](https://github.com/fermoyadrop)
|
36
|
+
[#504](https://github.com/SlatherOrg/slather/pull/505)
|
37
|
+
|
38
|
+
## v2.7.1
|
39
|
+
|
40
|
+
* Support generating coverage for framework targets
|
41
|
+
[onato](https://github.com/onato)
|
42
|
+
[#482](https://github.com/SlatherOrg/slather/pull/482)
|
43
|
+
|
44
|
+
* Show number of lines in HTML report
|
45
|
+
[SiemianHS](https://github.com/SiemianHS)
|
46
|
+
[#494](https://github.com/SlatherOrg/slather/pull/494)
|
47
|
+
|
48
|
+
* Fixed issues with HTML report generation
|
49
|
+
[fchiba](https://github.com/fchiba)
|
50
|
+
[#483](https://github.com/SlatherOrg/slather/pull/483)
|
51
|
+
[#484](https://github.com/SlatherOrg/slather/pull/484)
|
52
|
+
|
53
|
+
* Don't fail if a source file doesn't exist
|
54
|
+
[chillpop](https://github.com/chillpop)
|
55
|
+
[#492](https://github.com/SlatherOrg/slather/pull/492)
|
56
|
+
|
57
|
+
## v2.7.0
|
58
|
+
|
59
|
+
* Add Branch Coverage data for ProfData coverage files
|
60
|
+
[hborawski](https://github.com/hborawski)
|
61
|
+
[#477](https://github.com/SlatherOrg/slather/pull/477)
|
62
|
+
|
63
|
+
* Fixed 'Argument list too long' when running 'xcrun llvm-cov'
|
64
|
+
[samuelsainz](https://github.com/samuelsainz)
|
65
|
+
[#476](https://github.com/SlatherOrg/slather/pull/476)
|
66
|
+
|
67
|
+
## v2.6.1
|
68
|
+
|
69
|
+
* Update nokogiri to 1.11
|
70
|
+
[ashin-omg](https://github.com/ashin-omg)
|
71
|
+
[#473](https://github.com/SlatherOrg/slather/pull/473)
|
72
|
+
|
3
73
|
## v2.6.0
|
4
74
|
|
5
75
|
* Added GitHub actions support
|
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
|
}
|
@@ -30,7 +30,7 @@ class CoverageCommand < Clamp::Command
|
|
30
30
|
option ["--scheme"], "SCHEME", "The scheme for which the coverage was generated"
|
31
31
|
option ["--configuration"], "CONFIGURATION", "The configuration for test that the project was set"
|
32
32
|
option ["--workspace"], "WORKSPACE", "The workspace that the project was built in"
|
33
|
-
option ["--binary-file"], "BINARY_FILE", "The binary file against
|
33
|
+
option ["--binary-file"], "BINARY_FILE", "The binary file against which the coverage will be run", :multivalued => true
|
34
34
|
option ["--binary-basename"], "BINARY_BASENAME", "Basename of the file against which the coverage will be run", :multivalued => true
|
35
35
|
option ["--arch"], "ARCH", "Architecture to use from universal binaries"
|
36
36
|
option ["--source-files"], "SOURCE_FILES", "A Dir.glob compatible pattern used to limit the lookup to specific source files. Ignored in gcov mode.", :multivalued => true
|
@@ -51,7 +51,7 @@ module Slather
|
|
51
51
|
gcov_files_created = gcov_output.scan(/creating '(.+\..+\.gcov)'/)
|
52
52
|
|
53
53
|
gcov_file_name = "./#{source_file_pathname.basename}.gcov"
|
54
|
-
if File.
|
54
|
+
if File.exist?(gcov_file_name)
|
55
55
|
gcov_data = File.new(gcov_file_name).read
|
56
56
|
else
|
57
57
|
gcov_data = ""
|
@@ -41,6 +41,16 @@ module Slather
|
|
41
41
|
end
|
42
42
|
private :github_job_id
|
43
43
|
|
44
|
+
def bitrise_job_id
|
45
|
+
ENV['BITRISE_BUILD_NUMBER']
|
46
|
+
end
|
47
|
+
private :bitrise_job_id
|
48
|
+
|
49
|
+
def bitrise_pull_request
|
50
|
+
ENV['BITRISE_PULL_REQUEST']
|
51
|
+
end
|
52
|
+
private :bitrise_pull_request
|
53
|
+
|
44
54
|
def github_pull_request
|
45
55
|
ENV['CI_PULL_REQUEST'] || ""
|
46
56
|
end
|
@@ -71,6 +81,11 @@ module Slather
|
|
71
81
|
end
|
72
82
|
private :github_branch_name
|
73
83
|
|
84
|
+
def bitrise_branch_name
|
85
|
+
ENV['BITRISE_GIT_BRANCH'] || `git ls-remote --heads origin | grep $(git rev-parse HEAD) | cut -d / -f 3-`.chomp
|
86
|
+
end
|
87
|
+
private :bitrise_branch_name
|
88
|
+
|
74
89
|
def buildkite_job_id
|
75
90
|
ENV['BUILDKITE_BUILD_NUMBER']
|
76
91
|
end
|
@@ -151,16 +166,39 @@ module Slather
|
|
151
166
|
end
|
152
167
|
private :github_git_info
|
153
168
|
|
169
|
+
def bitrise_git_info
|
170
|
+
{
|
171
|
+
:head => {
|
172
|
+
:id => ENV['BITRISE_GIT_COMMIT'],
|
173
|
+
:committer_name => (ENV['GIT_CLONE_COMMIT_AUTHOR_NAME'] || `git log --format=%an -n 1 HEAD`.chomp || ""),
|
174
|
+
:committer_email => (ENV['GIT_CLONE_COMMIT_AUTHOR_EMAIL'] || `git log --format=%ae -n 1 HEAD`.chomp || ""),
|
175
|
+
:message => (ENV['BITRISE_GIT_MESSAGE'] || `git log --format=%s -n 1 HEAD`.chomp || "")
|
176
|
+
},
|
177
|
+
:branch => bitrise_branch_name
|
178
|
+
}
|
179
|
+
end
|
180
|
+
private :bitrise_git_info
|
181
|
+
|
154
182
|
def github_build_url
|
155
183
|
"https://github.com/" + ENV['GITHUB_REPOSITORY'] + "/actions/runs/" + ENV['GITHUB_RUN_ID']
|
156
184
|
end
|
157
185
|
private :github_build_url
|
158
186
|
|
187
|
+
def is_parallel
|
188
|
+
ENV['IS_PARALLEL'] != nil
|
189
|
+
end
|
190
|
+
private :is_parallel
|
191
|
+
|
192
|
+
def github_job_name
|
193
|
+
ENV['GITHUB_JOB']
|
194
|
+
end
|
195
|
+
private :github_job_name
|
196
|
+
|
159
197
|
def coveralls_coverage_data
|
160
198
|
if ci_service == :travis_ci || ci_service == :travis_pro
|
161
199
|
if travis_job_id
|
162
200
|
if ci_service == :travis_ci
|
163
|
-
|
201
|
+
|
164
202
|
if coverage_access_token.to_s.strip.length > 0
|
165
203
|
raise StandardError, "Access token is set. Uploading coverage data for public repositories doesn't require an access token."
|
166
204
|
end
|
@@ -170,7 +208,7 @@ module Slather
|
|
170
208
|
:service_name => "travis-ci",
|
171
209
|
:source_files => coverage_files.map(&:as_json)
|
172
210
|
}.to_json
|
173
|
-
elsif ci_service == :travis_pro
|
211
|
+
elsif ci_service == :travis_pro
|
174
212
|
|
175
213
|
if coverage_access_token.to_s.strip.length == 0
|
176
214
|
raise StandardError, "Access token is not set. Uploading coverage data for private repositories requires an access token."
|
@@ -258,13 +296,42 @@ module Slather
|
|
258
296
|
:source_files => coverage_files.map(&:as_json),
|
259
297
|
:service_build_url => github_build_url,
|
260
298
|
:service_pull_request => github_pull_request,
|
261
|
-
:git => github_git_info
|
299
|
+
:git => github_git_info,
|
300
|
+
:parallel => is_parallel,
|
301
|
+
:flag_name => github_job_name
|
262
302
|
}.to_json
|
263
303
|
else
|
264
304
|
raise StandardError, "Environment variable `GITHUB_RUN_ID` not set. Is this running on github build?"
|
265
305
|
end
|
306
|
+
elsif ci_service == :bitrise
|
307
|
+
{
|
308
|
+
:service_job_id => bitrise_job_id,
|
309
|
+
:service_name => 'bitrise',
|
310
|
+
:repo_token => coverage_access_token,
|
311
|
+
:source_files => coverage_files.map(&:as_json),
|
312
|
+
:service_pull_request => bitrise_pull_request,
|
313
|
+
:service_branch => bitrise_branch_name,
|
314
|
+
:git => bitrise_git_info
|
315
|
+
}.to_json
|
266
316
|
else
|
267
|
-
|
317
|
+
{
|
318
|
+
:service_job_id => ENV['CI_BUILD_NUMBER'],
|
319
|
+
:service_name => ENV['CI_NAME'] || ci_service,
|
320
|
+
:repo_token => coverage_access_token,
|
321
|
+
:source_files => coverage_files.map(&:as_json),
|
322
|
+
:service_build_url => ENV['CI_BUILD_URL'],
|
323
|
+
:service_pull_request => ENV['CI_PULL_REQUEST'],
|
324
|
+
:service_branch => ENV['CI_BRANCH'],
|
325
|
+
:git => {
|
326
|
+
:head => {
|
327
|
+
:id => ENV['CI_COMMIT'],
|
328
|
+
:committer_name => (`git log --format=%an -n 1 HEAD`.chomp || ""),
|
329
|
+
:committer_email => (`git log --format=%ae -n 1 HEAD`.chomp || ""),
|
330
|
+
:message => (`git log --format=%s -n 1 HEAD`.chomp || "")
|
331
|
+
},
|
332
|
+
:branch => ENV['CI_BRANCH']
|
333
|
+
}
|
334
|
+
}.to_json
|
268
335
|
end
|
269
336
|
end
|
270
337
|
private :coveralls_coverage_data
|
@@ -277,8 +344,8 @@ module Slather
|
|
277
344
|
|
278
345
|
curl_result = `curl -s --form json_file=@#{f.path} #{coveralls_api_jobs_path}`
|
279
346
|
|
280
|
-
if curl_result.is_a? String
|
281
|
-
curl_result_json = JSON.parse(curl_result)
|
347
|
+
if curl_result.is_a? String
|
348
|
+
curl_result_json = JSON.parse(curl_result)
|
282
349
|
|
283
350
|
if curl_result_json["error"]
|
284
351
|
error_message = curl_result_json["message"]
|
@@ -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|
|
@@ -82,6 +87,22 @@ module Slather
|
|
82
87
|
percentage = (total_tested_lines / total_relevant_lines.to_f) * 100.0
|
83
88
|
cov.span "Total Coverage : "
|
84
89
|
cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
|
90
|
+
cov.span " ("
|
91
|
+
cov.span total_tested_lines, :id => "total_tested_lines"
|
92
|
+
cov.span " of "
|
93
|
+
cov.span total_relevant_lines, :id => "total_relevant_lines"
|
94
|
+
cov.span " lines)"
|
95
|
+
}
|
96
|
+
|
97
|
+
cov.h4 {
|
98
|
+
percentage = (total_branches_tested / total_relevant_branches.to_f) * 100.0
|
99
|
+
cov.span "Total Branch Coverage : "
|
100
|
+
cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
|
101
|
+
cov.span " ("
|
102
|
+
cov.span total_branches_tested, :id => "total_branches_tested"
|
103
|
+
cov.span " of "
|
104
|
+
cov.span total_relevant_branches, :id => "total_relevant_branches"
|
105
|
+
cov.span " lines)"
|
85
106
|
}
|
86
107
|
|
87
108
|
cov.input(:class => "search", :placeholder => "Search")
|
@@ -133,6 +154,7 @@ module Slather
|
|
133
154
|
filepath = coverage_file.source_file_pathname_relative_to_repo_root
|
134
155
|
filename = File.basename(filepath)
|
135
156
|
percentage = coverage_file.percentage_lines_tested
|
157
|
+
branch_percentage = coverage_file.rate_branches_tested * 100
|
136
158
|
|
137
159
|
cleaned_gcov_lines = coverage_file.cleaned_gcov_data.split("\n")
|
138
160
|
is_file_empty = (cleaned_gcov_lines.count <= 0)
|
@@ -142,7 +164,10 @@ module Slather
|
|
142
164
|
builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
|
143
165
|
cov.h2(:class => "cov_title") {
|
144
166
|
cov.span("Coverage for \"#{filename}\"" + (!is_file_empty ? " : " : ""))
|
167
|
+
cov.span("Lines: ") unless is_file_empty
|
145
168
|
cov.span("#{decimal_f(percentage)}%", :class => class_for_coverage_percentage(percentage)) unless is_file_empty
|
169
|
+
cov.span(" Branches: ") unless is_file_empty
|
170
|
+
cov.span("#{decimal_f(branch_percentage)}%", :class => class_for_coverage_percentage(branch_percentage)) unless is_file_empty
|
146
171
|
}
|
147
172
|
|
148
173
|
cov.h4("(#{coverage_file.num_lines_tested} of #{coverage_file.num_lines_testable} relevant lines covered)", :class => "cov_subtitle")
|
@@ -157,8 +182,9 @@ module Slather
|
|
157
182
|
|
158
183
|
cov.table(:class => "source_code") {
|
159
184
|
cleaned_gcov_lines.each do |line|
|
160
|
-
|
161
185
|
line_number = coverage_file.line_number_in_line(line)
|
186
|
+
missed_regions = coverage_file.branch_region_data[line_number]
|
187
|
+
hits = coverage_file.coverage_for_line(line)
|
162
188
|
next unless line_number > 0
|
163
189
|
|
164
190
|
line_source = line.split(line_number_separator, 3)[2]
|
@@ -171,7 +197,30 @@ module Slather
|
|
171
197
|
cov.td(line, :class => classes[idx])
|
172
198
|
else
|
173
199
|
cov.td(:class => classes[idx]) {
|
174
|
-
cov.pre {
|
200
|
+
cov.pre {
|
201
|
+
# If the line has coverage and missed regions, split up
|
202
|
+
# the line to show regions that weren't covered
|
203
|
+
if missed_regions != nil && hits != nil && hits > 0
|
204
|
+
regions = missed_regions.map do |region|
|
205
|
+
region_start, region_length = region
|
206
|
+
if region_length != nil
|
207
|
+
line[region_start, region_length]
|
208
|
+
else
|
209
|
+
line[region_start, line.length - region_start]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
current_line = line
|
213
|
+
regions.each do |region|
|
214
|
+
covered, remainder = current_line.split(region, 2)
|
215
|
+
cov.code(covered, :class => "objc")
|
216
|
+
cov.code(region, :class => "objc missed")
|
217
|
+
current_line = remainder
|
218
|
+
end
|
219
|
+
cov.code(current_line, :class => "objc")
|
220
|
+
else
|
221
|
+
cov.code(line, :class => "objc")
|
222
|
+
end
|
223
|
+
}
|
175
224
|
}
|
176
225
|
end
|
177
226
|
}
|
@@ -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] << [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,12 @@ 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
|
-
|
138
|
+
filename = file["filename"]
|
139
|
+
path = Pathname(filename)
|
140
|
+
# Don't crash if the file doesn't exist on disk.
|
141
|
+
# This may happen for autogenerated files that have been deleted.
|
142
|
+
filename = path.exist? ? path.realpath : filename
|
143
|
+
{"filename" => filename, "segments" => file["segments"]}
|
139
144
|
end)
|
140
145
|
end
|
141
146
|
end
|
@@ -162,13 +167,24 @@ module Slather
|
|
162
167
|
end
|
163
168
|
private :create_coverage_files_for_binary
|
164
169
|
|
165
|
-
def create_coverage_files(binary_path,
|
170
|
+
def create_coverage_files(binary_path, path_objects)
|
166
171
|
line_numbers_first = Gem::Version.new(self.llvm_version) >= Gem::Version.new('8.1.0')
|
172
|
+
# get just file names from the path objects
|
173
|
+
pathnames = path_objects.map { |path_obj| path_obj["filename"] }.compact
|
174
|
+
# Map of path name => segment array
|
175
|
+
paths_to_segments = path_objects.reduce(Hash.new) do |hash, path_obj|
|
176
|
+
hash[path_obj["filename"]] = path_obj["segments"]
|
177
|
+
hash
|
178
|
+
end
|
167
179
|
files = create_profdata(binary_path, pathnames)
|
168
180
|
files.map do |source|
|
169
181
|
coverage_file = coverage_file_class.new(self, source, line_numbers_first)
|
170
182
|
# If a single source file is used, the resulting output does not contain the file name.
|
171
183
|
coverage_file.source_file_pathname = pathnames.first if pathnames.count == 1
|
184
|
+
# if there is segment data for the given path, add it to the coverage_file
|
185
|
+
if paths_to_segments.key?(coverage_file.source_file_pathname)
|
186
|
+
coverage_file.segments = paths_to_segments[coverage_file.source_file_pathname]
|
187
|
+
end
|
172
188
|
!coverage_file.ignored? ? coverage_file : nil
|
173
189
|
end.compact
|
174
190
|
end
|
@@ -192,7 +208,7 @@ module Slather
|
|
192
208
|
|
193
209
|
def profdata_coverage_dir
|
194
210
|
@profdata_coverage_dir ||= begin
|
195
|
-
raise StandardError, "The specified build directory (#{self.build_directory}) does not exist" unless File.
|
211
|
+
raise StandardError, "The specified build directory (#{self.build_directory}) does not exist" unless File.exist?(self.build_directory)
|
196
212
|
dir = nil
|
197
213
|
if self.scheme
|
198
214
|
dir = Dir[File.join(build_directory,"/**/CodeCoverage/#{self.scheme}")].first
|
@@ -277,7 +293,10 @@ module Slather
|
|
277
293
|
if self.arch
|
278
294
|
llvm_cov_args << "--arch" << self.arch
|
279
295
|
end
|
280
|
-
|
296
|
+
|
297
|
+
# 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".
|
298
|
+
# Using the xargs command we can break the list of source_files into sublists small enough to be acceptable.
|
299
|
+
`printf '%s\\0' #{source_files.shelljoin} | xargs -0 xcrun llvm-cov #{llvm_cov_args.shelljoin}`
|
281
300
|
end
|
282
301
|
private :unsafe_profdata_llvm_cov_output
|
283
302
|
|
@@ -356,7 +375,7 @@ module Slather
|
|
356
375
|
end
|
357
376
|
|
358
377
|
def configure_ci_service
|
359
|
-
self.ci_service ||= (self.class.yml["ci_service"] || :
|
378
|
+
self.ci_service ||= (ENV["CI_SERVICE"] || self.class.yml["ci_service"] || :other)
|
360
379
|
end
|
361
380
|
|
362
381
|
def configure_input_format
|
@@ -484,7 +503,7 @@ module Slather
|
|
484
503
|
end
|
485
504
|
end
|
486
505
|
|
487
|
-
raise StandardError, "No scheme named '#{self.scheme}' found in #{self.path}" unless File.
|
506
|
+
raise StandardError, "No scheme named '#{self.scheme}' found in #{self.path}" unless File.exist? xcscheme_path
|
488
507
|
|
489
508
|
xcscheme = Xcodeproj::XCScheme.new(xcscheme_path)
|
490
509
|
|
@@ -568,6 +587,19 @@ module Slather
|
|
568
587
|
def find_buildable_names(xcscheme)
|
569
588
|
found_buildable_names = []
|
570
589
|
|
590
|
+
# enumerate code coverage targets
|
591
|
+
begin
|
592
|
+
code_coverage_targets = xcscheme.test_action.xml_element.elements['CodeCoverageTargets']
|
593
|
+
targets = code_coverage_targets.map do |node|
|
594
|
+
Xcodeproj::XCScheme::BuildableReference.new(node) if node.is_a?(REXML::Element)
|
595
|
+
end.compact
|
596
|
+
buildable_names = targets.each do |target|
|
597
|
+
found_buildable_names.push(target.buildable_name)
|
598
|
+
end
|
599
|
+
rescue
|
600
|
+
# just in case if there are no entries in the test action
|
601
|
+
end
|
602
|
+
|
571
603
|
# enumerate build action entries
|
572
604
|
begin
|
573
605
|
xcscheme.build_action.entries.each do |entry|
|
data/lib/slather/version.rb
CHANGED
data/slather.gemspec
CHANGED
@@ -28,8 +28,8 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency 'equivalent-xml', '~> 0.6'
|
29
29
|
|
30
30
|
spec.add_dependency 'clamp', '~> 1.3'
|
31
|
-
spec.add_dependency 'xcodeproj', '~> 1.
|
32
|
-
spec.add_dependency 'nokogiri', '
|
31
|
+
spec.add_dependency 'xcodeproj', '~> 1.21'
|
32
|
+
spec.add_dependency 'nokogiri', '>= 1.13.9'
|
33
33
|
spec.add_dependency 'CFPropertyList', '>= 2.2', '< 4'
|
34
34
|
|
35
35
|
spec.add_runtime_dependency 'activesupport'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
//
|
2
|
+
// FixtureFramework.h
|
3
|
+
// FixtureFramework
|
4
|
+
//
|
5
|
+
// Created by Stephen Williams on 11/03/21.
|
6
|
+
// Copyright © 2021 marklarr. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#import <Foundation/Foundation.h>
|
10
|
+
|
11
|
+
//! Project version number for FixtureFramework.
|
12
|
+
FOUNDATION_EXPORT double FixtureFrameworkVersionNumber;
|
13
|
+
|
14
|
+
//! Project version string for FixtureFramework.
|
15
|
+
FOUNDATION_EXPORT const unsigned char FixtureFrameworkVersionString[];
|
16
|
+
|
17
|
+
// In this header, you should import all the public headers of your framework using statements like #import <FixtureFramework/PublicHeader.h>
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
7
|
+
<key>CFBundleExecutable</key>
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
9
|
+
<key>CFBundleIdentifier</key>
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
12
|
+
<string>6.0</string>
|
13
|
+
<key>CFBundleName</key>
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
15
|
+
<key>CFBundlePackageType</key>
|
16
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
17
|
+
<key>CFBundleShortVersionString</key>
|
18
|
+
<string>1.0</string>
|
19
|
+
<key>CFBundleVersion</key>
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
21
|
+
<key>NSHumanReadableCopyright</key>
|
22
|
+
<string>Copyright © 2021 marklarr. All rights reserved.</string>
|
23
|
+
</dict>
|
24
|
+
</plist>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
//
|
2
|
+
// FixtureFrameworkTests.swift
|
3
|
+
// FixtureFrameworkTests
|
4
|
+
//
|
5
|
+
// Created by Stephen Williams on 11/03/21.
|
6
|
+
// Copyright © 2021 marklarr. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
import XCTest
|
10
|
+
@testable import FixtureFramework
|
11
|
+
|
12
|
+
class FixtureFrameworkTests: XCTestCase {
|
13
|
+
|
14
|
+
override func setUpWithError() throws {
|
15
|
+
// Put setup code here. This method is called before the invocation of each test method in the class.
|
16
|
+
}
|
17
|
+
|
18
|
+
override func tearDownWithError() throws {
|
19
|
+
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
20
|
+
}
|
21
|
+
|
22
|
+
func testExample() throws {
|
23
|
+
// This is an example of a functional test case.
|
24
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
25
|
+
}
|
26
|
+
|
27
|
+
func testPerformanceExample() throws {
|
28
|
+
// This is an example of a performance test case.
|
29
|
+
self.measure {
|
30
|
+
// Put the code you want to measure the time of here.
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
}
|