Module: EarlGrey
- Defined in:
- lib/earlgrey/version.rb,
lib/earlgrey/cli.rb,
lib/earlgrey/configure_earlgrey.rb,
lib/earlgrey/extensions/analyzer_extensions.rb,
lib/earlgrey/extensions/aggregate_target_extensions.rb
Overview
Copyright 2016 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Defined Under Namespace
Modules: AggregateTargetExtensions, AnalyzerExtension Classes: CLI
Constant Summary collapse
- VERSION =
'1.15.0'.freeze
- XCScheme =
Xcodeproj::XCScheme
- EnvironmentVariable =
XCScheme::EnvironmentVariable
- XCSCHEME_EXT =
'*.xcscheme'.freeze
- ENVIRONMENT_KEY =
'DYLD_INSERT_LIBRARIES'.freeze
- ENVIRONMENT_VALUE =
'@executable_path/EarlGrey.framework/EarlGrey'.freeze
- FRAMEWORK_SEARCH_PATHS =
'FRAMEWORK_SEARCH_PATHS'.freeze
- HEADER_SEARCH_PATHS =
'HEADER_SEARCH_PATHS'.freeze
- SWIFT_FILETYPE =
'sourcecode.swift'.freeze
- UNITTEST_PRODUCTTYPE =
'com.apple.product-type.bundle.unit-test'.freeze
- CARTHAGE_BUILD_IOS =
'$(SRCROOT)/Carthage/Build/iOS'.freeze
- CARTHAGE_HEADERS_IOS =
'$(SRCROOT)/Carthage/Build/iOS/**'.freeze
- EARLGREY_FRAMEWORK =
'EarlGrey.framework'.freeze
- CARTHAGE_FRAMEWORK_PATH =
'Carthage/Build/iOS/EarlGrey.framework'.freeze
- POD_FRAMEWORK_PATH =
'Pods/EarlGrey/EarlGrey/EarlGrey.framework'.freeze
Class Attribute Summary collapse
-
.carthage ⇒ Object
readonly
Returns the value of attribute carthage.
-
.installer ⇒ Object
readonly
Returns the value of attribute installer.
-
.project_name ⇒ Object
readonly
Returns the value of attribute project_name.
-
.scheme_file ⇒ Object
readonly
Returns the value of attribute scheme_file.
-
.swift ⇒ Object
readonly
Returns the value of attribute swift.
-
.swift_version ⇒ Object
readonly
Returns the value of attribute swift_version.
-
.test_target ⇒ Object
readonly
Returns the value of attribute test_target.
-
.test_target_name ⇒ Object
readonly
Returns the value of attribute test_target_name.
-
.user_project ⇒ Object
readonly
Returns the value of attribute user_project.
Class Method Summary collapse
-
.add_carthage_copy_phase(target) ⇒ Object
Add Carthage copy phase.
-
.add_carthage_search_paths(target) ⇒ PBXNativeTarget
Updates test target’s build configuration framework and header search paths for carthage.
-
.add_earlgrey_copy_files_script(target, framework_ref) ⇒ Object
Generates a copy files build phase to embed the EarlGrey framework into the app under test.
-
.add_earlgrey_framework(target, framework_ref) ⇒ Object
Add EarlGrey.framework into the build phase “Link Binary With Libraries”.
-
.add_earlgrey_product(project, carthage) ⇒ Object
Adds EarlGrey.framework to products group.
-
.add_environment_variables_to_test_scheme(name, scheme) ⇒ Object
Load the EarlGrey framework when the app binary is loaded by the dynamic loader, before the main() method is called.
-
.configure_for_earlgrey(project_name, test_target_name, scheme_file, opts = {}) ⇒ nil
Main entry point.
-
.copy_swift_files(project, target, swift_version = nil) ⇒ Object
Copies EarlGrey.swift and adds it to the project.
-
.dir_path ⇒ String
Returns the project’s directory.
-
.error(message) ⇒ nil
Raise error message after removing excessive spaces.
-
.has_swift?(target) ⇒ Boolean
Check if the target contains a swift source file rubocop:disable Style/PredicateName.
-
.modify_scheme_for_actions(project, targets) ⇒ Array<String, Xcodeproj::XCScheme>
Add DYLD_INSERT_LIBRARIES to the launching environments for the test schemes to ensure that EarlGrey is correctly loaded before main() is called.
-
.path_for(project_name, ext) ⇒ String
Returns path to Xcode file, prepending current working dir if necessary.
-
.puts_magenta(string) ⇒ nil
Prints string as magenta after stripping excess spacing.
-
.puts_yellow(string) ⇒ nil
Prints string as yellow after stripping excess spacing.
-
.schemes_for_native_targets(project, targets) ⇒ Array<Xcodeproj::XCScheme>
Returns the schemes that contain the given targets.
- .set_defaults(project_name, test_target_name, scheme_file, opts = {}) ⇒ Object
-
.strip(string) ⇒ String
Strips each line in a string.
Class Attribute Details
.carthage ⇒ Object (readonly)
Returns the value of attribute carthage.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def carthage @carthage end |
.installer ⇒ Object (readonly)
Returns the value of attribute installer.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def installer @installer end |
.project_name ⇒ Object (readonly)
Returns the value of attribute project_name.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def project_name @project_name end |
.scheme_file ⇒ Object (readonly)
Returns the value of attribute scheme_file.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def scheme_file @scheme_file end |
.swift ⇒ Object (readonly)
Returns the value of attribute swift.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def swift @swift end |
.swift_version ⇒ Object (readonly)
Returns the value of attribute swift_version.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def swift_version @swift_version end |
.test_target ⇒ Object (readonly)
Returns the value of attribute test_target.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def test_target @test_target end |
.test_target_name ⇒ Object (readonly)
Returns the value of attribute test_target_name.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def test_target_name @test_target_name end |
.user_project ⇒ Object (readonly)
Returns the value of attribute user_project.
56 57 58 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 56 def user_project @user_project end |
Class Method Details
.add_carthage_copy_phase(target) ⇒ Object
Add Carthage copy phase
327 328 329 330 331 332 333 334 335 336 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 327 def add_carthage_copy_phase(target) shell_script_name = 'Carthage copy-frameworks Run Script' target_names = target.shell_script_build_phases.map(&:name) unless target_names.include?(shell_script_name) shell_script = target.new_shell_script_build_phase shell_script_name shell_script.shell_path = '/bin/bash' shell_script.shell_script = '/usr/local/bin/carthage copy-frameworks' shell_script.input_paths = [CARTHAGE_FRAMEWORK_PATH] end end |
.add_carthage_search_paths(target) ⇒ PBXNativeTarget
Updates test target’s build configuration framework and header search paths for carthage. Generates a copy files build phase to embed the EarlGrey framework into the app under test.
310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 310 def add_carthage_search_paths(target) target.build_configurations.each do |config| settings = config.build_settings settings[FRAMEWORK_SEARCH_PATHS] = Array(settings[FRAMEWORK_SEARCH_PATHS]) unless settings[FRAMEWORK_SEARCH_PATHS].include?(CARTHAGE_BUILD_IOS) settings[FRAMEWORK_SEARCH_PATHS] << CARTHAGE_BUILD_IOS end settings[HEADER_SEARCH_PATHS] = Array(settings[HEADER_SEARCH_PATHS]) settings[HEADER_SEARCH_PATHS] << CARTHAGE_HEADERS_IOS unless settings[HEADER_SEARCH_PATHS].include?(CARTHAGE_HEADERS_IOS) end target end |
.add_earlgrey_copy_files_script(target, framework_ref) ⇒ Object
Generates a copy files build phase to embed the EarlGrey framework into the app under test.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 288 def add_earlgrey_copy_files_script(target, framework_ref) earlgrey_copy_files_phase_name = 'EarlGrey Copy Files' return true if target.copy_files_build_phases.any? do |copy_files_phase| copy_files_phase.name == earlgrey_copy_files_phase_name end return false unless target.product_type.eql? UNITTEST_PRODUCTTYPE new_copy_files_phase = target.new_copy_files_build_phase(earlgrey_copy_files_phase_name) new_copy_files_phase.dst_path = '$(TEST_HOST)/../' new_copy_files_phase.dst_subfolder_spec = '0' build_file = new_copy_files_phase.add_file_reference framework_ref, true build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy'] } build_file end |
.add_earlgrey_framework(target, framework_ref) ⇒ Object
Add EarlGrey.framework into the build phase “Link Binary With Libraries”
343 344 345 346 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 343 def add_earlgrey_framework(target, framework_ref) linked_frameworks = target.frameworks_build_phase.files.map(&:display_name) target.frameworks_build_phase.add_file_reference framework_ref, true unless linked_frameworks.include? EARLGREY_FRAMEWORK end |
.add_earlgrey_product(project, carthage) ⇒ Object
Adds EarlGrey.framework to products group. Returns file ref.
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 262 def add_earlgrey_product(project, carthage) framework_path = if carthage CARTHAGE_FRAMEWORK_PATH else POD_FRAMEWORK_PATH end framework_ref = project.frameworks_group.files.find do |f| # TODO: should have some md5 check on the actual binary f.path == framework_path end unless framework_ref framework_ref = project.frameworks_group.new_file(framework_path) framework_ref.source_tree = 'SOURCE_ROOT' end framework_ref end |
.add_environment_variables_to_test_scheme(name, scheme) ⇒ Object
Load the EarlGrey framework when the app binary is loaded by the dynamic loader, before the main() method is called.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 218 def add_environment_variables_to_test_scheme(name, scheme) name = File.basename(name, '.xcscheme') test_action = scheme.test_action test_variables = test_action.environment_variables # If any environment variables or arguments were being used in the test # action by being copied from the launch (run) action then copy them over # to the test action along with the EarlGrey environment variable. if test_action.should_use_launch_scheme_args_env? scheme.launch_action.environment_variables.all_variables.each do |var| test_variables.assign_variable var end end env_variable = test_variables[ENVIRONMENT_KEY] || EnvironmentVariable.new(key: ENVIRONMENT_KEY, value: '') if env_variable.value.include? ENVIRONMENT_VALUE puts_magenta <<-S DYLD_INSERT_LIBRARIES is already set up for #{name}, ignored. S return scheme end puts_magenta <<-S Adding EarlGrey Framework Location as an Environment Variable in the App Project's Test Target's Scheme Test Action #{name}. S test_action.should_use_launch_scheme_args_env = false env_variable.value += env_variable.value.empty? ? '' : ':' env_variable.value += ENVIRONMENT_VALUE env_variable.enabled = true test_variables.assign_variable env_variable test_action.environment_variables = test_variables scheme.save! end |
.configure_for_earlgrey(project_name, test_target_name, scheme_file, opts = {}) ⇒ nil
Main entry point. Configures An Xcode project for use with EarlGrey.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 146 def configure_for_earlgrey(project_name, test_target_name, scheme_file, opts = {}) set_defaults(project_name, test_target_name, scheme_file, opts) # Add DYLD_INSERT_LIBRARIES to the schemes # rubocop:disable Performance/HashEachMethods modify_scheme_for_actions(user_project, [test_target]).each do |_, scheme| scheme.save! end # rubocop:enable Performance/HashEachMethods # Add a Copy Files Build Phase for EarlGrey.framework to embed it into # the app under test. framework_ref = add_earlgrey_product user_project, carthage add_earlgrey_framework test_target, framework_ref add_earlgrey_copy_files_script test_target, framework_ref # Add header/framework search paths for carthage add_carthage_search_paths test_target if carthage # Adds EarlGrey.swift copy_swift_files(user_project, test_target, swift_version) if swift user_project.save puts_magenta <<-S EarlGrey setup complete. You can use the Test Target: #{test_target_name} for EarlGrey testing. S end |
.copy_swift_files(project, target, swift_version = nil) ⇒ Object
Copies EarlGrey.swift and adds it to the project. No op if the target doesn’t contain swift.
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 364 def copy_swift_files(project, target, swift_version = nil) return unless has_swift?(target) || !swift_version.to_s.empty? project_test_targets = project.main_group.children test_target_group = project_test_targets.find { |g| g.display_name == target.name } raise "Test target group not found! #{test_target_group}" unless test_target_group swift_version ||= '4.0' src_root = File.join(__dir__, 'files') dst_root = test_target_group.real_path raise "Missing target folder #{dst_root}" unless File.exist? dst_root src_swift_name = 'EarlGrey.swift' src_swift = File.join(src_root, "Swift-#{swift_version}", src_swift_name) unless File.exist? src_swift puts_magenta "EarlGrey.swift for version #{swift_version} not found. " \ 'Falling back to version 4.0.' swift_fallback = 'Swift-4.0' src_swift = File.join(src_root, swift_fallback, src_swift_name) raise "Unable to locate #{swift_fallback} file at path #{src_swift}." unless File.exist?(src_swift) end dst_swift = File.join(dst_root, src_swift_name) FileUtils.copy src_swift, dst_swift # Add files to testing target group otherwise Xcode can't read them. new_files = [src_swift_name] existing_files = test_target_group.children.map(&:display_name) new_files.each do |file| next if existing_files.include? file test_target_group.new_reference(file) end # Add EarlGrey.swift to sources build phase existing_sources = target.source_build_phase.files.map(&:display_name) unless existing_sources.include? src_swift_name target_files = test_target_group.files earlgrey_swift_file_ref = target_files.find { |f| f.display_name == src_swift_name } raise 'EarlGrey.swift not found in testing target' unless earlgrey_swift_file_ref target.source_build_phase.add_file_reference earlgrey_swift_file_ref, true end end |
.dir_path ⇒ String
Returns the project’s directory. If CocoaPods hasn’t had it passed in, then the current directory is chosen.
73 74 75 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 73 def dir_path installer ? installer.config.installation_root : Dir.pwd end |
.error(message) ⇒ nil
Raise error message after removing excessive spaces.
87 88 89 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 87 def error() raise strip() end |
.has_swift?(target) ⇒ Boolean
Check if the target contains a swift source file rubocop:disable Style/PredicateName
352 353 354 355 356 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 352 def has_swift?(target) target.source_build_phase.files_references.any? do |ref| SWIFT_FILETYPE == (ref.last_known_file_type || ref.explicit_file_type) end end |
.modify_scheme_for_actions(project, targets) ⇒ Array<String, Xcodeproj::XCScheme>
Add DYLD_INSERT_LIBRARIES to the launching environments for the test schemes to ensure that EarlGrey is correctly loaded before main() is called.
204 205 206 207 208 209 210 211 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 204 def modify_scheme_for_actions(project, targets) schemes = schemes_for_native_targets(project, targets).uniq do |name, _| name end schemes.each do |name, scheme| add_environment_variables_to_test_scheme(name, scheme) end end |
.path_for(project_name, ext) ⇒ String
Returns path to Xcode file, prepending current working dir if necessary.
63 64 65 66 67 68 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 63 def path_for(project_name, ext) ext_match = File.extname(project_name) == ext return project_name if File.exist?(project_name) && ext_match path = File.join(dir_path, File.basename(project_name, '.*') + ext) path ? path : nil end |
.puts_magenta(string) ⇒ nil
Prints string as magenta after stripping excess spacing
94 95 96 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 94 def puts_magenta(string) puts strip(string).magenta end |
.puts_yellow(string) ⇒ nil
Prints string as yellow after stripping excess spacing
101 102 103 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 101 def puts_yellow(string) puts strip(string).yellow end |
.schemes_for_native_targets(project, targets) ⇒ Array<Xcodeproj::XCScheme>
Returns the schemes that contain the given targets
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 181 def schemes_for_native_targets(project, targets) schemes = Dir[File.join(XCScheme.shared_data_dir(project.path), XCSCHEME_EXT)] + Dir[File.join(XCScheme.user_data_dir(project.path), XCSCHEME_EXT)] schemes = schemes.map { |scheme| [scheme, Xcodeproj::XCScheme.new(scheme)] } targets_names = targets.map(&:name) schemes.select do |scheme| scheme[1].test_action.testables.any? do |testable| testable.buildable_references.any? do |buildable| targets_names.include? buildable.target_name end end end end |
.set_defaults(project_name, test_target_name, scheme_file, opts = {}) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 105 def set_defaults(project_name, test_target_name, scheme_file, opts = {}) @swift = opts.fetch(:swift, false) @carthage = opts.fetch(:carthage, false) @swift_version = opts.fetch(:swift_version, '4.0') puts_magenta "Checking and Updating #{project_name} for EarlGrey." project_file = path_for project_name, '.xcodeproj' raise 'No test target provided' unless test_target_name if project_file.nil? error <<-E The target's xcodeproj file could not be found. Please check if the correct PROJECT_NAME is being passed in the Podfile. Current PROJECT_NAME is: #{project_name} E end @project_name = project_name @test_target_name = test_target_name @scheme_file = File.basename(scheme_file, '.*') + '.xcscheme' @user_project = Xcodeproj::Project.open(project_file) all_targets = user_project.targets @test_target = all_targets.find { |target| target.name == test_target_name } unless test_target error <<-E Unable to find target: #{test_target_name}. Targets are: #{all_targets.map(&:name)} E end end |
.strip(string) ⇒ String
Strips each line in a string
80 81 82 |
# File 'lib/earlgrey/configure_earlgrey.rb', line 80 def strip(string) string.split("\n").map(&:strip).join("\n") end |