slather 2.6.0 → 2.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eeaf99ed5212bdc90e8098dfde877452af7f074ecfd41fc577d46f90b1ee65eb
4
- data.tar.gz: 5dbd0db5223f26990c2bfd3ab02f4ed36a15d8088a0b5c393f522a785a0176cd
3
+ metadata.gz: 6791a42172a6764126080d1fa51acce74d384c68687e3bb657bd0311e54cac0a
4
+ data.tar.gz: 11b47fcf1ff99baa4ea01cbe9fd202a0db9f3f9e7ad76c5b8b79b23516128cd0
5
5
  SHA512:
6
- metadata.gz: 6802b4ef28cfb856bf68d214416d6a455de715723327dc7167600bc9cae705dacbdbffb0b8d154b2027dde6d5b2f6baec719f69a81e5293a437da1e260461e73
7
- data.tar.gz: c6b95c762eaa1d5260da5de5910e7f429a79e45556a3b32568ba8c7c9f3ed173ed514330793c39babc767e4f021dda7fc83971750d16407d0149050286495b95
6
+ metadata.gz: 07bfabe0e5af2083b8aba45676989ea8d90b7e26ba276a17a64e93e184be42229e1e869b990623c0a8fa4df0306748b4e0c6b68821c90d5b18dc88109dc52ae1
7
+ data.tar.gz: bc8b62cc1b47b59d67f8acff77a9b2910c4b82273035257470ded7376e3ca4930146aa3105d3c8bb910c12acbb5cf36a35909d825ef4e85b593ce65a7cba99e5
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,58 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v2.7.2
4
+
5
+ * Update xcodeproj version
6
+ [adamyanalunas](https://github.com/adamyanalunas)
7
+ [#502](https://github.com/SlatherOrg/slather/pull/502)
8
+
9
+ * Update nokogiri version
10
+ [jwelton](https://github.com/jwelton)
11
+ [#503](https://github.com/SlatherOrg/slather/pull/503)
12
+
13
+ * Support alternate CI systems in coveralls output
14
+ [fermoyadrop](https://github.com/fermoyadrop)
15
+ [#504](https://github.com/SlatherOrg/slather/pull/504)
16
+
17
+ * Add Bitrise support to coveralls output
18
+ [fermoyadrop](https://github.com/fermoyadrop)
19
+ [#504](https://github.com/SlatherOrg/slather/pull/505)
20
+
21
+ ## v2.7.1
22
+
23
+ * Support generating coverage for framework targets
24
+ [onato](https://github.com/onato)
25
+ [#482](https://github.com/SlatherOrg/slather/pull/482)
26
+
27
+ * Show number of lines in HTML report
28
+ [SiemianHS](https://github.com/SiemianHS)
29
+ [#494](https://github.com/SlatherOrg/slather/pull/494)
30
+
31
+ * Fixed issues with HTML report generation
32
+ [fchiba](https://github.com/fchiba)
33
+ [#483](https://github.com/SlatherOrg/slather/pull/483)
34
+ [#484](https://github.com/SlatherOrg/slather/pull/484)
35
+
36
+ * Don't fail if a source file doesn't exist
37
+ [chillpop](https://github.com/chillpop)
38
+ [#492](https://github.com/SlatherOrg/slather/pull/492)
39
+
40
+ ## v2.7.0
41
+
42
+ * Add Branch Coverage data for ProfData coverage files
43
+ [hborawski](https://github.com/hborawski)
44
+ [#477](https://github.com/SlatherOrg/slather/pull/477)
45
+
46
+ * Fixed 'Argument list too long' when running 'xcrun llvm-cov'
47
+ [samuelsainz](https://github.com/samuelsainz)
48
+ [#476](https://github.com/SlatherOrg/slather/pull/476)
49
+
50
+ ## v2.6.1
51
+
52
+ * Update nokogiri to 1.11
53
+ [ashin-omg](https://github.com/ashin-omg)
54
+ [#473](https://github.com/SlatherOrg/slather/pull/473)
55
+
3
56
  ## v2.6.0
4
57
 
5
58
  * 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
  }
@@ -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,6 +166,19 @@ 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
@@ -263,8 +291,35 @@ module Slather
263
291
  else
264
292
  raise StandardError, "Environment variable `GITHUB_RUN_ID` not set. Is this running on github build?"
265
293
  end
294
+ elsif ci_service == :bitrise
295
+ {
296
+ :service_job_id => bitrise_job_id,
297
+ :service_name => 'bitrise',
298
+ :repo_token => coverage_access_token,
299
+ :source_files => coverage_files.map(&:as_json),
300
+ :service_pull_request => bitrise_pull_request,
301
+ :service_branch => bitrise_branch_name,
302
+ :git => bitrise_git_info
303
+ }.to_json
266
304
  else
267
- raise StandardError, "No support for ci named #{ci_service}"
305
+ {
306
+ :service_job_id => ENV['CI_BUILD_NUMBER'],
307
+ :service_name => ENV['CI_NAME'] || ci_service,
308
+ :repo_token => coverage_access_token,
309
+ :source_files => coverage_files.map(&:as_json),
310
+ :service_build_url => ENV['CI_BUILD_URL'],
311
+ :service_pull_request => ENV['CI_PULL_REQUEST'],
312
+ :service_branch => ENV['CI_BRANCH'],
313
+ :git => {
314
+ :head => {
315
+ :id => ENV['CI_COMMIT'],
316
+ :committer_name => (`git log --format=%an -n 1 HEAD`.chomp || ""),
317
+ :committer_email => (`git log --format=%ae -n 1 HEAD`.chomp || ""),
318
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
319
+ },
320
+ :branch => ENV['CI_BRANCH']
321
+ }
322
+ }.to_json
268
323
  end
269
324
  end
270
325
  private :coveralls_coverage_data
@@ -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
@@ -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
@@ -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.2' 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.12'
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
+ }
@@ -0,0 +1,22 @@
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>1</string>
21
+ </dict>
22
+ </plist>