illuminator 0.1.0
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 +7 -0
- data/gem/README.md +37 -0
- data/gem/bin/illuminatorTestRunner.rb +22 -0
- data/gem/lib/illuminator.rb +171 -0
- data/gem/lib/illuminator/argument-parsing.rb +299 -0
- data/gem/lib/illuminator/automation-builder.rb +39 -0
- data/gem/lib/illuminator/automation-runner.rb +589 -0
- data/gem/lib/illuminator/build-artifacts.rb +118 -0
- data/gem/lib/illuminator/device-installer.rb +45 -0
- data/gem/lib/illuminator/host-utils.rb +42 -0
- data/gem/lib/illuminator/instruments-runner.rb +301 -0
- data/gem/lib/illuminator/javascript-runner.rb +98 -0
- data/gem/lib/illuminator/listeners/console-logger.rb +32 -0
- data/gem/lib/illuminator/listeners/full-output.rb +13 -0
- data/gem/lib/illuminator/listeners/instruments-listener.rb +22 -0
- data/gem/lib/illuminator/listeners/intermittent-failure-detector.rb +49 -0
- data/gem/lib/illuminator/listeners/pretty-output.rb +26 -0
- data/gem/lib/illuminator/listeners/saltinel-agent.rb +66 -0
- data/gem/lib/illuminator/listeners/saltinel-listener.rb +26 -0
- data/gem/lib/illuminator/listeners/start-detector.rb +52 -0
- data/gem/lib/illuminator/listeners/stop-detector.rb +46 -0
- data/gem/lib/illuminator/listeners/test-listener.rb +58 -0
- data/gem/lib/illuminator/listeners/trace-error-detector.rb +38 -0
- data/gem/lib/illuminator/options.rb +96 -0
- data/gem/lib/illuminator/resources/IlluminatorGeneratedEnvironment.erb +13 -0
- data/gem/lib/illuminator/resources/IlluminatorGeneratedRunnerForInstruments.erb +19 -0
- data/gem/lib/illuminator/test-definitions.rb +23 -0
- data/gem/lib/illuminator/test-suite.rb +155 -0
- data/gem/lib/illuminator/version.rb +3 -0
- data/gem/lib/illuminator/xcode-builder.rb +144 -0
- data/gem/lib/illuminator/xcode-utils.rb +219 -0
- data/gem/resources/BuildConfiguration.xcconfig +10 -0
- data/gem/resources/js/AppMap.js +767 -0
- data/gem/resources/js/Automator.js +1132 -0
- data/gem/resources/js/Base64.js +142 -0
- data/gem/resources/js/Bridge.js +102 -0
- data/gem/resources/js/Config.js +92 -0
- data/gem/resources/js/Extensions.js +2025 -0
- data/gem/resources/js/Illuminator.js +228 -0
- data/gem/resources/js/Preferences.js +24 -0
- data/gem/resources/scripts/UIAutomationBridge.rb +248 -0
- data/gem/resources/scripts/common.applescript +25 -0
- data/gem/resources/scripts/diff_png.sh +61 -0
- data/gem/resources/scripts/kill_all_sim_processes.sh +17 -0
- data/gem/resources/scripts/plist_to_json.sh +40 -0
- data/gem/resources/scripts/set_hardware_keyboard.applescript +0 -0
- metadata +225 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c94f4888bca611f421fcaf152f94e1e5418bed78
|
4
|
+
data.tar.gz: f967a48a1432cf3419c7e7d62e269a0769159d33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6ebf64b498f0f7fee2b399c824a7d307bcb4c1bf58536685bdd1232cbb98c7a425753a5b42ffa4d58729a69b3f242da2e22f40a3961185f798ea0e757701a119
|
7
|
+
data.tar.gz: 1b00dd71f903e20cc000dad3f78effe97879544bf61596b7a0925d9b49e0ca7522de20f882b5926361d545c32c2463dc756f0bf0f5c289198fd82a9fc13d4934
|
data/gem/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Illuminator gem
|
2
|
+
|
3
|
+
This gem contains ruby modules necessary to run tests using the [Illuminator framework](http://github.com/paypal/Illuminator).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'illuminator'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install illuminator
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
See the [main Illuminator documentation](https://github.com/paypal/Illuminator).
|
24
|
+
|
25
|
+
## Development
|
26
|
+
|
27
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
28
|
+
|
29
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it ( https://github.com/paypal/illuminator/fork )
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create a new Pull Request
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'illuminator'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
parser_factory = Illuminator::ParserFactory.new
|
8
|
+
|
9
|
+
parser_factory.prepare({}, # no defaults are being set
|
10
|
+
{}, # no extra parse flags are being defined
|
11
|
+
{}) # no argument processing overrides are being provided
|
12
|
+
|
13
|
+
# Each command line option has a single-character code, so we lay out the order of the options (# for separator) here
|
14
|
+
#parser = parser_factory.build_parser(options, 'APDasdq#xtoni#rvmw#bzl#Bfek#')
|
15
|
+
parser = parser_factory.build_parser(options, 'AyfEBxrc#aDPWqs#dbzlek#vmp#xtoniw#')
|
16
|
+
|
17
|
+
# read the options into an Illuminator::Options structure
|
18
|
+
option_struct = parser.parse ARGV
|
19
|
+
|
20
|
+
# use the defined options
|
21
|
+
success = Illuminator::run_with_options option_struct
|
22
|
+
exit 1 unless success
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require "illuminator/version"
|
2
|
+
|
3
|
+
require "illuminator/automation-builder"
|
4
|
+
require "illuminator/automation-runner"
|
5
|
+
require "illuminator/argument-parsing"
|
6
|
+
require "illuminator/device-installer"
|
7
|
+
require "illuminator/build-artifacts"
|
8
|
+
require "illuminator/host-utils"
|
9
|
+
require "illuminator/xcode-utils"
|
10
|
+
require "illuminator/options"
|
11
|
+
|
12
|
+
|
13
|
+
module Illuminator
|
14
|
+
|
15
|
+
class Framework
|
16
|
+
|
17
|
+
def self.will_clean options
|
18
|
+
return true if options.illuminator.clean.derived
|
19
|
+
return true if options.illuminator.clean.artifacts
|
20
|
+
return true if options.illuminator.clean.xcode
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.clean_countdown
|
25
|
+
countdown = "3....2....1...."
|
26
|
+
print "Cleaning in ".yellow
|
27
|
+
countdown.split("").each do |c|
|
28
|
+
print c.yellow
|
29
|
+
sleep(0.2)
|
30
|
+
end
|
31
|
+
print "\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.validate_options(options)
|
35
|
+
noproblems = true
|
36
|
+
|
37
|
+
# so we can call BS on the user
|
38
|
+
bs = lambda do |message|
|
39
|
+
puts message.red
|
40
|
+
noproblems = false
|
41
|
+
end
|
42
|
+
|
43
|
+
# some things to check
|
44
|
+
things = {
|
45
|
+
"Build artifacts directory" => options.build_artifacts_dir,
|
46
|
+
}
|
47
|
+
|
48
|
+
# now check them
|
49
|
+
things.each { |k, v| bs.call "#{k} was not specified" if v.nil? }
|
50
|
+
|
51
|
+
# fail quickly if simulator device and/or version are wrong
|
52
|
+
if options.illuminator.hardware_id.nil?
|
53
|
+
device = options.simulator.device
|
54
|
+
version = options.simulator.version
|
55
|
+
devices = XcodeUtils.instance.get_simulator_device_types()
|
56
|
+
versions = XcodeUtils.instance.get_simulator_runtimes()
|
57
|
+
|
58
|
+
|
59
|
+
unless devices.include? device
|
60
|
+
bs.call "Specified simulator device '#{device}' does not appear to be installed - options are #{devices}"
|
61
|
+
end
|
62
|
+
|
63
|
+
unless versions.include? version
|
64
|
+
bs.call "Specified simulator iOS version '#{version}' does not appear to be installed - options are #{versions}"
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
# check paths
|
70
|
+
if options.illuminator.task.automate
|
71
|
+
bs.call "Implementation was not specified" if options.javascript.implementation.nil?
|
72
|
+
|
73
|
+
if options.javascript.test_path.nil?
|
74
|
+
bs.call "Javascript test definitions file was not specified"
|
75
|
+
else
|
76
|
+
unless File.exists? options.javascript.test_path
|
77
|
+
bs.call "Could not find specified javascript test definitions file at '#{options.javascript.test_path}'"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
return noproblems
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
def self.run_with_options(originalOptions)
|
90
|
+
|
91
|
+
options = Options.new(originalOptions.to_h) # immediately create a copy of the options, because we may mangle them
|
92
|
+
|
93
|
+
# validate some inputs
|
94
|
+
return false unless Framework.validate_options(options)
|
95
|
+
|
96
|
+
Illuminator::BuildArtifacts.instance.set_root options.build_artifacts_dir
|
97
|
+
|
98
|
+
hardware_id = options.illuminator.hardware_id
|
99
|
+
app_name = options.xcode.app_name
|
100
|
+
|
101
|
+
# do any initial cleaning
|
102
|
+
clean_dirs = {
|
103
|
+
HostUtils.realpath("~/Library/Developer/Xcode/DerivedData") => options.illuminator.clean.derived,
|
104
|
+
Illuminator::BuildArtifacts.instance.root(true) => options.illuminator.clean.artifacts,
|
105
|
+
}
|
106
|
+
Framework.clean_countdown if Framework.will_clean(options) and (not options.illuminator.clean.no_delay)
|
107
|
+
clean_dirs.each do |d, do_clean|
|
108
|
+
dir = HostUtils.realpath d
|
109
|
+
if do_clean
|
110
|
+
puts "Illuminator cleanup: removing #{dir}"
|
111
|
+
FileUtils.rmtree dir
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Initialize builder and build
|
116
|
+
if (not options.instruments.app_location.nil?)
|
117
|
+
puts "Skipping build because app_location was provided".yellow if options.illuminator.task.build
|
118
|
+
options.instruments.app_location = HostUtils::realpath(options.instruments.app_location)
|
119
|
+
elsif (not options.illuminator.task.build)
|
120
|
+
options.instruments.app_location = Illuminator::BuildArtifacts.instance.app_location(app_name) # assume app is here
|
121
|
+
else
|
122
|
+
builder = AutomationBuilder.new
|
123
|
+
builder.project_dir = options.xcode.project_dir
|
124
|
+
builder.project = options.xcode.project
|
125
|
+
builder.scheme = options.xcode.scheme
|
126
|
+
builder.workspace = options.xcode.workspace
|
127
|
+
builder.do_clean = options.illuminator.clean.xcode
|
128
|
+
unless options.xcode.environment_vars.nil?
|
129
|
+
options.xcode.environment_vars.each { |name, value| builder.add_environment_variable(name, value) }
|
130
|
+
end
|
131
|
+
|
132
|
+
# if app name is not specified, make sure that we will only have one to run
|
133
|
+
XcodeUtils.remove_existing_apps(Illuminator::BuildArtifacts.instance.xcode) if app_name.nil?
|
134
|
+
if builder.build_for_automation(options.xcode.sdk, hardware_id)
|
135
|
+
puts 'Build succeded'.green
|
136
|
+
options.instruments.app_location = Illuminator::BuildArtifacts.instance.app_location(app_name)
|
137
|
+
else
|
138
|
+
puts 'Build failed, check logs for results'.red
|
139
|
+
exit builder.exit_code
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
return true unless options.illuminator.task.automate
|
144
|
+
|
145
|
+
# Install on real device
|
146
|
+
unless hardware_id.nil?
|
147
|
+
DeviceInstaller.instance.install_on_device(options.instruments.app_location, hardware_id)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Initialize automation
|
151
|
+
runner = AutomationRunner.new
|
152
|
+
runner.app_name = app_name
|
153
|
+
runner.cleanup
|
154
|
+
return runner.run_with_options(options)
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
# override_options is a lambda function that acts on the options object
|
159
|
+
def self.rerun(config_path, override_options = nil)
|
160
|
+
|
161
|
+
# load config from supplied path
|
162
|
+
json_config = IO.read(config_path)
|
163
|
+
|
164
|
+
# process any overrides
|
165
|
+
options = override_options.(Illuminator::Options.new(JSON.parse(json_config))) unless override_options.nil?
|
166
|
+
|
167
|
+
return run_with_options options
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require_relative './options'
|
5
|
+
require_relative './host-utils'
|
6
|
+
|
7
|
+
module Illuminator
|
8
|
+
|
9
|
+
class Parser < OptionParser
|
10
|
+
attr_reader :positional_args
|
11
|
+
|
12
|
+
def initialize options
|
13
|
+
super
|
14
|
+
@_options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_retest_args
|
18
|
+
known_retests = ["solo"]
|
19
|
+
|
20
|
+
@_options["retest"] = [] if @_options["retest"].nil?
|
21
|
+
|
22
|
+
@_options["retest"].each do |r|
|
23
|
+
if known_retests.include? r
|
24
|
+
# ok
|
25
|
+
elsif /^\d+x$/.match(r)
|
26
|
+
# ok (1x, 2x, 3x...)
|
27
|
+
else
|
28
|
+
puts "Got unknown --retest specifier '#{r}'".yellow
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_max_retests
|
34
|
+
ret = 0
|
35
|
+
@_options["retest"].each do |r|
|
36
|
+
matches = /^(\d+)x$/.match(r)
|
37
|
+
unless matches.nil?
|
38
|
+
ret = [ret, matches[1].to_i].max
|
39
|
+
end
|
40
|
+
end
|
41
|
+
ret
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_clean_args
|
45
|
+
known_cleans = ["xcode", "buildArtifacts", "derivedData", "noDelay"]
|
46
|
+
|
47
|
+
@_options["clean"] = [] if @_options["clean"].nil?
|
48
|
+
|
49
|
+
@_options["clean"].each do |c|
|
50
|
+
unless known_cleans.include? c
|
51
|
+
puts "Got unknown --clean specifier '#{c}'".yellow
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# copy internal options storage into a options object
|
57
|
+
def copy_parsed_options_into(illuminatorOptions)
|
58
|
+
check_clean_args
|
59
|
+
check_retest_args
|
60
|
+
|
61
|
+
# load up known illuminatorOptions
|
62
|
+
# we only load non-nil options, just in case there was already something in the illuminatorOptions obj
|
63
|
+
illuminatorOptions.build_artifacts_dir = @_options["buildArtifacts"] unless @_options["buildArtifacts"].nil?
|
64
|
+
|
65
|
+
illuminatorOptions.xcode.app_name = @_options["app_name"] unless @_options["app_name"].nil?
|
66
|
+
illuminatorOptions.xcode.sdk = @_options["sdk"] unless @_options["sdk"].nil?
|
67
|
+
illuminatorOptions.xcode.scheme = @_options["scheme"] unless @_options["scheme"].nil?
|
68
|
+
illuminatorOptions.xcode.workspace = @_options["xcodeWorkspace"] unless @_options["xcodeWorkspace"].nil?
|
69
|
+
|
70
|
+
illuminatorOptions.illuminator.entry_point = @_options["entry_point"] unless @_options["entry_point"].nil?
|
71
|
+
illuminatorOptions.illuminator.test.random_seed = @_options["random_seed"].to_i unless @_options["random_seed"].nil?
|
72
|
+
illuminatorOptions.illuminator.test.tags.any = @_options["tags_any"] unless @_options["tags_any"].nil?
|
73
|
+
illuminatorOptions.illuminator.test.tags.all = @_options["tags_all"] unless @_options["tags_all"].nil?
|
74
|
+
illuminatorOptions.illuminator.test.tags.none = @_options["tags_none"] unless @_options["tags_none"].nil?
|
75
|
+
|
76
|
+
illuminatorOptions.illuminator.test.retest.attempts = get_max_retests
|
77
|
+
illuminatorOptions.illuminator.test.retest.solo = @_options["retest"].include? "solo"
|
78
|
+
|
79
|
+
illuminatorOptions.illuminator.clean.xcode = @_options["clean"].include? "xcode"
|
80
|
+
illuminatorOptions.illuminator.clean.derived = @_options["clean"].include? "derivedData"
|
81
|
+
illuminatorOptions.illuminator.clean.artifacts = @_options["clean"].include? "buildArtifacts"
|
82
|
+
illuminatorOptions.illuminator.clean.noDelay = @_options["clean"].include? "noDelay"
|
83
|
+
|
84
|
+
illuminatorOptions.illuminator.task.build = (not @_options["skipBuild"]) unless @_options["skipBuild"].nil?
|
85
|
+
illuminatorOptions.illuminator.task.automate = (not @_options["skipAutomate"]) unless @_options["skipAutomate"].nil?
|
86
|
+
illuminatorOptions.illuminator.task.set_sim = (not @_options["skipSetSim"]) unless @_options["skipSetSim"].nil?
|
87
|
+
illuminatorOptions.illuminator.task.coverage = @_options["coverage"] unless @_options["coverage"].nil?
|
88
|
+
illuminatorOptions.illuminator.hardware_id = @_options["hardware_id"] unless @_options["hardware_id"].nil?
|
89
|
+
|
90
|
+
illuminatorOptions.simulator.device = @_options["sim_device"] unless @_options["sim_device"].nil?
|
91
|
+
illuminatorOptions.simulator.version = @_options["sim_version"] unless @_options["sim_version"].nil?
|
92
|
+
illuminatorOptions.simulator.language = @_options["sim_language"] unless @_options["sim_language"].nil?
|
93
|
+
illuminatorOptions.simulator.kill_after = (not @_options["skipKillAfter"]) unless @_options["skipKillAfter"].nil?
|
94
|
+
|
95
|
+
illuminatorOptions.instruments.app_location = @_options["app_location"] unless @_options["app_location"].nil?
|
96
|
+
illuminatorOptions.instruments.do_verbose = @_options["verbose"] unless @_options["verbose"].nil?
|
97
|
+
illuminatorOptions.instruments.timeout = @_options["timeout"].to_i unless @_options["timeout"].nil?
|
98
|
+
|
99
|
+
illuminatorOptions.javascript.test_path = @_options["test_path"] unless @_options["test_path"].nil?
|
100
|
+
illuminatorOptions.javascript.implementation = @_options["implementation"] unless @_options["implementation"].nil?
|
101
|
+
|
102
|
+
known_keys = Illuminator::ParserFactory.new.letter_map.values # get option keynames from a plain vanilla factory
|
103
|
+
|
104
|
+
# load up unknown illuminatorOptions
|
105
|
+
illuminatorOptions.app_specific = @_options.select { |keyname, _| not (known_keys.include? keyname) }
|
106
|
+
|
107
|
+
return illuminatorOptions
|
108
|
+
end
|
109
|
+
|
110
|
+
def parse args
|
111
|
+
@positional_args = super(args)
|
112
|
+
return copy_parsed_options_into(Illuminator::Options.new)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
class ParserFactory
|
120
|
+
|
121
|
+
attr_reader :letter_map
|
122
|
+
|
123
|
+
# the currency of this parser factory is the "short" single-letter argument switch
|
124
|
+
def initialize()
|
125
|
+
@options = nil
|
126
|
+
@switches = {}
|
127
|
+
|
128
|
+
# build the list of how each parameter will be saved in the output
|
129
|
+
@letter_map = {
|
130
|
+
'A' => 'buildArtifacts',
|
131
|
+
'x' => 'entry_point',
|
132
|
+
'p' => 'test_path',
|
133
|
+
'a' => 'app_name',
|
134
|
+
'D' => 'xcodeProjectDir',
|
135
|
+
'P' => 'xcodeProject',
|
136
|
+
'W' => 'xcodeWorkspace',
|
137
|
+
't' => 'tags_any',
|
138
|
+
'o' => 'tags_all',
|
139
|
+
'n' => 'tags_none',
|
140
|
+
'q' => 'sdk',
|
141
|
+
's' => 'scheme',
|
142
|
+
'd' => 'hardware_id',
|
143
|
+
'i' => 'implementation',
|
144
|
+
'E' => 'app_location',
|
145
|
+
'b' => 'sim_device',
|
146
|
+
'z' => 'sim_version',
|
147
|
+
'l' => 'sim_language',
|
148
|
+
'f' => 'skipBuild',
|
149
|
+
'B' => 'skipAutomate',
|
150
|
+
'e' => 'skipSetSim',
|
151
|
+
'k' => 'skipKillAfter',
|
152
|
+
'c' => 'coverage',
|
153
|
+
'r' => 'retest',
|
154
|
+
'v' => 'verbose',
|
155
|
+
'm' => 'timeout',
|
156
|
+
'w' => 'random_seed',
|
157
|
+
'y' => 'clean',
|
158
|
+
}
|
159
|
+
|
160
|
+
@letter_processing = {
|
161
|
+
'p' => lambda {|p| Illuminator::HostUtils.realpath(p) }, # get real path to tests file
|
162
|
+
'E' => lambda {|p| Illuminator::HostUtils.realpath(p) }, # get real path to app
|
163
|
+
'y' => lambda {|p| p.split(',')}, # split comma-separated string into array
|
164
|
+
'r' => lambda {|p| p.split(',')}, # split comma-separated string into array
|
165
|
+
't' => lambda {|p| p.split(',')}, # split comma-separated string into array
|
166
|
+
'o' => lambda {|p| p.split(',')}, # split comma-separated string into array
|
167
|
+
'n' => lambda {|p| p.split(',')}, # split comma-separated string into array
|
168
|
+
}
|
169
|
+
|
170
|
+
@default_values = {
|
171
|
+
# 'D' => Dir.pwd, # Since this effectively happens in xcode-builder, DON'T do it here too
|
172
|
+
'A' => File.join(Dir.pwd, "buildArtifacts"),
|
173
|
+
'b' => 'iPhone 5',
|
174
|
+
'z' => '8.2',
|
175
|
+
'q' => 'iphonesimulator',
|
176
|
+
'l' => 'en',
|
177
|
+
'x' => 'runTestsByTag',
|
178
|
+
'm' => 30,
|
179
|
+
'f' => false,
|
180
|
+
'B' => false,
|
181
|
+
'e' => false,
|
182
|
+
'k' => false,
|
183
|
+
'c' => false,
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
# you must custom prepare before you can add custom switches... otherwise things get all stupid
|
188
|
+
def prepare(default_values = nil, letter_map_updates = nil, letter_processing_updates = nil)
|
189
|
+
@letter_map = @letter_map.merge(letter_map_updates) unless letter_map_updates.nil?
|
190
|
+
@letter_processing = @letter_processing.merge(letter_processing_updates) unless letter_processing_updates.nil?
|
191
|
+
@default_values = @default_values.merge default_values unless default_values.nil?
|
192
|
+
|
193
|
+
add_switch('A', ['-A', '--buildArtifacts PATH', 'The directory in which to store build artifacts'])
|
194
|
+
add_switch('x', ['-x', '--entryPoint LABEL', 'The execution entry point {runTestsByTag, runTestsByName, describe}'])
|
195
|
+
add_switch('p', ['-p', '--test_path PATH', 'Path to js file with all tests imported'])
|
196
|
+
add_switch('a', ['-a', '--app_name APPNAME', "Name of the app to build / run"])
|
197
|
+
add_switch('D', ['-D', '--xcodeProjectDirectory PATH', "Directory containing the Xcode project to build"])
|
198
|
+
add_switch('P', ['-P', '--xcodeProject PROJECTNAME', "Project to build -- required if there are 2 in the same directory"])
|
199
|
+
add_switch('W', ['-W', '--xcodeWorkspace WORKSPACENAME', "Workspace to build"])
|
200
|
+
add_switch('t', ['-t', '--tags-any TAGSANY', 'Run tests with any of the given tags'])
|
201
|
+
add_switch('o', ['-o', '--tags-all TAGSALL', 'Run tests with all of the given tags'])
|
202
|
+
add_switch('n', ['-n', '--tags-none TAGSNONE', 'Run tests with none of the given tags'])
|
203
|
+
add_switch('q', ['-q', '--sdk SDK', 'SDK to build against'])
|
204
|
+
add_switch('s', ['-s', '--scheme SCHEME', 'Build and run specific tests on given workspace scheme'])
|
205
|
+
add_switch('d', ['-d', '--hardware_id ID', 'hardware id of device to run on instead of simulator'])
|
206
|
+
add_switch('i', ['-i', '--implementation IMPL', 'Device tests implementation'])
|
207
|
+
add_switch('E', ['-E', '--app_location LOCATION', 'Location of app executable, if pre-built'])
|
208
|
+
add_switch('b', ['-b', '--simDevice DEVICE', 'Run on given simulated device'])
|
209
|
+
add_switch('z', ['-z', '--simVersion VERSION', 'Run on given simulated iOS version'])
|
210
|
+
add_switch('l', ['-l', '--simLanguage LANGUAGE', 'Run on given simulated iOS language'])
|
211
|
+
add_switch('f', ['-f', '--skip-build', 'Just automate; assume already built'])
|
212
|
+
add_switch('B', ['-B', '--skip-automate', "Don't automate; build only"])
|
213
|
+
add_switch('e', ['-e', '--skip-set-sim', 'Assume that simulator has already been chosen and properly reset'])
|
214
|
+
add_switch('k', ['-k', '--skip-kill-after', 'Leave the simulator open after the run'])
|
215
|
+
add_switch('y', ['-y', '--clean PLACES', 'Comma-separated list of places to clean {xcode, buildArtifacts, derivedData}'])
|
216
|
+
add_switch('c', ['-c', '--coverage', 'Generate coverage files'])
|
217
|
+
add_switch('r', ['-r', '--retest OPTIONS', 'Immediately retest failed tests with comma-separated options {1x, solo}'])
|
218
|
+
add_switch('v', ['-v', '--verbose', 'Show verbose output from instruments'])
|
219
|
+
add_switch('m', ['-m', '--timeout TIMEOUT', 'Seconds to wait for instruments tool to start tests'])
|
220
|
+
add_switch('w', ['-w', '--random-seed SEED', 'Randomize test order based on given integer seed'])
|
221
|
+
end
|
222
|
+
|
223
|
+
# add a parse switch for the given letter key, using the given options.
|
224
|
+
# the parse action is defined by the existence of letter_processing for the letter key,
|
225
|
+
# which by default is simple assignment
|
226
|
+
def add_switch(letter, opts)
|
227
|
+
dest = get_letter_destination(letter)
|
228
|
+
|
229
|
+
# alter opts to include the default values
|
230
|
+
altered = false
|
231
|
+
if @default_values[letter].nil?
|
232
|
+
opts_with_default = opts
|
233
|
+
else
|
234
|
+
opts_with_default = opts.map do |item|
|
235
|
+
if (!altered and item.chars.first != '-')
|
236
|
+
item += " :: Defaults to \"#{@default_values[letter]}\""
|
237
|
+
altered = true
|
238
|
+
end
|
239
|
+
item
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
@switches[letter] = OpenStruct.new(:opts => opts_with_default,
|
244
|
+
:block => lambda do |newval|
|
245
|
+
# assign the parsed value to the output, processing it if necessary
|
246
|
+
if @letter_processing[letter]
|
247
|
+
@options[dest] = @letter_processing[letter].call(newval)
|
248
|
+
else
|
249
|
+
@options[dest] = newval
|
250
|
+
end
|
251
|
+
end)
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
# letter destination defaults to the letter itself, but can be overwritten by letter_map
|
256
|
+
def get_letter_destination(letter)
|
257
|
+
return @letter_map[letter]? @letter_map[letter] : letter
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# factory function
|
262
|
+
def build_parser(options, letters = nil)
|
263
|
+
@options = options
|
264
|
+
|
265
|
+
if letters.nil?
|
266
|
+
letters = switches.keys.join('')
|
267
|
+
end
|
268
|
+
|
269
|
+
# helpful error message for bad chars
|
270
|
+
bad_chars = letters.chars.to_a.select{|c| c != "#" and @switches[c].nil?}
|
271
|
+
unless bad_chars.empty?
|
272
|
+
raise ArgumentError, "build_parser got letters (#{letters}) containing unknown option characters: #{bad_chars.to_s}"
|
273
|
+
end
|
274
|
+
|
275
|
+
retval = Illuminator::Parser.new options
|
276
|
+
|
277
|
+
# build a parser as specified by the user
|
278
|
+
letters.each_char do |c|
|
279
|
+
options[get_letter_destination(c)] = @default_values[c] unless @default_values[c].nil?
|
280
|
+
|
281
|
+
if c == '#'
|
282
|
+
retval.separator(' ---------------------------------------------------------------------------------')
|
283
|
+
else
|
284
|
+
retval.on(*(@switches[c].send(:opts))) {|foo| @switches[c].send(:block).call(foo)}
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# help message is hard coded!
|
289
|
+
retval.on_tail('-h', '--help', 'Show this help message') {|foo| puts retval.help(); exit }
|
290
|
+
|
291
|
+
retval.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options]"
|
292
|
+
|
293
|
+
#puts retval
|
294
|
+
return retval
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|