run_loop_tcc 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/bin/run-loop +19 -0
  4. data/lib/run_loop/abstract.rb +18 -0
  5. data/lib/run_loop/app.rb +372 -0
  6. data/lib/run_loop/cache/cache.rb +68 -0
  7. data/lib/run_loop/cli/cli.rb +48 -0
  8. data/lib/run_loop/cli/codesign.rb +24 -0
  9. data/lib/run_loop/cli/errors.rb +11 -0
  10. data/lib/run_loop/cli/instruments.rb +160 -0
  11. data/lib/run_loop/cli/locale.rb +31 -0
  12. data/lib/run_loop/cli/simctl.rb +257 -0
  13. data/lib/run_loop/cli/tcc.rb +139 -0
  14. data/lib/run_loop/codesign.rb +76 -0
  15. data/lib/run_loop/core.rb +902 -0
  16. data/lib/run_loop/core_simulator.rb +960 -0
  17. data/lib/run_loop/detect_aut/detect.rb +185 -0
  18. data/lib/run_loop/detect_aut/errors.rb +126 -0
  19. data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
  20. data/lib/run_loop/detect_aut/xcode.rb +157 -0
  21. data/lib/run_loop/device.rb +722 -0
  22. data/lib/run_loop/device_agent/app/CBX-Runner.app.zip +0 -0
  23. data/lib/run_loop/device_agent/bin/xctestctl +0 -0
  24. data/lib/run_loop/device_agent/cbxrunner.rb +156 -0
  25. data/lib/run_loop/device_agent/frameworks/Frameworks.zip +0 -0
  26. data/lib/run_loop/device_agent/frameworks.rb +65 -0
  27. data/lib/run_loop/device_agent/ipa/CBX-Runner.app.zip +0 -0
  28. data/lib/run_loop/device_agent/launcher.rb +51 -0
  29. data/lib/run_loop/device_agent/xcodebuild.rb +91 -0
  30. data/lib/run_loop/device_agent/xctestctl.rb +109 -0
  31. data/lib/run_loop/directory.rb +179 -0
  32. data/lib/run_loop/dnssd.rb +148 -0
  33. data/lib/run_loop/dot_dir.rb +87 -0
  34. data/lib/run_loop/dylib_injector.rb +145 -0
  35. data/lib/run_loop/encoding.rb +56 -0
  36. data/lib/run_loop/environment.rb +361 -0
  37. data/lib/run_loop/fifo.rb +40 -0
  38. data/lib/run_loop/host_cache.rb +128 -0
  39. data/lib/run_loop/http/error.rb +15 -0
  40. data/lib/run_loop/http/request.rb +44 -0
  41. data/lib/run_loop/http/retriable_client.rb +166 -0
  42. data/lib/run_loop/http/server.rb +17 -0
  43. data/lib/run_loop/instruments.rb +436 -0
  44. data/lib/run_loop/ipa.rb +142 -0
  45. data/lib/run_loop/l10n.rb +93 -0
  46. data/lib/run_loop/language.rb +63 -0
  47. data/lib/run_loop/lipo.rb +132 -0
  48. data/lib/run_loop/lldb.rb +52 -0
  49. data/lib/run_loop/locale.rb +101 -0
  50. data/lib/run_loop/logging.rb +111 -0
  51. data/lib/run_loop/otool.rb +76 -0
  52. data/lib/run_loop/patches/awesome_print.rb +17 -0
  53. data/lib/run_loop/physical_device/life_cycle.rb +268 -0
  54. data/lib/run_loop/plist_buddy.rb +189 -0
  55. data/lib/run_loop/process_terminator.rb +128 -0
  56. data/lib/run_loop/process_waiter.rb +117 -0
  57. data/lib/run_loop/regex.rb +19 -0
  58. data/lib/run_loop/shell.rb +103 -0
  59. data/lib/run_loop/sim_control.rb +1264 -0
  60. data/lib/run_loop/simctl.rb +275 -0
  61. data/lib/run_loop/sqlite.rb +61 -0
  62. data/lib/run_loop/strings.rb +88 -0
  63. data/lib/run_loop/tcc/TCC.db +0 -0
  64. data/lib/run_loop/tcc/tcc.rb +240 -0
  65. data/lib/run_loop/template.rb +61 -0
  66. data/lib/run_loop/version.rb +182 -0
  67. data/lib/run_loop/xcode.rb +318 -0
  68. data/lib/run_loop/xcrun.rb +107 -0
  69. data/lib/run_loop/xcuitest.rb +550 -0
  70. data/lib/run_loop.rb +230 -0
  71. data/plists/simctl/com.apple.UIAutomation.plist +0 -0
  72. data/plists/simctl/com.apple.UIAutomationPlugIn.plist +0 -0
  73. data/scripts/calabash_script_uia.js +28184 -0
  74. data/scripts/lib/json2.min.js +26 -0
  75. data/scripts/lib/log.js +26 -0
  76. data/scripts/lib/on_alert.js +224 -0
  77. data/scripts/read-cmd.sh +2 -0
  78. data/scripts/run_dismiss_location.js +89 -0
  79. data/scripts/run_loop_basic.js +34 -0
  80. data/scripts/run_loop_fast_uia.js +188 -0
  81. data/scripts/run_loop_host.js +117 -0
  82. data/scripts/run_loop_shared_element.js +125 -0
  83. data/scripts/timeout3 +23 -0
  84. data/scripts/udidetect +0 -0
  85. data/vendor-licenses/FBSimulatorControl.LICENSE +30 -0
  86. data/vendor-licenses/xctestctl.LICENSE +32 -0
  87. metadata +443 -0
