run_loop 0.0.1
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.
- data/.gitignore +22 -0
- data/.gitmodules +3 -0
- data/.irbrc +17 -0
- data/CHANGES.txt +1 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +16 -0
- data/Rakefile +2 -0
- data/bin/run-loop +9 -0
- data/docs/intro.md +17 -0
- data/irb.sh +2 -0
- data/lib/run_loop.rb +2 -0
- data/lib/run_loop/cli.rb +21 -0
- data/lib/run_loop/core.rb +160 -0
- data/lib/run_loop/version.rb +3 -0
- data/run_loop.gemspec +20 -0
- data/scripts/run_dismiss_location.js +97 -0
- data/scripts/run_screenshooter.sh +172 -0
- data/scripts/udidetect +0 -0
- data/scripts/unix_instruments +92 -0
- metadata +83 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
coverage
|
6
|
+
out
|
7
|
+
.irb-history
|
8
|
+
InstalledFiles
|
9
|
+
lib/bundler/man
|
10
|
+
pkg
|
11
|
+
rdoc
|
12
|
+
spec/reports
|
13
|
+
test/tmp
|
14
|
+
test/version_tmp
|
15
|
+
tmp
|
16
|
+
Gemfile.lock
|
17
|
+
.idea
|
18
|
+
|
19
|
+
# YARD artifacts
|
20
|
+
.yardoc
|
21
|
+
_yardoc
|
22
|
+
doc/
|
data/.gitmodules
ADDED
data/.irbrc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'irb/completion'
|
3
|
+
require 'irb/ext/save-history'
|
4
|
+
|
5
|
+
ARGV.concat [ "--readline",
|
6
|
+
"--prompt-mode",
|
7
|
+
"simple" ]
|
8
|
+
|
9
|
+
# 25 entries in the list
|
10
|
+
IRB.conf[:SAVE_HISTORY] = 50
|
11
|
+
|
12
|
+
# Store results in home directory with specified file name
|
13
|
+
IRB.conf[:HISTORY_FILE] = ".irb-history"
|
14
|
+
|
15
|
+
require 'run_loop'
|
16
|
+
|
17
|
+
|
data/CHANGES.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0: Initial release
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
run-loop
|
2
|
+
|
3
|
+
Copyright (c) Karl Krukow (http://www.lesspainful.com). All rights reserved.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
run-loop
|
2
|
+
===================
|
3
|
+
|
4
|
+
Credits
|
5
|
+
=======
|
6
|
+
|
7
|
+
UI Screen Shooter @jonathanpenn for the wrapper around instruments
|
8
|
+
https://github.com/jonathanpenn/ui-screen-shooter
|
9
|
+
|
10
|
+
UI Screen Shooter is licensed under the MIT license.
|
11
|
+
See the LICENSE file for more info.
|
12
|
+
|
13
|
+
|
14
|
+
License
|
15
|
+
=======
|
16
|
+
run-loop is available under the MIT license. See the LICENSE file for more info.
|
data/Rakefile
ADDED
data/bin/run-loop
ADDED
data/docs/intro.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
What?
|
2
|
+
=====
|
3
|
+
Library for launching iOS apps and controlling various aspects of iOS simulator.
|
4
|
+
|
5
|
+
Use instruments tool for launching and expose certain UI Automation functionality via a "run loop" UIA script.
|
6
|
+
|
7
|
+
Must work as both a command line tool and a ruby library.
|
8
|
+
|
9
|
+
|
10
|
+
Usage
|
11
|
+
=====
|
12
|
+
|
13
|
+
* Run an app using a predefined or custom UIA script
|
14
|
+
|
15
|
+
* Set simulator hardware, os, language, locale
|
16
|
+
|
17
|
+
* Reset simulator
|
data/irb.sh
ADDED
data/lib/run_loop.rb
ADDED
data/lib/run_loop/cli.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module RunLoop
|
5
|
+
class CLI < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.join( File.dirname(__FILE__), '..','..','scripts' )
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
desc "example", "example desc"
|
14
|
+
long_desc "Long desc"
|
15
|
+
def example
|
16
|
+
say "example: #{CLI.source_root}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
module RunLoop
|
6
|
+
|
7
|
+
class TimeoutError < RuntimeError
|
8
|
+
end
|
9
|
+
|
10
|
+
module Core
|
11
|
+
|
12
|
+
SCRIPTS_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'scripts'))
|
13
|
+
SCRIPTS = {
|
14
|
+
:dismiss => "run_dismiss_location.js"
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.scripts_path
|
18
|
+
SCRIPTS_PATH
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.script_for_key(key)
|
22
|
+
if SCRIPTS[key].nil?
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
File.join(scripts_path, SCRIPTS[key])
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run_with_options(options)
|
29
|
+
template = automation_template
|
30
|
+
instruments_path = "instruments"#File.join(scripts_path,"unix_instruments")
|
31
|
+
results_dir = options[:results_dir] || Dir.mktmpdir("run_loop")
|
32
|
+
results_dir_trace = File.join(results_dir,"trace")
|
33
|
+
FileUtils.mkdir_p(results_dir_trace)
|
34
|
+
|
35
|
+
bundle_dir_or_bundle_id = options[:app] || ENV['APP_BUNDLE_PATH']
|
36
|
+
|
37
|
+
unless bundle_dir_or_bundle_id
|
38
|
+
raise "key :app or environment variable APP_BUNDLE_PATH must be specified as path to app bundle (simulator) or bundle id (device)"
|
39
|
+
end
|
40
|
+
|
41
|
+
if File.exist?(bundle_dir_or_bundle_id)
|
42
|
+
#Assume simulator
|
43
|
+
udid = nil
|
44
|
+
else
|
45
|
+
udid = options[:udid]
|
46
|
+
unless udid
|
47
|
+
begin
|
48
|
+
Timeout::timeout(3,TimeoutError) do
|
49
|
+
udid = `#{File.join(scripts_path,'udidetect')}`.chomp
|
50
|
+
end
|
51
|
+
rescue TimeoutError => e
|
52
|
+
|
53
|
+
end
|
54
|
+
unless udid
|
55
|
+
raise "Unable to find connected device."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
if udid
|
63
|
+
instruments_path = "#{instruments_path} -w #{udid}"
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
cmd = [
|
69
|
+
instruments_path,
|
70
|
+
"-D", results_dir_trace,
|
71
|
+
"-t", template,
|
72
|
+
"\"#{bundle_dir_or_bundle_id}\"",
|
73
|
+
"-e", "UIARESULTSPATH", results_dir,
|
74
|
+
"-e", "UIASCRIPT", options[:script],
|
75
|
+
*(options[:instruments_args] || [])
|
76
|
+
]
|
77
|
+
|
78
|
+
pid = fork do
|
79
|
+
log_header("Starting App: #{bundle_dir_or_bundle_id}")
|
80
|
+
cmd_str = cmd.join(" ")
|
81
|
+
if ENV['DEBUG']
|
82
|
+
log(cmd_str)
|
83
|
+
end
|
84
|
+
exec(cmd_str)
|
85
|
+
end
|
86
|
+
|
87
|
+
Process.detach(pid)
|
88
|
+
|
89
|
+
File.open(File.join(results_dir,"run_loop.pid"), "w") do |f|
|
90
|
+
f.write pid
|
91
|
+
end
|
92
|
+
|
93
|
+
return {:pid => pid, :results_dir => results_dir}
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.automation_template
|
97
|
+
xcode_path = `xcode-select -print-path`.chomp
|
98
|
+
automation_bundle = File.expand_path(File.join(xcode_path, "..", "Applications", "Instruments.app", "Contents", "PlugIns", "AutomationInstrument.bundle"))
|
99
|
+
if not File.exist? automation_bundle
|
100
|
+
automation_bundle= File.expand_path(File.join(xcode_path, "Platforms", "iPhoneOS.platform", "Developer", "Library", "Instruments", "PlugIns", "AutomationInstrument.bundle"))
|
101
|
+
raise "Unable to find AutomationInstrument.bundle" if not File.exist? automation_bundle
|
102
|
+
end
|
103
|
+
File.join(automation_bundle, "Contents", "Resources", "Automation.tracetemplate")
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.log(message)
|
107
|
+
puts "#{Time.now } #{message}"
|
108
|
+
$stdout.flush
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.log_header(message)
|
112
|
+
puts "\n\e[#{35}m### #{message} ###\e[0m"
|
113
|
+
$stdout.flush
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.run(options={})
|
119
|
+
script = validate_script(options)
|
120
|
+
options[:script] = script
|
121
|
+
|
122
|
+
Core.run_with_options(options)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.stop(options)
|
126
|
+
results_dir = options[:results_dir]
|
127
|
+
pid = options[:pid] || IO.read(File.join(results_dir,"run_loop.pid"))
|
128
|
+
dest = options[:out] || Dir.pwd
|
129
|
+
|
130
|
+
if pid
|
131
|
+
Process.kill("HUP",pid.to_i)
|
132
|
+
end
|
133
|
+
|
134
|
+
FileUtils.mkdir_p(dest)
|
135
|
+
pngs = Dir.glob(File.join(results_dir,"Run 1","*.png"))
|
136
|
+
FileUtils.cp(pngs, dest) if pngs and pngs.length > 0
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.validate_script(options)
|
140
|
+
script = options[:script]
|
141
|
+
if script
|
142
|
+
if script.is_a?(Symbol)
|
143
|
+
script = Core.script_for_key(script)
|
144
|
+
unless script
|
145
|
+
raise "Unknown script for symbol: #{options[:script]}. Options: #{Core::SCRIPTS.keys.join(', ')}"
|
146
|
+
end
|
147
|
+
elsif script.is_a?(String)
|
148
|
+
unless File.exist?(script)
|
149
|
+
raise "File does not exist: #{script}"
|
150
|
+
end
|
151
|
+
else
|
152
|
+
raise "Unknown type for :script key: #{options[:script].class}"
|
153
|
+
end
|
154
|
+
else
|
155
|
+
script = Core.script_for_key(:dismiss)
|
156
|
+
end
|
157
|
+
script
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
data/run_loop.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "run_loop/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "run_loop"
|
7
|
+
s.version = RunLoop::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Karl Krukow"]
|
10
|
+
s.email = ["karl@lesspainful.com"]
|
11
|
+
s.homepage = "http://calaba.sh"
|
12
|
+
s.summary = %q{Tools related to running Calabash iOS tests}
|
13
|
+
s.description = %q{calabash-cucumber drives tests for native iOS apps. RunLoop provides a number of tools associated with running Calabash tests.}
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = "run-loop"
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_dependency( "thor" )
|
20
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
var target = UIATarget.localTarget(),
|
2
|
+
screenshot_count = 0;
|
3
|
+
|
4
|
+
function findAlertViewText(alert) {
|
5
|
+
if (!alert) {
|
6
|
+
return false;
|
7
|
+
}
|
8
|
+
var txt = alert.name(),
|
9
|
+
txts;
|
10
|
+
if (txt == null) {
|
11
|
+
txts = alert.staticTexts();
|
12
|
+
if (txts != null && txts.length > 0) {
|
13
|
+
|
14
|
+
txt = txts[0].name();
|
15
|
+
}
|
16
|
+
|
17
|
+
}
|
18
|
+
return txt;
|
19
|
+
}
|
20
|
+
|
21
|
+
function isLocationPrompt(alert) {
|
22
|
+
var exps = [
|
23
|
+
["OK", /vil bruge din aktuelle placering/],
|
24
|
+
["OK", /Would Like to Use Your Current Location/],
|
25
|
+
["Ja", /Darf (?:.)+ Ihren aktuellen Ort verwenden/]
|
26
|
+
],
|
27
|
+
ans, exp,
|
28
|
+
txt;
|
29
|
+
|
30
|
+
txt = findAlertViewText(alert);
|
31
|
+
for (var i = 0; i < exps.length; i++) {
|
32
|
+
ans = exps[i][0];
|
33
|
+
exp = exps[i][1];
|
34
|
+
if (exp.test(txt)) {
|
35
|
+
return ans;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return false;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
var alertHandlers = [//run in reverse order of this:
|
43
|
+
isLocationPrompt
|
44
|
+
];
|
45
|
+
|
46
|
+
|
47
|
+
UIATarget.onAlert = function (alert) {
|
48
|
+
var N = alertHandlers.length;
|
49
|
+
while (N--) {
|
50
|
+
if (alertHandlers[i]) {
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
return true;
|
55
|
+
};
|
56
|
+
|
57
|
+
function performAction(action, data) {
|
58
|
+
UIALogger.logMessage("perform action:" + action);
|
59
|
+
var actionTaken = true;
|
60
|
+
switch (action) {
|
61
|
+
case "setLocation":
|
62
|
+
target.setLocation({"latitude":data.latitude, "longitude":data.longitude});
|
63
|
+
break;
|
64
|
+
case "background":
|
65
|
+
target.deactivateAppForDuration(data.duration);
|
66
|
+
break;
|
67
|
+
case "registerAlertHandler":
|
68
|
+
alertHandlers.push(eval(data.handler));
|
69
|
+
break;
|
70
|
+
case "screenshot":
|
71
|
+
screenshot_count += 1;
|
72
|
+
target.captureScreenWithName(data.name || ("screenshot_" + screenshot_count));
|
73
|
+
break;
|
74
|
+
}
|
75
|
+
if (actionTaken && !data.preserve) {
|
76
|
+
target.frontMostApp().setPreferencesValueForKey(null, "__run_loop_action");
|
77
|
+
}
|
78
|
+
|
79
|
+
}
|
80
|
+
|
81
|
+
UIALogger.logStart("RunLoop");
|
82
|
+
|
83
|
+
var app = target.frontMostApp(),
|
84
|
+
val,
|
85
|
+
count = 0,
|
86
|
+
action = null;
|
87
|
+
while (true) {
|
88
|
+
target.delay(0.3);
|
89
|
+
val = app.preferencesValueForKey("__run_loop_action");
|
90
|
+
if (val && typeof val == 'object') {
|
91
|
+
action = val.action;
|
92
|
+
performAction(action, val);
|
93
|
+
}
|
94
|
+
count += 1;
|
95
|
+
}
|
96
|
+
|
97
|
+
UIALogger.logPass("RunLoop");
|
@@ -0,0 +1,172 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)
|
3
|
+
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
|
22
|
+
|
23
|
+
# Tell bash that we want the whole script to fail if any part fails.
|
24
|
+
set -e
|
25
|
+
|
26
|
+
# We require a parameter for where to put the results
|
27
|
+
destination="$1"
|
28
|
+
|
29
|
+
main() {
|
30
|
+
check_destination
|
31
|
+
|
32
|
+
xcode clean build TARGETED_DEVICE_FAMILY=1
|
33
|
+
|
34
|
+
bin/choose_sim_device "iPhone (Retina 3.5-inch)"
|
35
|
+
shoot en fr ja
|
36
|
+
|
37
|
+
bin/choose_sim_device "iPhone (Retina 4-inch)"
|
38
|
+
shoot en fr ja
|
39
|
+
|
40
|
+
# We to build again with the iPad device family because otherwise Instruments
|
41
|
+
# will build and run for iPhone even though the simulator says otherwise.
|
42
|
+
xcode build TARGETED_DEVICE_FAMILY=2
|
43
|
+
|
44
|
+
bin/choose_sim_device "iPad (Retina)"
|
45
|
+
shoot en fr ja
|
46
|
+
|
47
|
+
close_sim
|
48
|
+
}
|
49
|
+
|
50
|
+
# Global variables to keep track of where everything goes
|
51
|
+
dev_tools_dir=`xcode-select -print-path`
|
52
|
+
tmp_dir="/tmp"
|
53
|
+
build_dir="$tmp_dir/screen_shooter"
|
54
|
+
bundle_dir="$build_dir/app.app"
|
55
|
+
trace_results_dir="$build_dir/traces"
|
56
|
+
|
57
|
+
check_destination() {
|
58
|
+
# Abort if the destination directory already exists. Better safe than sorry.
|
59
|
+
|
60
|
+
if [ -z "$destination" ]; then
|
61
|
+
echo "usage: run_screenshooter.sh destination_directory"
|
62
|
+
exit 1
|
63
|
+
elif [ -d "$destination" ]; then
|
64
|
+
echo "Destination directory \"$destination\" already exists! Aborting."
|
65
|
+
exit 1
|
66
|
+
fi
|
67
|
+
}
|
68
|
+
|
69
|
+
shoot() {
|
70
|
+
# Takes the sim device type and a language code, runs the screenshot script,
|
71
|
+
# and then copies over the screenshots to the destination
|
72
|
+
|
73
|
+
for language in $*; do
|
74
|
+
clean_trace_results_dir
|
75
|
+
choose_sim_language $language
|
76
|
+
run_automation "automation/shoot_the_screens.js"
|
77
|
+
copy_screenshots
|
78
|
+
done
|
79
|
+
}
|
80
|
+
|
81
|
+
xcode() {
|
82
|
+
# A wrapper around `xcodebuild` that tells it to build the app in the temp
|
83
|
+
# directory. If your app uses workspaces or special schemes, you'll need to
|
84
|
+
# specify them here.
|
85
|
+
#
|
86
|
+
# Use `man xcodebuild` for more information on how to build your project.
|
87
|
+
|
88
|
+
xcodebuild -sdk iphonesimulator \
|
89
|
+
CONFIGURATION_BUILD_DIR=$build_dir \
|
90
|
+
PRODUCT_NAME=app \
|
91
|
+
$*
|
92
|
+
}
|
93
|
+
|
94
|
+
clean_trace_results_dir() {
|
95
|
+
# Removes the trace results directory. We need to do this because Instruments
|
96
|
+
# keeps appending new trace runs and it's simpler for us to always assume
|
97
|
+
# there's just one run recorded where we look for screenshots.
|
98
|
+
|
99
|
+
rm -rf "$trace_results_dir"
|
100
|
+
mkdir -p "$trace_results_dir"
|
101
|
+
}
|
102
|
+
|
103
|
+
choose_sim_language() {
|
104
|
+
# Alters the global preference file for every simulator type and moves the
|
105
|
+
# chosen language identifier to the top.
|
106
|
+
|
107
|
+
echo "Localizing for $1"
|
108
|
+
|
109
|
+
pref_files=`ls ~/Library/Application\ Support/iPhone\ Simulator/[0-9]*/Library/Preferences/.GlobalPreferences.plist`
|
110
|
+
|
111
|
+
close_sim
|
112
|
+
|
113
|
+
|
114
|
+
# Set the string split delimiter to a newline for the 'for..in'
|
115
|
+
old=$IFS
|
116
|
+
IFS="
|
117
|
+
"
|
118
|
+
|
119
|
+
for file in $pref_files; do
|
120
|
+
# Disable errors temporarily just in case the prefs don't have the key
|
121
|
+
# we're trying to delete. This could happen when experimenting and leaving
|
122
|
+
# the prefs file in an inconsistent state. If anything goes horribly wrong,
|
123
|
+
# just delete the prefs file altogether and run the simulator to recreate
|
124
|
+
# it.
|
125
|
+
set +e
|
126
|
+
/usr/libexec/PlistBuddy "$file" -c "Delete :AppleLanguages"
|
127
|
+
set -e
|
128
|
+
|
129
|
+
# Create the language array with just the given language
|
130
|
+
/usr/libexec/PlistBuddy "$file" \
|
131
|
+
-c "Add :AppleLanguages array" \
|
132
|
+
-c "Add :AppleLanguages:0 string '$1'" \
|
133
|
+
-c "Set :AppleLocale '$1'"
|
134
|
+
done
|
135
|
+
|
136
|
+
# Put the old string split delimiter back
|
137
|
+
IFS=$old
|
138
|
+
}
|
139
|
+
|
140
|
+
|
141
|
+
close_sim() {
|
142
|
+
# Closes the simulator. We need to do this after altering the languages and
|
143
|
+
# when we want to clean up at the end.
|
144
|
+
|
145
|
+
osascript -e 'tell application "iPhone Simulator" to quit'
|
146
|
+
}
|
147
|
+
|
148
|
+
run_automation() {
|
149
|
+
# Runs the UI Automation JavaScript file that actually takes the screenshots.
|
150
|
+
|
151
|
+
tracetemplate="$dev_tools_dir/../Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate"
|
152
|
+
|
153
|
+
# Check out the `unix_instruments` script to see why we need this wrapper.
|
154
|
+
bin/unix_instruments \
|
155
|
+
-D "$trace_results_dir/trace" \
|
156
|
+
-t "$tracetemplate" \
|
157
|
+
$bundle_dir \
|
158
|
+
-e UIARESULTSPATH "$trace_results_dir" \
|
159
|
+
-e UIASCRIPT "$1" \
|
160
|
+
$*
|
161
|
+
}
|
162
|
+
|
163
|
+
copy_screenshots() {
|
164
|
+
# Since we're always clearing out the trace results before every run, we can
|
165
|
+
# assume that any screenshots were saved in the "Run 1" directory. Copy them
|
166
|
+
# to the destination!
|
167
|
+
|
168
|
+
mkdir -p "$destination"
|
169
|
+
cp $trace_results_dir/Run\ 1/*.png $destination
|
170
|
+
}
|
171
|
+
|
172
|
+
main
|
data/scripts/udidetect
ADDED
Binary file
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
#
|
3
|
+
# Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net)
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
#
|
23
|
+
|
24
|
+
|
25
|
+
# unix_instruments
|
26
|
+
#
|
27
|
+
# A wrapper around `instruments` that returns a proper unix status code
|
28
|
+
# depending on whether the run failed or not. Alas, Apple's instruments tool
|
29
|
+
# doesn't care about unix status codes, so I must grep for the "Fail:" string
|
30
|
+
# and figure it out myself. As long as the command doesn't output that string
|
31
|
+
# anywhere else inside it, then it should work.
|
32
|
+
#
|
33
|
+
# I use a tee pipe to capture the output and deliver it to stdout
|
34
|
+
#
|
35
|
+
# Author: Jonathan Penn (jonathan@cocoamanifest.net)
|
36
|
+
#
|
37
|
+
|
38
|
+
set -e # Bomb on any script errors
|
39
|
+
|
40
|
+
run_instruments() {
|
41
|
+
# Because instruments buffers it's output if it determines that it is being
|
42
|
+
# piped to another process, we have to use ptys to get around that so that we
|
43
|
+
# can use `tee` to save the output for grepping and print to stdout in real
|
44
|
+
# time at the same time.
|
45
|
+
#
|
46
|
+
# I don't like this because I'm hard coding a tty/pty pair in here. Suggestions
|
47
|
+
# to make this cleaner?
|
48
|
+
|
49
|
+
output=$(mktemp -t unix-instruments)
|
50
|
+
instruments $@ &> /dev/ttyvf & pid_instruments=$!
|
51
|
+
|
52
|
+
# Cat the instruments output to tee which outputs to stdout and saves to
|
53
|
+
# $output at the same time
|
54
|
+
cat < /dev/ptyvf | tee $output
|
55
|
+
|
56
|
+
# Clear the process id we saved when forking instruments so the cleanup
|
57
|
+
# function called on exit knows it doesn't have to kill anything
|
58
|
+
pid_instruments=0
|
59
|
+
|
60
|
+
# Process the instruments output looking for anything that resembles a fail
|
61
|
+
# message
|
62
|
+
cat $output | get_error_status
|
63
|
+
}
|
64
|
+
|
65
|
+
get_error_status() {
|
66
|
+
# Catch "Instruments Trace Error"
|
67
|
+
# Catch "Instruments Usage Error"
|
68
|
+
# Catch "00-00-00 00:00:00 +000 Fail:"
|
69
|
+
# Catch "00-00-00 00:00:00 +000 Error:"
|
70
|
+
# Catch "00-00-00 00:00:00 +000 None: Script threw an uncaught JavaScript error"
|
71
|
+
ruby -e 'exit 1 if STDIN.read =~ /Instruments Usage Error|Instruments Trace Error|^\d+-\d+-\d+ \d+:\d+:\d+ [-+]\d+ (Fail:|Error:|None: Script threw an uncaught JavaScript error)/'
|
72
|
+
}
|
73
|
+
|
74
|
+
trap cleanup_instruments EXIT INT TERM
|
75
|
+
function cleanup_instruments() {
|
76
|
+
# Because we fork instruments in this script, we need to clean up if it's
|
77
|
+
# still running because of an error or the user pressed Ctrl-C
|
78
|
+
if [[ $pid_instruments -gt 0 ]]; then
|
79
|
+
echo "Cleaning up instruments..."
|
80
|
+
kill $pid_instruments
|
81
|
+
fi
|
82
|
+
}
|
83
|
+
|
84
|
+
# Running this file with "----test" will try to parse an error out of whatever
|
85
|
+
# is handed in to it from stdin. Use this method to double check your work if
|
86
|
+
# you need a custom "get_error_status" function above.
|
87
|
+
if [[ $1 == "----test" ]]; then
|
88
|
+
get_error_status
|
89
|
+
else
|
90
|
+
run_instruments $@
|
91
|
+
fi
|
92
|
+
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: run_loop
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Karl Krukow
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: calabash-cucumber drives tests for native iOS apps. RunLoop provides
|
31
|
+
a number of tools associated with running Calabash tests.
|
32
|
+
email:
|
33
|
+
- karl@lesspainful.com
|
34
|
+
executables:
|
35
|
+
- run-loop
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- .gitignore
|
40
|
+
- .gitmodules
|
41
|
+
- .irbrc
|
42
|
+
- CHANGES.txt
|
43
|
+
- Gemfile
|
44
|
+
- LICENSE
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- bin/run-loop
|
48
|
+
- docs/intro.md
|
49
|
+
- irb.sh
|
50
|
+
- lib/run_loop.rb
|
51
|
+
- lib/run_loop/cli.rb
|
52
|
+
- lib/run_loop/core.rb
|
53
|
+
- lib/run_loop/version.rb
|
54
|
+
- run_loop.gemspec
|
55
|
+
- scripts/run_dismiss_location.js
|
56
|
+
- scripts/run_screenshooter.sh
|
57
|
+
- scripts/udidetect
|
58
|
+
- scripts/unix_instruments
|
59
|
+
homepage: http://calaba.sh
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.23
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Tools related to running Calabash iOS tests
|
83
|
+
test_files: []
|