illuminator 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|