slather 2.6.0 → 2.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +2 -0
  4. data/CHANGELOG.md +70 -0
  5. data/assets/slather.css +2 -1
  6. data/lib/slather/command/coverage_command.rb +1 -1
  7. data/lib/slather/coverage_file.rb +1 -1
  8. data/lib/slather/coverage_service/coveralls.rb +73 -6
  9. data/lib/slather/coverage_service/html_output.rb +51 -2
  10. data/lib/slather/profdata_coverage_file.rb +42 -2
  11. data/lib/slather/project.rb +38 -6
  12. data/lib/slather/version.rb +1 -1
  13. data/slather.gemspec +2 -2
  14. data/spec/fixtures/FixtureFramework/FixtureFramework.h +19 -0
  15. data/spec/fixtures/FixtureFramework/FlashExperiment.swift +7 -0
  16. data/spec/fixtures/FixtureFramework/Info.plist +24 -0
  17. data/spec/fixtures/FixtureFrameworkTests/FixtureFrameworkTests.swift +34 -0
  18. data/spec/fixtures/FixtureFrameworkTests/FlashExperimentTests.swift +9 -0
  19. data/spec/fixtures/FixtureFrameworkTests/Info.plist +22 -0
  20. data/spec/fixtures/cobertura.xml +157 -37
  21. data/spec/fixtures/fixtures.xcodeproj/project.pbxproj +222 -0
  22. data/spec/fixtures/fixtures.xcodeproj/xcshareddata/xcschemes/fixtures.xcscheme +21 -5
  23. data/spec/fixtures/fixtures.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  24. data/spec/slather/coverage_service/cobertura_xml_spec.rb +1 -1
  25. data/spec/slather/coverage_service/html_output_spec.rb +2 -2
  26. data/spec/slather/coverage_service/json_spec.rb +1 -1
  27. data/spec/slather/coverage_service/llvm_cov_spec.rb +1 -1
  28. data/spec/slather/coverage_service/sonarqube_xml_spec.rb +1 -1
  29. data/spec/slather/profdata_coverage_spec.rb +16 -0
  30. data/spec/slather/project_spec.rb +10 -6
  31. metadata +23 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eeaf99ed5212bdc90e8098dfde877452af7f074ecfd41fc577d46f90b1ee65eb
4
- data.tar.gz: 5dbd0db5223f26990c2bfd3ab02f4ed36a15d8088a0b5c393f522a785a0176cd
3
+ metadata.gz: b43954fd6f31e519f192e32ad881197d35830912e22158ca17cf333b86f97e0d
4
+ data.tar.gz: 97cf7f9b6eb50d2472aec42c3f698c3a299c38cfd8757cdb2a6e2dcad0933bc6
5
5
  SHA512:
6
- metadata.gz: 6802b4ef28cfb856bf68d214416d6a455de715723327dc7167600bc9cae705dacbdbffb0b8d154b2027dde6d5b2f6baec719f69a81e5293a437da1e260461e73
7
- data.tar.gz: c6b95c762eaa1d5260da5de5910e7f429a79e45556a3b32568ba8c7c9f3ed173ed514330793c39babc767e4f021dda7fc83971750d16407d0149050286495b95
6
+ metadata.gz: f38c40172a16f8375b56cdc873e92339f1f275cef7848bc0d9947714073dd5ff93ba11dc1957781c69316eec59a213c079067b99cb48c134aeb24c20ae2cb945
7
+ data.tar.gz: 1a098f9ab86b11d5c65cea0c309a99a709de76dfdc0f1171f0e100784522a74613cdb3fb06346f4fb1d6e27825250f01ece561ac07bea6e59a489837c7c0c654
data/.gitignore CHANGED
@@ -20,7 +20,7 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
-
23
+ .vendor
24
24
  # Xcode
25
25
  #
26
26
  *.pbxuser
data/.travis.yml CHANGED
@@ -2,6 +2,8 @@ language: objective-c
2
2
  script: bundle exec rake
3
3
  osx_image: xcode12.2
4
4
 
5
+ cache: bundler
6
+
5
7
  before_install:
6
8
  - curl http://curl.haxx.se/ca/cacert.pem -o /usr/local/share/cacert.pem
7
9
  - gem install bundler -v "~> 2.0" --no-document
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 the which the coverage will be run", :multivalued => true
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.exists?(gcov_file_name)
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
- raise StandardError, "No support for ci named #{ci_service}"
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 { cov.code(line, :class => "objc") }
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
 
@@ -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
- Pathname(file["filename"]).realpath
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, pathnames)
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.exists?(self.build_directory)
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
- `xcrun llvm-cov #{llvm_cov_args.shelljoin} #{source_files.shelljoin}`
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"] || :travis_ci)
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.exists? xcscheme_path
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|
@@ -1,3 +1,3 @@
1
1
  module Slather
2
- VERSION = '2.6.0' unless defined?(Slather::VERSION)
2
+ VERSION = '2.7.4' unless defined?(Slather::VERSION)
3
3
  end
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.7'
32
- spec.add_dependency 'nokogiri', '~> 1.8'
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,7 @@
1
+ import Foundation
2
+
3
+ public struct FlashExperiment {
4
+ public let isAwesome = true
5
+
6
+ public init() {}
7
+ }
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ import XCTest
2
+ import FixtureFramework
3
+
4
+ class FlashExperimentTests: XCTestCase {
5
+ func testExample() throws {
6
+ let sut = FlashExperiment()
7
+ XCTAssertTrue(sut.isAwesome, "Your flash experiment isn't awesome!")
8
+ }
9
+ }