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,275 @@
1
+ module RunLoop
2
+
3
+ # @!visibility private
4
+ # An interface to the `simctl` command line tool for CoreSimulator.
5
+ #
6
+ # Replacement for SimControl.
7
+ class Simctl
8
+
9
+ # @!visibility private
10
+ DEFAULTS = {
11
+ :timeout => RunLoop::Environment.ci? ? 90 : 30,
12
+ :log_cmd => true
13
+ }
14
+
15
+ # @!visibility private
16
+ SIMCTL_PLIST_DIR = lambda {
17
+ dirname = File.dirname(__FILE__)
18
+ joined = File.join(dirname, '..', '..', 'plists', 'simctl')
19
+ File.expand_path(joined)
20
+ }.call
21
+
22
+ # @!visibility private
23
+ def self.uia_automation_plist
24
+ File.join(SIMCTL_PLIST_DIR, 'com.apple.UIAutomation.plist')
25
+ end
26
+
27
+ # @!visibility private
28
+ def self.uia_automation_plugin_plist
29
+ File.join(SIMCTL_PLIST_DIR, 'com.apple.UIAutomationPlugIn.plist')
30
+ end
31
+
32
+ # @!visibility private
33
+ attr_reader :device
34
+
35
+ # @!visibility private
36
+ def initialize
37
+ @ios_devices = []
38
+ @tvos_devices = []
39
+ @watchos_devices = []
40
+ end
41
+
42
+ # @!visibility private
43
+ def to_s
44
+ "#<Simctl: #{xcode.version}>"
45
+ end
46
+
47
+ # @!visibility private
48
+ def inspect
49
+ to_s
50
+ end
51
+
52
+ # @!visibility private
53
+ def simulators
54
+ simulators = ios_devices
55
+ if simulators.empty?
56
+ simulators = fetch_devices![:ios]
57
+ end
58
+ simulators
59
+ end
60
+
61
+ # @!visibility private
62
+ #
63
+ # This method is not supported on Xcode < 7 - returns nil.
64
+ #
65
+ # Simulator must be booted in El Cap, which makes this method useless for us
66
+ # because we have to do a bunch of pre-launch checks for sandbox resetting.
67
+ #
68
+ # Testing has shown that moving the device in and out of the booted state
69
+ # takes a long time (seconds) and is unpredictable.
70
+ #
71
+ # TODO ensure a booted state.
72
+ #
73
+ # @param [String] bundle_id The CFBundleIdentifier of the app.
74
+ # @param [RunLoop::Device] device The device under test.
75
+ # @return [String] The path to the .app bundle if it exists; nil otherwise.
76
+ def app_container(device, bundle_id)
77
+ return nil if !xcode.version_gte_7?
78
+ cmd = ["simctl", "get_app_container", device.udid, bundle_id]
79
+ hash = execute(cmd, DEFAULTS)
80
+
81
+ exit_status = hash[:exit_status]
82
+ if exit_status != 0
83
+ nil
84
+ else
85
+ hash[:out].strip
86
+ end
87
+ end
88
+
89
+ # @!visibility private
90
+ #
91
+ # SimControl compatibility
92
+ def ensure_accessibility(device)
93
+ sim_control.ensure_accessibility(device)
94
+ end
95
+
96
+ # @!visibility private
97
+ #
98
+ # SimControl compatibility
99
+ def ensure_software_keyboard(device)
100
+ sim_control.ensure_software_keyboard(device)
101
+ end
102
+
103
+ # @!visibility private
104
+ #
105
+ # TODO Make this private again; exposed for SimControl compatibility.
106
+ def xcode
107
+ @xcode ||= RunLoop::Xcode.new
108
+ end
109
+
110
+ private
111
+
112
+ # @!visibility private
113
+ attr_reader :ios_devices, :tvos_devices, :watchos_devices
114
+
115
+ # @!visibility private
116
+ def execute(array, options)
117
+ merged = DEFAULTS.merge(options)
118
+ xcrun.run_command_in_context(array, merged)
119
+ end
120
+
121
+ # @!visibility private
122
+ #
123
+ # Starting in Xcode 7, simctl allows a --json option for listing devices.
124
+ #
125
+ # On Xcode 6, we will fall back to SimControl which does a line-by-line
126
+ # processing of `simctl list devices`. tvOS and watchOS devices are not
127
+ # available on Xcode < 7.
128
+ #
129
+ # This is a destructive operation on `@ios_devices`, `@tvos_devices`, and
130
+ # `@watchos_devices`. Callers should check for existing devices to avoid
131
+ # the overhead of calling `simctl list devices --json`.
132
+ def fetch_devices!
133
+ if !xcode.version_gte_7?
134
+ return {
135
+ :ios => sim_control.simulators,
136
+ :tvos => [],
137
+ :watchos => []
138
+ }
139
+ end
140
+
141
+ @ios_devices = []
142
+ @tvos_devices = []
143
+ @watchos_devices = []
144
+
145
+ cmd = ["simctl", "list", "devices", "--json"]
146
+ hash = execute(cmd, DEFAULTS)
147
+
148
+ out = hash[:out]
149
+ exit_status = hash[:exit_status]
150
+ if exit_status != 0
151
+ raise RuntimeError, %Q[simctl exited #{exit_status}:
152
+
153
+ #{out}
154
+
155
+ while trying to list devices.
156
+ ]
157
+ end
158
+
159
+ devices = json_to_hash(out)["devices"]
160
+
161
+ devices.each do |key, device_list|
162
+ version = device_key_to_version(key)
163
+ bucket = bucket_for_key(key)
164
+
165
+ device_list.each do |record|
166
+ if device_available?(record)
167
+ bucket << device_from_record(record, version)
168
+ end
169
+ end
170
+ end
171
+ {
172
+ :ios => ios_devices,
173
+ :tvos => tvos_devices,
174
+ :watchos => watchos_devices
175
+ }
176
+ end
177
+
178
+ # @!visibility private
179
+ #
180
+ # command_runner_ng combines stderr and stdout and starting in Xcode 7.3,
181
+ # simctl has started generating stderr output. This must be filtered out
182
+ # so that we can parse the JSON response.
183
+ def filter_stderr(out)
184
+ out.split($-0).map do |line|
185
+ if stderr_line?(line)
186
+ nil
187
+ else
188
+ line
189
+ end
190
+ end.compact.join($-0)
191
+ end
192
+
193
+ # @!visibility private
194
+ def stderr_line?(line)
195
+ line[/CoreSimulatorService/, 0] || line[/simctl\[.+\]/, 0]
196
+ end
197
+
198
+ # @!visibility private
199
+ def json_to_hash(json)
200
+ filtered = filter_stderr(json)
201
+ begin
202
+ JSON.parse(filtered)
203
+ rescue TypeError, JSON::ParserError => e
204
+ raise RuntimeError, %Q[Could not parse simctl JSON response:
205
+
206
+ #{e}
207
+ ]
208
+ end
209
+ end
210
+
211
+ # @!visibility private
212
+ def device_key_is_ios?(key)
213
+ key[/iOS/, 0]
214
+ end
215
+
216
+ # @!visibility private
217
+ def device_key_is_tvos?(key)
218
+ key[/tvOS/, 0]
219
+ end
220
+
221
+ # @!visibility private
222
+ def device_key_is_watchos?(key)
223
+ key[/watchOS/, 0]
224
+ end
225
+
226
+ # @!visibility private
227
+ def device_key_to_version(key)
228
+ str = key.split(" ").last
229
+ RunLoop::Version.new(str)
230
+ end
231
+
232
+ # @!visibility private
233
+ def device_available?(record)
234
+ record["availability"] == "(available)"
235
+ end
236
+
237
+ # @!visibility private
238
+ def device_from_record(record, version)
239
+ RunLoop::Device.new(record["name"],
240
+ version,
241
+ record["udid"],
242
+ record["state"])
243
+ end
244
+
245
+ # @!visibility private
246
+ def bucket_for_key(key)
247
+ if device_key_is_ios?(key)
248
+ bin = @ios_devices
249
+ elsif device_key_is_tvos?(key)
250
+ bin = @tvos_devices
251
+ elsif device_key_is_watchos?(key)
252
+ bin = @watchos_devices
253
+ else
254
+ raise RuntimeError, "Unexpected key while processing simctl output:
255
+
256
+ key = #{key}
257
+
258
+ is not an iOS, tvOS, or watchOS device"
259
+ end
260
+ bin
261
+ end
262
+
263
+ # @!visibility private
264
+ def xcrun
265
+ @xcrun ||= RunLoop::Xcrun.new
266
+ end
267
+
268
+ # @!visibility private
269
+ # Support for Xcode < 7 when trying to collect simulators. Xcode 7 allows
270
+ # a --json option which is much easier to parse.
271
+ def sim_control
272
+ @sim_control ||= RunLoop::SimControl.new
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,61 @@
1
+ module RunLoop
2
+ # @!visibility private
3
+ class Sqlite
4
+
5
+ # @!visibility private
6
+ # MacOS ships with sqlite3
7
+ SQLITE3 = "/usr/bin/sqlite3"
8
+
9
+ # @!visibility private
10
+ def self.exec(file, sql)
11
+ if !File.exist?(file)
12
+ raise ArgumentError,
13
+ %Q{sqlite database must exist at path:
14
+
15
+ #{file}
16
+ }
17
+ end
18
+
19
+ if sql.nil? || sql == ""
20
+ raise ArgumentError, "Sql argument must not be nil or the empty string"
21
+ end
22
+
23
+ args = [SQLITE3, file, sql]
24
+ hash = self.xcrun.exec(args, {:log_cmd => true})
25
+
26
+ out = hash[:out]
27
+ exit_status = hash[:exit_status]
28
+
29
+ if exit_status.nil? || exit_status != 0
30
+ raise RuntimeError,
31
+ %Q{
32
+ Could not complete sqlite operation:
33
+
34
+ file: #{file}
35
+ sql: #{sql}
36
+ out: #{out}
37
+
38
+ Exited with status: '#{exit_status}'
39
+ }
40
+ end
41
+
42
+ out
43
+ end
44
+
45
+ # @!visibilty private
46
+ def self.parse(string, delimiter="|")
47
+ if string == nil
48
+ []
49
+ else
50
+ string.split(delimiter)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def self.xcrun
57
+ RunLoop::Xcrun.new
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,88 @@
1
+ module RunLoop
2
+ # @!visibility private
3
+ #
4
+ # A class for interacting with the strings tool
5
+ class Strings
6
+
7
+ # @!visibility private
8
+ attr_reader :path
9
+
10
+ # @!visibility private
11
+ def initialize(path)
12
+ @path = path
13
+
14
+ if !Strings.valid_path?(path)
15
+ raise ArgumentError,
16
+ %Q{File:
17
+
18
+ #{path}
19
+
20
+ must exist and not be a directory.
21
+ }
22
+ end
23
+ end
24
+
25
+ # @!visibility private
26
+ def to_s
27
+ "#<STRINGS: #{path}>"
28
+ end
29
+
30
+ # @!visibility private
31
+ def inspect
32
+ to_s
33
+ end
34
+
35
+ # @!visibility private
36
+ #
37
+ # @return [RunLoop::Version] A version instance or nil if the file
38
+ # at path does not contain server version information.
39
+ def server_version
40
+ regex = /CALABASH VERSION: (\d+\.\d+\.\d+(\.pre\d+)?)/
41
+ match = dump[regex, 0]
42
+
43
+ if match
44
+ str = match.split(":")[1]
45
+ RunLoop::Version.new(str)
46
+ else
47
+ nil
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ # @!visibility private
54
+ def dump
55
+ args = ["strings", path]
56
+ opts = { :log_cmd => true }
57
+
58
+ hash = xcrun.run_command_in_context(args, opts)
59
+
60
+ if hash[:exit_status] != 0
61
+ raise RuntimeError,
62
+ %Q{Could not get strings info from file:
63
+
64
+ #{path}
65
+
66
+ #{args.join(" ")}
67
+
68
+ exited #{hash[:exit_status]} with the following output:
69
+
70
+ #{hash[:out]}
71
+ }
72
+ end
73
+
74
+ @dump = hash[:out]
75
+ end
76
+
77
+ # @!visibility private
78
+ def self.valid_path?(path)
79
+ File.exist?(path) && !File.directory?(path)
80
+ end
81
+
82
+ # @!visibility private
83
+ def xcrun
84
+ RunLoop::Xcrun.new
85
+ end
86
+ end
87
+ end
88
+
Binary file
@@ -0,0 +1,240 @@
1
+ module RunLoop
2
+ # @!visibility private
3
+ class TCC
4
+
5
+ # @!visibility private
6
+ PRIVACY_SERVICES = {
7
+ :calendar => "kTCCServiceCalendar",
8
+ :camera => "kTCCServiceCamera",
9
+ :contacts => "kTCCServiceAddressBook",
10
+ :microphone => "kTCCServiceMicrophone",
11
+ :motion => "kTCCServiceMotion",
12
+ :photos => "kTCCServicePhotos",
13
+ :reminders => "kTCCServiceReminders",
14
+ :twitter => "kTCCServiceTwitter"
15
+ }
16
+
17
+ # Returns a list of known services as keys that can be passed
18
+ # to RunLoop::TCC.allow or RunLoop::TCC.deny.
19
+ def self.services
20
+ PRIVACY_SERVICES.map do |key, _|
21
+ key
22
+ end
23
+ end
24
+
25
+ # Prohibits the `device` from popping a Privacy Alert for `service`.
26
+ #
27
+ # Only works on iOS Simulator.
28
+ #
29
+ # There is a set of known services like :camera, :microphone, and :twitter,
30
+ # but you can pass arbritary services - this may or may not have an effect
31
+ # on your application.
32
+ #
33
+ # @param [String, RunLoop::Device] device
34
+ # @param [String] bundle_id
35
+ # @param [Array] services An array of services. The default is to allow
36
+ # all services.
37
+ #
38
+ # @raise [ArgumentError] If device is a physical device.
39
+ # @raise [ArgumentError] If not device with identifier can be found.
40
+ def self.allow(device, bundle_id, services = [])
41
+ _device = self.ensure_device(device)
42
+
43
+ if services.empty?
44
+ _services = self.services
45
+ else
46
+ _services = services
47
+ end
48
+
49
+ tcc = self.tcc(device, bundle_id)
50
+
51
+ _services.each do |service|
52
+ tcc.allow_service(service)
53
+ end
54
+ _services
55
+ end
56
+
57
+ # Force the `device` to pop a Privacy Alert for `service`.
58
+ #
59
+ # Only works on iOS Simulator.
60
+ #
61
+ # @param [String, RunLoop::Device] device
62
+ # @param [String] bundle_id
63
+ # @param [Array] services An array of services. The default is to deny
64
+ # all services.
65
+ #
66
+ # @raise [ArgumentError] If device is a physical device.
67
+ # @raise [ArgumentError] If not device with identifier can be found.
68
+ def self.deny(device, bundle_id, services = [])
69
+ _device = self.ensure_device(device)
70
+
71
+ if services.empty?
72
+ _services = self.services
73
+ else
74
+ _services = services
75
+ end
76
+
77
+ tcc = self.tcc(device, bundle_id)
78
+
79
+ _services.each do |service|
80
+ tcc.deny_service(service)
81
+ end
82
+ _services
83
+ end
84
+
85
+ # @!visibility private
86
+ def initialize(device, bundle_id)
87
+ @device = device
88
+ @bundle_id = bundle_id
89
+
90
+ if device.physical_device?
91
+ raise(ArgumentError, "Managing the TCC.db only works on simulators")
92
+ end
93
+
94
+ if !bundle_id.is_a?(String)
95
+ raise(ArgumentError, "Managing the TCC.db requires a valid bundle_id")
96
+ end
97
+ end
98
+
99
+ # @!visibility private
100
+ def allow_service(service)
101
+ service_name = service_name(service)
102
+ state = service_is_allowed(service_name)
103
+
104
+ return true if state == true
105
+
106
+ if state == nil
107
+ insert_allowed(service_name, 1)
108
+ else
109
+ update_allowed(service_name, 1)
110
+ end
111
+ true
112
+ end
113
+
114
+ # @!visibility private
115
+ def deny_service(service)
116
+ service_name = service_name(service)
117
+ state = service_is_allowed(service_name)
118
+
119
+ # state == false; need to update prompt_count
120
+ if state == nil
121
+ insert_allowed(service_name, 0)
122
+ else
123
+ update_allowed(service_name, 0)
124
+ end
125
+ true
126
+ end
127
+
128
+ # @!visibility private
129
+ def delete_service(service)
130
+ service_name = service_name(service)
131
+ state = service_is_allowed(service_name)
132
+
133
+ return true if state.nil?
134
+ delete_allowed(service_name)
135
+ true
136
+ end
137
+
138
+ private
139
+
140
+ # @!visibility private
141
+ attr_reader :device, :bundle_id
142
+
143
+ # @!visibility private
144
+ ACCESS_COLUMNS = [
145
+ "service",
146
+ "client",
147
+ "client_type",
148
+ "allowed",
149
+ "prompt_count"
150
+ ]
151
+
152
+ # @!visibility private
153
+ def where(service)
154
+ %Q{WHERE client="#{client}" AND service="#{service}"}
155
+ end
156
+
157
+ # @!visibility private
158
+ def service_is_allowed(service)
159
+ service_name = service_name(service)
160
+ sql = %Q{SELECT allowed FROM access #{where(service_name)}}
161
+ out = RunLoop::Sqlite.exec(db, sql)
162
+
163
+ case out
164
+ when ""
165
+ return nil
166
+ when "1"
167
+ return true
168
+ when "0"
169
+ return false
170
+ else
171
+ raise RuntimeError, %Q{Expected '', '1', or '0' found: '#{out}'"}
172
+ end
173
+ end
174
+
175
+ # @!visibility private
176
+ def access_columns
177
+ "service, client, client_type, allowed, prompt_count"
178
+ end
179
+
180
+ # @!visibility private
181
+ def access_values(service, state)
182
+ %Q{"#{service}", "#{client}", 0, #{state}, #{state}}
183
+ end
184
+
185
+ # @!visibility private
186
+ def insert_allowed(service, state)
187
+ sql = %Q{INSERT INTO access (#{access_columns}) VALUES (#{access_values(service, state)})}
188
+ RunLoop::Sqlite.exec(db, sql)
189
+ end
190
+
191
+ # @!visibility private
192
+ def update_allowed(service, state)
193
+ sql = %Q{UPDATE access SET allowed=#{state}, prompt_count=#{state} #{where(service)}}
194
+ RunLoop::Sqlite.exec(db, sql)
195
+ end
196
+
197
+ # @!visibility private
198
+ def delete_allowed(service)
199
+ sql = %Q{DELETE FROM access #{where(service)}}
200
+ RunLoop::Sqlite.exec(db, sql)
201
+ end
202
+
203
+ # @!visibility private
204
+ def service_name(key)
205
+ PRIVACY_SERVICES[key] || key
206
+ end
207
+
208
+ # @!visibility private
209
+ def client
210
+ bundle_id
211
+ end
212
+
213
+ # @!visibility private
214
+ def db
215
+ device.simulator_tcc_db
216
+ end
217
+
218
+ # @!visibility private
219
+ def self.tcc(device, bundle_id)
220
+ RunLoop::TCC.new(device, bundle_id)
221
+ end
222
+
223
+ # @!visibility private
224
+ def self.ensure_device(device)
225
+ if device.is_a?(RunLoop::Device)
226
+ simulator = device
227
+ else
228
+ simulator = RunLoop::Device.device_with_identifier(device)
229
+ end
230
+
231
+ if simulator.physical_device?
232
+ raise ArgumentError,
233
+ "Cannot manage Privacy Settings on physical devices"
234
+ end
235
+
236
+ simulator
237
+ end
238
+ end
239
+ end
240
+
@@ -0,0 +1,61 @@
1
+ require 'erb'
2
+
3
+ module RunLoop
4
+
5
+ # @!visibility private
6
+ # Class to break up javascript templates in to reusable chunks
7
+ class UIAScriptTemplate < ERB
8
+
9
+ # @!visibility private
10
+ def initialize(template_root, template_relative_path)
11
+ @template_root = template_root
12
+ template_path = File.join(@template_root, template_relative_path)
13
+ @template = File.read(template_path).force_encoding("utf-8")
14
+ super(@template)
15
+ end
16
+
17
+ # @!visibility private
18
+ def render_template(template_relative_path)
19
+ UIAScriptTemplate.new(@template_root, template_relative_path).result
20
+ end
21
+
22
+ # @!visibility private
23
+ def result
24
+ super(binding)
25
+ end
26
+
27
+ # @!visibility private
28
+ def self.sub_path_var!(javascript, results_dir)
29
+ self.substitute_variable!(javascript, "PATH", results_dir)
30
+ end
31
+
32
+ # @!visibility private
33
+ def self.sub_read_script_path_var!(javascript, read_cmd_sh)
34
+ self.substitute_variable!(javascript, "READ_SCRIPT_PATH", read_cmd_sh)
35
+ end
36
+
37
+ # @!visibility private
38
+ def self.sub_timeout_script_path_var!(javascript, timeout_sh)
39
+ self.substitute_variable!(javascript, "TIMEOUT_SCRIPT_PATH", timeout_sh)
40
+ end
41
+
42
+ # @!visibility private
43
+ def self.sub_flush_uia_logs_var!(javascript, value)
44
+ self.substitute_variable!(javascript, "FLUSH_LOGS", value)
45
+ end
46
+
47
+ # @!visibility private
48
+ #
49
+ # Legacy and XTC - related to :no_flush which is a deprecated option.
50
+ #
51
+ # Replaced with :flush_uia_logs
52
+ def self.sub_mode_var!(javascript, value)
53
+ self.substitute_variable!(javascript, "MODE", value)
54
+ end
55
+
56
+ # @!visibility private
57
+ def self.substitute_variable!(javascript, variable, value)
58
+ javascript.gsub!(/\$#{variable}/, value)
59
+ end
60
+ end
61
+ end