@@ -0,0 +1,26 @@
1
+
2
+ if(typeof JSON!=='object'){JSON={};}
3
+ (function(){'use strict';function f(n){return n<10?'0'+n:n;}
4
+ if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
5
+ f(this.getUTCMonth()+1)+'-'+
6
+ f(this.getUTCDate())+'T'+
7
+ f(this.getUTCHours())+':'+
8
+ f(this.getUTCMinutes())+':'+
9
+ f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
10
+ var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
11
+ function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
12
+ if(typeof rep==='function'){value=rep.call(holder,key,value);}
13
+ switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
14
+ gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
15
+ v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}
16
+ if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]==='string'){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
17
+ v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
18
+ if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
19
+ rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
20
+ return str('',{'':value});};}
21
+ if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
22
+ return reviver.call(holder,key,value);}
23
+ text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
24
+ ('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
25
+ if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
26
+ throw new SyntaxError('JSON.parse');};}}());
@@ -0,0 +1,26 @@
1
+ var Log = (function () {
2
+ var forceFlush = [];
3
+ var N = "$FLUSH_LOGS" == "FLUSH_LOGS" ? 16384 : 0;
4
+ var i = N;
5
+ while (i--) {
6
+ forceFlush[i] = "*";
7
+ }
8
+ forceFlush = forceFlush.join('');
9
+
10
+ function log_json(object)
11
+ {
12
+ UIALogger.logMessage("OUTPUT_JSON:\n"+JSON.stringify(object)+"\nEND_OUTPUT");
13
+ if (forceFlush.length > 0) {
14
+ UIALogger.logMessage(forceFlush);
15
+ }
16
+ }
17
+
18
+ return {
19
+ result: function (status, data) {
20
+ log_json({"status": status, "value": data, "index":_actualIndex});
21
+ },
22
+ output: function (msg) {
23
+ log_json({"output": msg,"last_index":_actualIndex});
24
+ }
25
+ };
26
+ })();
@@ -0,0 +1,224 @@
1
+ function findAlertTitle(alert) {
2
+ if (!alert) {
3
+ return false;
4
+ }
5
+ var title = alert.name();
6
+ var staticTexts;
7
+
8
+ if (title === null) {
9
+ staticTexts = alert.staticTexts();
10
+ if (staticTexts !== null && staticTexts.length > 0) {
11
+
12
+ title = staticText[0].name();
13
+ }
14
+
15
+ }
16
+ return title;
17
+ }
18
+
19
+ function findAlertButtonNames(alert) {
20
+ if (!alert) {
21
+ return false;
22
+ }
23
+
24
+ var buttons = alert.buttons();
25
+ var leftButton = buttons[0].name();
26
+ var rightButton = buttons[1].name();
27
+
28
+ return leftButton + "," + rightButton;
29
+ }
30
+
31
+ function englishLocalizations() {
32
+ return [
33
+ ["OK", /Would Like to Use Your Current Location/],
34
+ ["OK", /Location Accuracy/],
35
+ ["Allow", /access your location/],
36
+ ["OK", /Would Like to Access Your Photos/],
37
+ ["OK", /Would Like to Access Your Contacts/],
38
+ ["OK", /Access the Microphone/],
39
+ ["OK", /Would Like to Access Your Calendar/],
40
+ ["OK", /Would Like to Access Your Reminders/],
41
+ ["OK", /Would Like to Access Your Motion Activity/],
42
+ ["OK", /Would Like to Access the Camera/],
43
+ ["OK", /Would Like to Access Your Motion & Fitness Activity/],
44
+ ["OK", /Would Like Access to Twitter Accounts/],
45
+ ["OK", /data available to nearby bluetooth devices/],
46
+ ["OK", /[Ww]ould [Ll]ike to [Ss]end [Yy]ou( Push)? Notifications/]
47
+ ];
48
+ }
49
+
50
+ function danishLocalizations() {
51
+ return [
52
+ ["Tillad", /bruge din lokalitet, når du bruger appen/],
53
+ ["Tillad", /også når du ikke bruger appen/],
54
+ ["OK", /vil bruge din aktuelle placering/],
55
+ ["OK", /vil bruge dine kontakter/],
56
+ ["OK", /vil bruge mikrofonen/],
57
+ ["OK", /vil bruge din kalender/],
58
+ ["OK", /vil bruge dine påmindelser/],
59
+ ["OK", /vil bruge dine fotos/],
60
+ ["OK", /ønsker adgang til Twitter-konti/],
61
+ ["OK", /vil bruge din fysiske aktivitet og din træningsaktivitet/],
62
+ ["OK", /vil bruge kameraet/],
63
+ ["OK", /vil gerne sende dig meddelelser/]
64
+ ];
65
+ }
66
+
67
+ function euSpanishLocalizations() {
68
+ return [
69
+ ["Permitir", /acceder a tu ubicación mientras utilizas la aplicación/],
70
+ ["Permitir", /acceder a tu ubicación aunque no estés utilizando la aplicación/],
71
+ ["OK", /quiere acceder a tus contactos/],
72
+ ["OK", /quiere acceder a tu calendario/],
73
+ ["OK", /quiere acceder a tus recordatorios/],
74
+ ["OK", /quiere acceder a tus fotos/],
75
+ ["OK", /quiere obtener acceso a cuentas Twitter/],
76
+ ["OK", /quiere acceder al micrófono/],
77
+ ["OK", /desea acceder a tu actividad física y deportiva/],
78
+ ["OK", /quiere acceder a la cámara/],
79
+ ["OK", /quiere enviarte notificaciones/]
80
+ ];
81
+ }
82
+
83
+ function es419SpanishLocalizations() {
84
+ return [
85
+ ["Permitir", /acceda a tu ubicación mientras la app está en uso/],
86
+ ["Permitir", /acceda a tu ubicación incluso cuando la app no está en uso/],
87
+ ["OK", /quiere acceder a tu condición y actividad física/]
88
+ ];
89
+ }
90
+
91
+ function spanishLocalizations() {
92
+ return [].concat(
93
+ euSpanishLocalizations(),
94
+ es419SpanishLocalizations()
95
+ );
96
+ }
97
+
98
+ function germanLocalizations() {
99
+ return [
100
+ ["Ja", /Darf (?:.)+ Ihren aktuellen Ort verwenden/],
101
+ ["Erlauben", /auf Ihren Standort zugreifen, wenn Sie die App benutzen/],
102
+ ["Erlauben", /auch auf Ihren Standort zugreifen, wenn Sie die App nicht benutzen/],
103
+ ["Erlauben", /auf Ihren Standort zugreifen, selbst wenn Sie die App nicht benutzen/],
104
+ ["Ja", /auf Ihre Kontakte zugreifen/],
105
+ ["Ja", /auf Ihren Kalender zugreifen/],
106
+ ["Ja", /auf Ihre Erinnerungen zugreifen/],
107
+ ["Ja", /auf Ihre Fotos zugreifen/],
108
+ ["Erlauben", /möchte auf Twitter-Accounts zugreifen/],
109
+ ["Ja", /auf das Mikrofon zugreifen/],
110
+ ["Ja", /möchte auf Ihre Bewegungs- und Fitnessdaten zugreifen/],
111
+ ["Ja", /auf Ihre Kamera zugreifen/],
112
+ ["OK", /Ihnen Mitteilungen senden/]
113
+ ];
114
+ }
115
+
116
+ function dutchLocalizations() {
117
+ return [
118
+ ["Sta toe", /tot uw locatie toestaan terwijl u de app gebruikt/],
119
+ ["Sta toe", /toegang tot uw locatie toestaan terwijl u de app gebruikt/],
120
+ ["Sta toe", /ook toegang tot uw locatie toestaan, zelfs als u de app niet gebruikt/],
121
+ ["Sta toe", /toegang tot uw locatie toestaan, zelfs als u de app niet gebruikt/],
122
+ ["OK", /wil toegang tot uw contacten/],
123
+ ["OK", /wil toegang tot uw agenda/],
124
+ ["OK", /wil toegang tot uw herinneringen/],
125
+ ["OK", /wil toegang tot uw foto's/],
126
+ ["OK", /wil toegang tot Twitter-accounts/],
127
+ ["OK", /wil toegang tot de microfoon/],
128
+ ["OK", /wil toegang tot uw bewegings- en fitnessactiviteit/],
129
+ ["OK", /wil toegang tot de camera/],
130
+ ["OK", /wil u berichten sturen/]
131
+ ];
132
+ }
133
+
134
+ function russianLocalizations() {
135
+ return [
136
+ // Location
137
+ ["OK", /запрашивает разрешение на использование Ващей текущей пгеопозиции/]
138
+ ];
139
+ }
140
+
141
+ function frenchLocalizations() {
142
+ return [
143
+ ["OK", /vous envoyer des notifications/],
144
+ ["Autoriser", /à accéder à vos données de localisation lorsque vous utilisez l’app/],
145
+ ["Autoriser", /à accéder à vos données de localisation même lorsque vous n’utilisez pas l’app/],
146
+ ["Autoriser", /à accéder aussi à vos données de localisation lorsque vous n’utilisez pas l’app/],
147
+ ["OK", /souhaite accéder à vos contacts/],
148
+ ["OK", /souhaite accéder à votre calendrier/],
149
+ ["OK", /souhaite accéder à vos rappels/],
150
+ ["OK", /souhaite accéder à vos mouvements et vos activités physiques/],
151
+ ["OK", /souhaite accéder à vos photos/],
152
+ ["OK", /souhaite accéder à l’appareil photo/],
153
+ ["OK", /souhaite accéder aux comptes Twitter/],
154
+ ["OK", /souhaite accéder au micro/]
155
+ ];
156
+ }
157
+
158
+ function localizations() {
159
+ return [].concat(
160
+ danishLocalizations(),
161
+ dutchLocalizations(),
162
+ englishLocalizations(),
163
+ germanLocalizations(),
164
+ russianLocalizations(),
165
+ spanishLocalizations(),
166
+ frenchLocalizations()
167
+ );
168
+ }
169
+
170
+ function isPrivacyAlert(alert) {
171
+
172
+ var expressions = localizations();
173
+
174
+ var title = findAlertTitle(alert);
175
+
176
+ // Comment this out when capturing new regexes. See the comment below.
177
+ Log.output({"alert":title});
178
+
179
+ // When debugging or trying to capture the regexes for a new
180
+ // localization, uncomment the logging below.
181
+ //
182
+ // Notes:
183
+ // * Microphone alerts only appear on physical devices.
184
+ // * You have to click through the Health alert; it is completely blocking -
185
+ // tests will not proceed.
186
+ // * Generating bluetooth alerts is NYI.
187
+ // * In general, there will be a different alert on device for using location
188
+ // in background mode.
189
+ // * Alerts vary by iOS.
190
+ // * To reset notifications on devices:
191
+ // General > Settings > Reset > Reset Location + Privacy
192
+ // - These are the last table rows
193
+ // - APNS permissions are reset once a day.
194
+ // * On devices, set the device language in Settings.
195
+ //
196
+ // Use the Permission.app.
197
+ //
198
+ // * Alert text is printed at the end of every test.
199
+ // * Alert text is written to a file in Permissions/tmp.
200
+ //
201
+ // Examples:
202
+ //
203
+ // # Simulator running Mexican Spanish
204
+ // $ APP_LANG="es-MX" APP_LOCALE="es_MX" be cucumber -t @supported
205
+ //
206
+ // # Device running Dutch
207
+ // $ APP_LANG="nl" APP_LOCALE="nl" be cucumber -t @supported -p macmini
208
+
209
+ // This is very slow, so only do this if you are trying to capture regexes.
210
+ //var buttonNames = findAlertButtonNames(alert);
211
+ //Log.output({"alert":{"title":title, "buttons":buttonNames, "capture":"YES"}});
212
+
213
+ var answer;
214
+ var expression;
215
+ for (var i = 0; i < expressions.length; i++) {
216
+ answer = expressions[i][0];
217
+ expression = expressions[i][1];
218
+ if (expression.test(title)) {
219
+ return answer;
220
+ }
221
+ }
222
+ return false;
223
+ }
224
+
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ read line < $1 && echo $line
@@ -0,0 +1,89 @@
1
+ var target = UIATarget.localTarget(),
2
+ screenshot_count = 0;
3
+
4
+ <%= render_template("lib/on_alert.js") %>
5
+
6
+ var alertHandlers = [//run in reverse order of this:
7
+ isLocationPrompt
8
+ ];
9
+
10
+
11
+ UIATarget.onAlert = function (alert) {
12
+ var N = alertHandlers.length;
13
+ while (N--) {
14
+ if (alertHandlers[i]) {
15
+ break;
16
+ }
17
+ }
18
+ return true;
19
+ };
20
+
21
+ function performAction(action, data) {
22
+ UIALogger.logMessage("perform action:" + action);
23
+ var actionTaken = true,
24
+ res = null;
25
+ switch (action) {
26
+ case "setLocation":
27
+ target.setLocation({"latitude":data.latitude, "longitude":data.longitude});
28
+ break;
29
+ case "background":
30
+ target.deactivateAppForDuration(data.duration);
31
+ break;
32
+ case "registerAlertHandler":
33
+ alertHandlers.push(eval(data.handler));
34
+ break;
35
+ case "screenshot":
36
+ screenshot_count += 1;
37
+ target.captureScreenWithName(data.name || ("screenshot_" + screenshot_count));
38
+ break;
39
+ case "eval":
40
+ try {
41
+ res = eval(data);
42
+ } catch (e) {
43
+ if (e) {
44
+ UIALogger.logMessage(e.toString());
45
+ }
46
+ }
47
+ break;
48
+ }
49
+ if (actionTaken && !data.preserve) {
50
+ target.frontMostApp().setPreferencesValueForKey(null, "__run_loop_action");
51
+ }
52
+ return res;
53
+
54
+ }
55
+
56
+ UIALogger.logStart("RunLoop");
57
+
58
+ var app = target.frontMostApp(),
59
+ val,
60
+ res,
61
+ count = 0,
62
+ action = null;
63
+ while (true) {
64
+ target.delay(1);
65
+ val = target.frontMostApp().preferencesValueForKey("__run_loop_action");
66
+ if (val)
67
+ UIALogger.logMessage(val);
68
+ else {
69
+ UIALogger.logMessage("null");
70
+ val = target.frontMostApp().preferencesValueForKey("x");
71
+ if (val)
72
+ UIALogger.logMessage(val.toString());
73
+ }
74
+
75
+ if (val && typeof val == 'object') {
76
+ action = val.action;
77
+ performAction(action, val);
78
+ }
79
+ else if (val && typeof val == 'string') {
80
+ res = performAction("eval", val);
81
+ if (res) {
82
+ UIALogger.logMessage(res.toString());
83
+ }
84
+ }
85
+
86
+ count += 1;
87
+ }
88
+
89
+ UIALogger.logPass("RunLoop");
@@ -0,0 +1,34 @@
1
+ <%= render_template("lib/json2.min.js") %>
2
+ <%= render_template("lib/log.js"); %>
3
+ <%= render_template("lib/on_alert.js"); %>
4
+
5
+ UIATarget.onAlert = function (alert) {
6
+ Log.output({"output":"on alert"});
7
+ var target = UIATarget.localTarget();
8
+ target.pushTimeout(10);
9
+ function dismissPrivacyAlert(retry_count) {
10
+ retry_count = retry_count || 0;
11
+ if (retry_count >= 5) {
12
+ Log.output("Maxed out retry (5) - unable to dismiss privacy alert.");
13
+ return;
14
+ }
15
+ try {
16
+ var answer = isPrivacyAlert(alert);
17
+ if (answer) {
18
+ alert.buttons()[answer].tap();
19
+ }
20
+ }
21
+ catch (e) {
22
+ Log.output("Exception while trying to touch alert. Retrying...");
23
+ if (e && typeof e.toString == 'function') {
24
+ Log.output(e.toString());
25
+ }
26
+ target.delay(1);
27
+ dismissPrivacyAlert(retry_count + 1);
28
+ }
29
+ }
30
+
31
+ dismissPrivacyAlert(0);
32
+ target.popTimeout();
33
+ return true;
34
+ };
@@ -0,0 +1,188 @@
1
+ <% render_template("lib/json2.min.js") %>
2
+
3
+ _RUN_LOOP_MAX_RETRY_AFTER_HANDLER = 10;
4
+ var _expectedIndex = 0,//expected index of next command
5
+ _actualIndex=0,//actual index of next command by reading commandPath
6
+ _exp,//expression to be eval'ed
7
+ _result,
8
+ _lastResponse=null;
9
+
10
+ <%= render_template("lib/log.js"); %>
11
+ <%= render_template("lib/on_alert.js"); %>
12
+
13
+ UIATarget.onAlert = function (alert) {
14
+ var target = UIATarget.localTarget(),
15
+ app = target.frontMostApp(),
16
+ req = null,
17
+ rsp = null,
18
+ actualIndex = null;
19
+ target.pushTimeout(10);
20
+ function dismissPrivacyAlert(retry_count) {
21
+ retry_count = retry_count || 0;
22
+ if (retry_count >= 5) {
23
+ Log.output("Maxed out retry (5) - unable to dismiss privacy alert.");
24
+ return;
25
+ }
26
+ try {
27
+ var answer = isPrivacyAlert(alert);
28
+ if (answer) {
29
+ alert.buttons()[answer].tap();
30
+ }
31
+ }
32
+ catch (e) {
33
+ Log.output("Exception while trying to touch privacy alert. Retrying...");
34
+ if (e && typeof e.toString == 'function') {
35
+ Log.output(e.toString());
36
+ }
37
+ target.delay(1);
38
+ dismissPrivacyAlert(retry_count + 1);
39
+ }
40
+ }
41
+
42
+ dismissPrivacyAlert(0);
43
+ target.popTimeout();
44
+
45
+ for (var i=0;i<_RUN_LOOP_MAX_RETRY_AFTER_HANDLER;i++) {
46
+ req = app.preferencesValueForKey(__calabashRequest);
47
+ rsp = app.preferencesValueForKey(__calabashResponse);
48
+ actualIndex = req && req['index'];
49
+ if (req && !isNaN(actualIndex) && actualIndex <= _lastResponse['index']) {
50
+ UIALogger.logMessage("Deleting previous response: "+(rsp && rsp['index']));
51
+ app.setPreferencesValueForKey(0, __calabashRequest);
52
+ app.setPreferencesValueForKey(null, __calabashRequest);
53
+ }
54
+ if (_lastResponse) {
55
+ UIALogger.logMessage("Re-Writing response: "+_lastResponse['value']);
56
+ _response(_lastResponse);
57
+ }
58
+ }
59
+ return true;
60
+ };
61
+
62
+ var target = null,
63
+ failureMessage = null,
64
+ preferences = null,
65
+ __calabashRequest = "__calabashRequest",
66
+ __calabashResponse = "__calabashResponse",
67
+ _sanitize = function(val) {
68
+ if (typeof val === 'undefined' || val === null || val instanceof UIAElementNil) {
69
+ return ":nil";
70
+ }
71
+ if (typeof val === 'string' || val instanceof String) {
72
+ return val;
73
+ }
74
+ var arrVal = null, i, N;
75
+ if (val instanceof Array || val instanceof UIAElementArray) {
76
+ arrVal = [];
77
+ for (i=0,N=val.length;i<N;i++) {
78
+ arrVal[i] = _sanitize(val[i]);
79
+ }
80
+ return arrVal;
81
+ }
82
+ if (val instanceof UIAElement) {
83
+ return val.toString();
84
+ }
85
+ var objVal = null, p;
86
+ if (typeof val == 'object') {
87
+ objVal = {};
88
+ for (p in val) {
89
+ objVal[p] = _sanitize(val[p]);
90
+ }
91
+ return objVal;
92
+ }
93
+ return val;
94
+ },
95
+ _response = function(response) {
96
+ var sanitized = _sanitize(response),
97
+ i = 0,
98
+ MAX_TRIES=120,
99
+ res,
100
+ tmp;
101
+
102
+ for (i=0; i<MAX_TRIES; i+=1) {
103
+ tmp = target.frontMostApp().preferencesValueForKey(__calabashResponse);
104
+ UIALogger.logMessage("Last response..."+(tmp && tmp['index']+"->"+tmp['value']));
105
+ target.frontMostApp().setPreferencesValueForKey(sanitized, __calabashResponse);
106
+ res = target.frontMostApp().preferencesValueForKey(__calabashRequest);
107
+ res = target.frontMostApp().preferencesValueForKey(__calabashResponse);
108
+ UIALogger.logMessage("Next response..."+(res && res['value']));
109
+ target.delay(0.1);
110
+ res = target.frontMostApp().preferencesValueForKey(__calabashResponse);
111
+ UIALogger.logMessage("Post delay response..."+(res && res['value']));
112
+ if (res && res['index'] == sanitized['index']) {
113
+ UIALogger.logMessage("Storage succeeded: "+ res['index']);
114
+ return;
115
+ } else {
116
+ UIALogger.logMessage("Storage failed: "+ res + " Retrying...");
117
+ target.delay(0.2);
118
+ }
119
+ }
120
+ throw new Error("Unable to write to preferences");
121
+ },
122
+ _success = function(result,index) {
123
+ _lastResponse = {"status":'success', "value":result, "index": index};
124
+ _response(_lastResponse);
125
+
126
+ },
127
+ _failure = function(err, index) {
128
+ _lastResponse = {"status":'error',
129
+ "value":err.toString(),
130
+ "backtrace":(err.stack ? err.stack.toString() : ""),
131
+ "index":index};
132
+ _response(_lastResponse);
133
+ },
134
+ _resetCalabashPreferences = function () {
135
+ //Implementation is weird but reading pref values seems to have side effects
136
+ //also deleting a key seemed to require writing 0 and then null :)
137
+ var app = UIATarget.localTarget().frontMostApp();
138
+ app.preferencesValueForKey(__calabashRequest);
139
+ app.preferencesValueForKey(__calabashResponse);
140
+ app.setPreferencesValueForKey(0, __calabashResponse);
141
+ app.setPreferencesValueForKey(null, __calabashResponse);
142
+ app.setPreferencesValueForKey(0, __calabashRequest);
143
+ app.setPreferencesValueForKey(null, __calabashRequest);
144
+ };
145
+
146
+ _resetCalabashPreferences();
147
+ Log.result('success', true);
148
+ target = UIATarget.localTarget();
149
+ while (true) {
150
+ try {
151
+ preferences = target.frontMostApp().preferencesValueForKey(__calabashRequest);
152
+ } catch (e) {
153
+ Log.output("Unable to read preferences..."+ e.toString());
154
+ target.delay(0.5);
155
+ continue;
156
+ }
157
+
158
+ if (!preferences) {
159
+ target.delay(0.2);
160
+ continue;
161
+ }
162
+
163
+ _actualIndex = preferences['index'];
164
+ if (!isNaN(_actualIndex) && _actualIndex >= _expectedIndex) {
165
+ UIATarget.localTarget().frontMostApp().setPreferencesValueForKey(null, __calabashResponse);
166
+ _exp = preferences['command'];
167
+ UIALogger.logMessage("index " + _actualIndex + " is command: "+ _exp);
168
+ try {
169
+ if (_exp == 'break;') {
170
+ _success("OK", _actualIndex);
171
+ break;
172
+ }
173
+ _result = eval(_exp);
174
+ UIALogger.logMessage("Success: "+ _result);
175
+ _success(_result, _actualIndex);
176
+ }
177
+ catch(err) {
178
+ failureMessage = "Failure: "+ err.toString() + " " + (err.stack ? err.stack.toString() : "");
179
+ Log.output({"output":failureMessage});
180
+ _failure(err, _actualIndex);
181
+ }
182
+ }
183
+ else {//likely old command is lingering...
184
+ continue;
185
+ }
186
+ _expectedIndex = Math.max(_actualIndex+1, _expectedIndex+1);
187
+ target.delay(0.2);
188
+ }