earlgrey 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46ff0c7e101aa31fa6d4d5c9604b4488561ecfca
4
- data.tar.gz: 176c09aa8a9c05e5e3cedec7a29d3dd74d7f78e4
3
+ metadata.gz: ed68b90f6bd6d7e53fa0cfe464cd16ffe0672ecc
4
+ data.tar.gz: 9c3fc73e5fcd2258afa374bd69c8bd4786c0bb95
5
5
  SHA512:
6
- metadata.gz: b55724a388c4a51cef26f87695a8723630e7a7b93c2e25e52aed0d2d90df708a6d091e1bd46061bfb8a651fa3c5021498536cc4c5e1028c74cd834a946db786c
7
- data.tar.gz: 17765b512b7894581951204ec174191eddac38e4c01ab4d7d10843a6f73729d24ecf104c93afef4079d912668a7515db4fdc454b41e950c5ec7c6d833bf6ea01
6
+ metadata.gz: a3ee69f75fb90f659a17ba74b7be44a2f5f36022331d94c364e6458361a47983589526376c4e4d451b88cbfbbe8ef2d6abcb6232cd5836ab9d503272a57fff04
7
+ data.tar.gz: 446c5a42857f11b30ef01f9259c414239233586f396d5e457fe9a65f5a3c6f891365f78e0eaf7bad2e48f110b3d35dd43c62da77eb9669ee7ad52db3d3da1b67
data/bin/earlgrey ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/earlgrey'
4
+
5
+ EarlGrey::CLI.start
data/lib/earlgrey.rb CHANGED
@@ -1 +1 @@
1
- require_relative 'earlgrey/version'
1
+ require_relative 'earlgrey/earlgrey'
@@ -0,0 +1,43 @@
1
+ module EarlGrey
2
+ class CLI < Thor
3
+ package_name 'EarlGrey'
4
+
5
+ desc 'install', 'Installs EarlGrey into an Xcode unit test target'
6
+ method_option :project, aliases: '-p', type: :string, required: false, desc: 'Project'
7
+ method_option :target, aliases: '-t', type: :string, required: true, desc: 'EarlGrey'
8
+ method_option :scheme, aliases: '-s', type: :string, required: false, desc: 'EarlGrey.xcscheme'
9
+ method_option :swift, type: :boolean, default: true
10
+ method_option :carthage, type: :boolean, default: true
11
+
12
+ def install
13
+ o = options.dup
14
+
15
+ project, target, scheme, swift, carthage = 'project', 'target', 'scheme', 'swift', 'carthage'
16
+
17
+ # CLI will never use Cocoapod's `post_install do |installer|`
18
+ podfile_installer = nil
19
+ EarlGrey.swift = o[swift]
20
+ EarlGrey.carthage = o[carthage]
21
+
22
+ # Use target as the default Scheme name.
23
+ o[scheme] ||= o[target]
24
+
25
+ o[project] ||= Dir.glob(File.join(Dir.pwd, '*.xcodeproj')).first
26
+ fail 'No project found' unless o[project]
27
+
28
+ EarlGrey.configure_for_earlgrey podfile_installer, o[project], o[target], o[scheme]
29
+ end
30
+ end
31
+ end
32
+
33
+ # earlgrey install -t Grey3
34
+ =begin
35
+ require 'xcodeproj'
36
+ project_file = '/Users/bootstraponline/Desktop/code/swift_xcuitest_example/Example/Example.xcodeproj'
37
+ user_project = Xcodeproj::Project.open(project_file)
38
+
39
+ test_target_name = 'Grey3'
40
+ all_targets = user_project.targets
41
+ test_target = all_targets.find { |target| target.name == test_target_name }
42
+
43
+ =end
@@ -0,0 +1,332 @@
1
+ #
2
+ # Copyright 2016 Google Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # global export for unqualified use in Pods file
17
+ def configure_for_earlgrey *args
18
+ EarlGrey.configure_for_earlgrey *args
19
+ end
20
+
21
+ module EarlGrey
22
+ class << self
23
+ attr_accessor :swift, :carthage
24
+ attr_reader :project_name, :test_target, :test_target_name, :scheme_file, :user_project
25
+
26
+ def path_for xcode_file, ext
27
+ return xcode_file if File.exist? xcode_file
28
+
29
+ path = File.join(Dir.pwd, File.basename(xcode_file, '.*') + ext)
30
+ path ? path : nil
31
+ end
32
+
33
+ def configure_for_earlgrey(installer, project_name, test_target_name, scheme_file)
34
+ puts ("Checking and Updating #{project_name} for EarlGrey.").blue
35
+ pods_project = installer ? installer.pods_project : true
36
+ project_file = path_for project_name, '.xcodeproj'
37
+
38
+ fail 'No test target provided' unless test_target_name
39
+
40
+ if pods_project.nil? || project_file.nil?
41
+ fail "The target's xcodeproj file could not be found. Please check if "\
42
+ 'the correct PROJECT_NAME is being passed in the Podfile. Current '\
43
+ "PROJECT_NAME is: #{project_name}"
44
+ end
45
+
46
+ @project_name = project_name
47
+ @test_target_name = test_target_name
48
+ @scheme_file = File.basename(scheme_file, '.*') + '.xcscheme'
49
+ @user_project = Xcodeproj::Project.open(project_file)
50
+ all_targets = user_project.targets
51
+ @test_target = all_targets.find { |target| target.name == test_target_name }
52
+ fail "Unable to find target: #{test_target_name}. Targets are: #{all_targets.map &:name}" unless test_target
53
+
54
+
55
+ # Add a Test Action to the User Project Scheme.
56
+ scheme = modify_scheme_for_actions
57
+
58
+ # Add a Copy Files Build Phase for EarlGrey.framework to embed it into the app under test.
59
+ # carthage uses carthage copy-frameworks instead of a copy files build phase.
60
+ add_earlgrey_copy_files_script unless carthage
61
+
62
+ # Add header/framework search paths for carthage
63
+ add_carthage_search_paths
64
+
65
+ # Adds BridgingHeader.h, EarlGrey.swift and sets bridging header.
66
+ copy_swift_files
67
+
68
+ save_earlgrey_scheme_changes(scheme) unless scheme.nil?
69
+
70
+ puts ("EarlGrey setup complete. You can use the Test Target : #{test_target_name} "\
71
+ "for EarlGrey testing.").blue
72
+ end
73
+
74
+ # Scheme changes to ensure that EarlGrey is correctly loaded before main() is called.
75
+ def modify_scheme_for_actions
76
+ scheme_filename = scheme_file
77
+ # If you do not pass on a scheme name, we set it to the project name itself.
78
+ if scheme_filename.to_s == ''
79
+ scheme_filename = project_name
80
+ end
81
+
82
+ xcdata_dir = Xcodeproj::XCScheme.user_data_dir(user_project.path)
83
+ unless File.exist?(File.join(xcdata_dir, scheme_filename).to_s)
84
+ xcdata_dir = Xcodeproj::XCScheme.shared_data_dir(user_project.path)
85
+ end
86
+
87
+ unless File.exist?(File.join(xcdata_dir, scheme_filename).to_s)
88
+ fail "The required scheme \"" + scheme_filename +"\" could not be found."
89
+ ' Please ensure that the required scheme file exists within your'\
90
+ ' project directory.'
91
+ end
92
+ scheme = Xcodeproj::XCScheme.new File.join(xcdata_dir, scheme_filename)
93
+ test_action_key = 'DYLD_INSERT_LIBRARIES'
94
+ test_action_value = '@executable_path/EarlGrey.framework/EarlGrey'
95
+ if not scheme.test_action.xml_element.to_s.include? test_action_value
96
+ scheme =
97
+ add_environment_variables_to_test_action_scheme(scheme_filename,
98
+ scheme,
99
+ test_action_key,
100
+ test_action_value)
101
+ end
102
+
103
+ return scheme
104
+ end
105
+
106
+ # Load the EarlGrey framework when the app binary is loaded by
107
+ # the dynamic loader, before the main() method is called.
108
+ def add_environment_variables_to_test_action_scheme(scheme_filename,
109
+ scheme,
110
+ test_action_key,
111
+ test_action_value)
112
+ test_action = scheme.test_action
113
+ if (scheme.test_action.xml_element.to_s.include? test_action_key) ||
114
+ (scheme.launch_action.xml_element.to_s.include? test_action_key)
115
+ puts ("\n//////////////////// EARLGREY SCHEME ISSUE ////////////////////\n"\
116
+ "EarlGrey failed to modify the Test Action part of the scheme: " + scheme_filename + "\n"\
117
+ + "for one of following reasons:\n\n"\
118
+ "1) DYLD_INSERT_LIBRARIES is already defined under Environment Variables of\n"\
119
+ "the Test Action.\n"\
120
+ "2) Run Action's environment variables are used for Test Action.\n\n"\
121
+ "To ensure correct functioning of EarlGrey, please manually add the\n"\
122
+ "following under Test Action's Environment Variables of the scheme:" + scheme_filename + "\n"\
123
+ "Environment Variables or EarlGrey's location will not be found.\n"\
124
+ "Name: DYLD_INSERT_LIBRARIES\n"\
125
+ "Value: @executable_path/EarlGrey.framework/EarlGrey\n"\
126
+ "///////////////////////////////////////////////////////////////\n\n").yellow
127
+ return
128
+ end
129
+ puts "Adding EarlGrey Framework Location as an Environment Variable "
130
+ "in the App Project's Test Target's Scheme Test Action."
131
+
132
+ # Check if the test action uses the run action's environment variables and arguments.
133
+ launch_action_env_args_present = false
134
+ if (scheme.test_action.xml_element.to_s.include? 'shouldUseLaunchSchemeArgsEnv') &&
135
+ ((scheme.launch_action.xml_element.to_s.include? '<EnvironmentVariables>') ||
136
+ (scheme.launch_action.xml_element.to_s.include? '<CommandLineArguments>'))
137
+ launch_action_env_args_present = true
138
+ end
139
+
140
+ test_action_isEnabled = 'YES'
141
+ test_action.should_use_launch_scheme_args_env = false
142
+
143
+ # If no environment variables are set, then create the element itself.
144
+ unless scheme.test_action.xml_element.to_s.include? '<EnvironmentVariables>'
145
+ scheme.test_action.xml_element.add_element('EnvironmentVariables')
146
+ end
147
+
148
+ # If Launch Action Arguments are present and none are present in the test
149
+ # action, then please add them in.
150
+ if (scheme.launch_action.xml_element.to_s.include? '<CommandLineArguments>') &&
151
+ !(scheme.test_action.xml_element.to_s.include? '<CommandLineArguments>')
152
+ scheme.test_action.xml_element.add_element('CommandLineArguments')
153
+ end
154
+
155
+ # Create a new environment variable and add it to the Environment Variables.
156
+ test_action_env_vars = scheme.test_action.xml_element.elements['EnvironmentVariables']
157
+ test_action_args = scheme.test_action.xml_element.elements['CommandLineArguments']
158
+
159
+ earl_grey_environment_variable = REXML::Element.new 'EnvironmentVariable'
160
+ earl_grey_environment_variable.attributes['key'] = test_action_key
161
+ earl_grey_environment_variable.attributes['value'] = test_action_value
162
+ earl_grey_environment_variable.attributes['isEnabled'] = test_action_isEnabled
163
+ test_action_env_vars.add_element(earl_grey_environment_variable)
164
+
165
+ # If any environment variables or arguments were being used in the test action by
166
+ # being copied from the launch (run) action then copy them over to the test action
167
+ # along with the EarlGrey environment variable.
168
+ if (launch_action_env_args_present)
169
+ launch_action_env_vars = scheme.launch_action.xml_element.elements['EnvironmentVariables']
170
+ launch_action_args = scheme.launch_action.xml_element.elements['CommandLineArguments']
171
+
172
+ # Add in the Environment Variables
173
+ launch_action_env_vars.elements.each('EnvironmentVariable') do |launch_action_env_var|
174
+ environment_variable = REXML::Element.new 'EnvironmentVariable'
175
+ environment_variable.attributes['key'] = launch_action_env_var.attributes['key']
176
+ environment_variable.attributes['value'] = launch_action_env_var.attributes['value']
177
+ environment_variable.attributes['isEnabled'] = launch_action_env_var.attributes['isEnabled']
178
+ test_action_env_vars.add_element(environment_variable)
179
+ end
180
+
181
+ #Add in the Arguments
182
+ launch_action_args.elements.each('CommandLineArgument') do |launch_action_arg|
183
+ argument = REXML::Element.new 'CommandLineArgument'
184
+ argument.attributes['argument'] = launch_action_arg.attributes['argument']
185
+ argument.attributes['isEnabled'] = launch_action_arg.attributes['isEnabled']
186
+ test_action_args.add_element(argument)
187
+ end
188
+
189
+ end
190
+ scheme.test_action = test_action
191
+ scheme
192
+ end
193
+
194
+ # Adds EarlGrey.framework to products group. Returns file ref.
195
+ def add_earlgrey_product
196
+ return @add_earlgrey_product if @add_earlgrey_product
197
+ framework_path = carthage ? '${SRCROOT}/Carthage/Build/iOS/EarlGrey.framework' :
198
+ '${SRCROOT}/Pods/EarlGrey/EarlGrey-1.0.0/EarlGrey.framework'
199
+
200
+ framework_ref = user_project.products_group.files.find { |f| f.path == framework_path }
201
+ return @add_earlgrey_product = framework_ref if framework_ref
202
+
203
+ framework_ref = user_project.products_group.new_file(framework_path)
204
+ framework_ref.source_tree = 'SRCROOT'
205
+
206
+ @add_earlgrey_product = framework_ref
207
+ end
208
+
209
+ # Generates a copy files build phase to embed the EarlGrey framework into
210
+ # the app under test.
211
+ def add_earlgrey_copy_files_script
212
+ earlgrey_copy_files_phase_name = 'EarlGrey Copy Files'
213
+ earlgrey_copy_files_exists = false
214
+ test_target.copy_files_build_phases.each do |copy_files_phase|
215
+ if copy_files_phase.name == earlgrey_copy_files_phase_name
216
+ earlgrey_copy_files_exists = true
217
+ end
218
+ end
219
+
220
+ unless earlgrey_copy_files_exists
221
+ new_copy_files_phase = test_target.new_copy_files_build_phase(earlgrey_copy_files_phase_name)
222
+ new_copy_files_phase.dst_path = '$(TEST_HOST)/../'
223
+ new_copy_files_phase.dst_subfolder_spec = '0'
224
+
225
+ file_ref = add_earlgrey_product
226
+ build_file = new_copy_files_phase.add_file_reference(file_ref, true)
227
+ build_file.settings = {'ATTRIBUTES' => ['CodeSignOnCopy']}
228
+ user_project.save
229
+ end
230
+ end
231
+
232
+ FRAMEWORK_SEARCH_PATHS = 'FRAMEWORK_SEARCH_PATHS'
233
+ HEADER_SEARCH_PATHS = 'HEADER_SEARCH_PATHS'
234
+
235
+ def add_carthage_search_paths
236
+ return unless carthage
237
+ carthage_build_ios = '$(SRCROOT)/Carthage/Build/iOS'
238
+ carthage_headers_ios = '$(SRCROOT)/Carthage/Build/iOS/**'
239
+
240
+ test_target.build_configurations.each do |config|
241
+ settings = config.build_settings
242
+ settings[FRAMEWORK_SEARCH_PATHS] = Array(settings[FRAMEWORK_SEARCH_PATHS])
243
+ unless settings[FRAMEWORK_SEARCH_PATHS].include?(carthage_build_ios)
244
+ settings[FRAMEWORK_SEARCH_PATHS] << carthage_build_ios
245
+ end
246
+
247
+ settings[HEADER_SEARCH_PATHS] = Array(settings[HEADER_SEARCH_PATHS])
248
+ unless settings[HEADER_SEARCH_PATHS].include?(carthage_headers_ios)
249
+ settings[HEADER_SEARCH_PATHS] << carthage_headers_ios
250
+ end
251
+ end
252
+
253
+ user_project.save
254
+ end
255
+
256
+ SWIFT_OBJC_BRIDGING_HEADER = 'SWIFT_OBJC_BRIDGING_HEADER'
257
+
258
+ def copy_swift_files
259
+ return unless swift
260
+ bridge_path = '$(TARGET_NAME)/BridgingHeader.h'
261
+
262
+ test_target.build_configurations.each do |config|
263
+ settings = config.build_settings
264
+ settings[SWIFT_OBJC_BRIDGING_HEADER] = bridge_path
265
+ end
266
+
267
+ user_project.save
268
+
269
+ src_root = File.join(__dir__, 'files')
270
+ dst_root = File.join(Dir.pwd, test_target_name)
271
+ fail "Missing target folder #{dst_root}" unless File.exist? dst_root
272
+
273
+ src_header_name = 'BridgingHeader.h'
274
+ src_header = File.join(src_root, src_header_name)
275
+ fail 'Bundled header missing' unless File.exist? src_header
276
+ dst_header = File.join(dst_root, src_header_name)
277
+
278
+ src_swift_name = 'EarlGrey.swift'
279
+ src_swift = File.join(src_root, src_swift_name)
280
+ fail 'Bundled swift missing' unless File.exist? src_swift
281
+ dst_swift = File.join(dst_root, src_swift_name)
282
+
283
+ FileUtils.copy src_header, dst_header
284
+ FileUtils.copy src_swift, dst_swift
285
+
286
+ test_target_group = user_project.main_group.children.find { |g| g.display_name == test_target_name }
287
+ fail "Test target group not found! #{test_target_group}" unless test_target_group
288
+
289
+ # Add files to testing target group otherwise Xcode can't read them.
290
+ new_files = [src_header_name, src_swift_name]
291
+ existing_files = test_target_group.children.map(&:display_name)
292
+
293
+ new_files.each do |file|
294
+ next if existing_files.include? file
295
+ test_target_group.new_reference(file)
296
+ end
297
+
298
+ # Add EarlGrey.swift to sources build phase
299
+ existing_sources = test_target.source_build_phase.files.map(&:display_name)
300
+ unless existing_sources.include? src_swift_name
301
+ earlgrey_swift_file_ref = test_target_group.files.find { |f| f.display_name == src_swift_name }
302
+ fail 'EarlGrey.swift not found in testing target' unless earlgrey_swift_file_ref
303
+ test_target.source_build_phase.add_file_reference earlgrey_swift_file_ref
304
+ end
305
+
306
+ # Link Binary With Libraries - frameworks_build_phase - Add EarlGrey.framework
307
+ earlgrey_framework = 'EarlGrey.framework'
308
+ existing_frameworks = test_target.frameworks_build_phase.files.map(&:display_name)
309
+ unless existing_frameworks.include? earlgrey_framework
310
+ framework_ref = add_earlgrey_product
311
+ test_target.frameworks_build_phase.add_file_reference framework_ref
312
+ end
313
+
314
+ # Add shell script phase
315
+ shell_script_name = 'Carthage copy-frameworks Run Script'
316
+ unless test_target.shell_script_build_phases.map(&:name).include?(shell_script_name)
317
+ shell_script = test_target.new_shell_script_build_phase shell_script_name
318
+ shell_script.shell_path = '/bin/bash'
319
+ shell_script.shell_script = '/usr/local/bin/carthage copy-frameworks'
320
+ shell_script.input_paths = ['$(SRCROOT)/Carthage/Build/iOS/EarlGrey.framework']
321
+ end
322
+
323
+ user_project.save
324
+ end
325
+
326
+ # Save the scheme changes. This is done here to prevent any irreversible changes in case
327
+ # of an exception being thrown.
328
+ def save_earlgrey_scheme_changes(scheme)
329
+ scheme.save!
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'xcodeproj'
3
+ require 'colored'
4
+ require 'thor'
5
+
6
+ require 'fileutils'
7
+
8
+ require_relative 'version'
9
+ require_relative 'configure_earlgrey_pods'
10
+ require_relative 'cli'
@@ -0,0 +1 @@
1
+ #import <EarlGrey/EarlGrey.h>
@@ -0,0 +1,78 @@
1
+ //
2
+ // Copyright 2016 Google Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ public func EarlGrey() -> EarlGreyImpl {
18
+ return EarlGreyImpl.invokedFromFile(#file, lineNumber: #line)
19
+ }
20
+
21
+ public func GREYAssert(@autoclosure expression: () -> BooleanType, reason: String) {
22
+ GREYAssert(expression, reason, details: "Expected expression to be true")
23
+ }
24
+
25
+ public func GREYAssertTrue(@autoclosure expression: () -> BooleanType, reason: String) {
26
+ GREYAssert(expression().boolValue,
27
+ reason,
28
+ details: "Expected the boolean expression to be true")
29
+ }
30
+
31
+ public func GREYAssertFalse(@autoclosure expression: () -> BooleanType, reason: String) {
32
+ GREYAssert(!expression().boolValue,
33
+ reason,
34
+ details: "Expected the boolean expression to be true")
35
+ }
36
+
37
+ public func GREYAssertNotNil(@autoclosure expression: () -> Any?, reason: String) {
38
+ GREYAssert(expression() != nil, reason, details: "Expected expression to be not nil")
39
+ }
40
+
41
+ public func GREYAssertNil(@autoclosure expression: () -> Any?, reason: String) {
42
+ GREYAssert(expression() == nil, reason, details: "Expected expression to be nil")
43
+ }
44
+
45
+ public func GREYAssertEqual<T : Equatable>(@autoclosure left: () -> T?,
46
+ @autoclosure _ right: () -> T?, reason: String) {
47
+ GREYAssert(left() == right(), reason, details: "Expeted left term to be equal to right term")
48
+ }
49
+
50
+ public func GREYFail(reason: String) {
51
+ greyFailureHandler.handleException(GREYFrameworkException(name: kGREYAssertionFailedException,
52
+ reason: reason),
53
+ details: "")
54
+ }
55
+
56
+ public func GREYFail(reason: String, details: String) {
57
+ greyFailureHandler.handleException(GREYFrameworkException(name: kGREYAssertionFailedException,
58
+ reason: reason),
59
+ details: details)
60
+ }
61
+
62
+ private func GREYAssert(@autoclosure expression: () -> BooleanType,
63
+ _ reason: String, details: String) {
64
+ GREYSetCurrentAsFailable()
65
+ if !expression().boolValue {
66
+ greyFailureHandler.handleException(GREYFrameworkException(name: kGREYAssertionFailedException,
67
+ reason: reason),
68
+ details: details)
69
+ }
70
+ }
71
+
72
+ private func GREYSetCurrentAsFailable() {
73
+ let greyFailureHandlerSelector =
74
+ #selector(GREYFailureHandler.setInvocationFile(_:andInvocationLine:))
75
+ if greyFailureHandler.respondsToSelector(greyFailureHandlerSelector) {
76
+ greyFailureHandler.setInvocationFile!(#file, andInvocationLine: #line)
77
+ }
78
+ }