earlgrey 0.0.1 → 0.0.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
  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
+ }