calabash 1.2.1 → 1.9.9.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +39 -0
  3. data/LICENSE +204 -21
  4. data/README.md +36 -6
  5. data/VERSIONING.md +16 -0
  6. data/bin/calabash +95 -0
  7. data/lib/calabash.rb +185 -1
  8. data/lib/calabash/android.rb +64 -0
  9. data/lib/calabash/android/adb.rb +277 -0
  10. data/lib/calabash/android/application.rb +110 -0
  11. data/lib/calabash/android/build.rb +12 -0
  12. data/lib/calabash/android/build/application.rb +13 -0
  13. data/lib/calabash/android/build/build_error.rb +11 -0
  14. data/lib/calabash/android/build/builder.rb +119 -0
  15. data/lib/calabash/android/build/java_keystore.rb +177 -0
  16. data/lib/calabash/android/build/resigner.rb +56 -0
  17. data/lib/calabash/android/build/test_server.rb +27 -0
  18. data/lib/calabash/android/console_helpers.rb +44 -0
  19. data/lib/calabash/android/cucumber.rb +3 -0
  20. data/lib/calabash/android/device.rb +965 -0
  21. data/lib/calabash/android/environment.rb +470 -0
  22. data/lib/calabash/android/gestures.rb +369 -0
  23. data/lib/calabash/android/interactions.rb +45 -0
  24. data/lib/calabash/android/lib/.irbrc +55 -0
  25. data/lib/calabash/android/lib/AndroidManifest.xml +51 -0
  26. data/lib/calabash/android/lib/TestServer.apk +0 -0
  27. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5 +0 -0
  28. data/lib/calabash/android/lib/calmd5/arm64-v8a/calmd5-pie +0 -0
  29. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5 +0 -0
  30. data/lib/calabash/android/lib/calmd5/armeabi-v7a/calmd5-pie +0 -0
  31. data/lib/calabash/android/lib/calmd5/armeabi/calmd5 +0 -0
  32. data/lib/calabash/android/lib/calmd5/armeabi/calmd5-pie +0 -0
  33. data/lib/calabash/android/lib/calmd5/mips/calmd5 +0 -0
  34. data/lib/calabash/android/lib/calmd5/mips/calmd5-pie +0 -0
  35. data/lib/calabash/android/lib/calmd5/mips64/calmd5 +0 -0
  36. data/lib/calabash/android/lib/calmd5/mips64/calmd5-pie +0 -0
  37. data/lib/calabash/android/lib/calmd5/x86/calmd5 +0 -0
  38. data/lib/calabash/android/lib/calmd5/x86/calmd5-pie +0 -0
  39. data/lib/calabash/android/lib/calmd5/x86_64/calmd5 +0 -0
  40. data/lib/calabash/android/lib/calmd5/x86_64/calmd5-pie +0 -0
  41. data/lib/calabash/android/lib/screenshot_taker.jar +0 -0
  42. data/lib/calabash/android/life_cycle.rb +37 -0
  43. data/lib/calabash/android/orientation.rb +30 -0
  44. data/lib/calabash/android/physical_buttons.rb +39 -0
  45. data/lib/calabash/android/screenshot.rb +9 -0
  46. data/lib/calabash/android/scroll.rb +5 -0
  47. data/lib/calabash/android/server.rb +10 -0
  48. data/lib/calabash/android/text.rb +54 -0
  49. data/lib/calabash/application.rb +74 -0
  50. data/lib/calabash/cli.rb +12 -0
  51. data/lib/calabash/cli/build.rb +33 -0
  52. data/lib/calabash/cli/console.rb +90 -0
  53. data/lib/calabash/cli/generate.rb +110 -0
  54. data/lib/calabash/cli/helpers.rb +130 -0
  55. data/lib/calabash/cli/resign.rb +33 -0
  56. data/lib/calabash/cli/run.rb +99 -0
  57. data/lib/calabash/cli/setup_keystore.rb +39 -0
  58. data/lib/calabash/color.rb +32 -0
  59. data/lib/calabash/console_helpers.rb +90 -0
  60. data/lib/calabash/defaults.rb +56 -0
  61. data/lib/calabash/device.rb +401 -0
  62. data/lib/calabash/environment.rb +75 -0
  63. data/lib/calabash/gestures.rb +384 -0
  64. data/lib/calabash/http.rb +8 -0
  65. data/lib/calabash/http/error.rb +15 -0
  66. data/lib/calabash/http/request.rb +42 -0
  67. data/lib/calabash/http/retriable_client.rb +156 -0
  68. data/lib/calabash/interactions.rb +105 -0
  69. data/lib/calabash/ios.rb +37 -0
  70. data/lib/calabash/ios/application.rb +119 -0
  71. data/lib/calabash/ios/conditions.rb +79 -0
  72. data/lib/calabash/ios/console_helpers.rb +72 -0
  73. data/lib/calabash/ios/device.rb +24 -0
  74. data/lib/calabash/ios/device/device_implementation.rb +779 -0
  75. data/lib/calabash/ios/device/gestures_mixin.rb +167 -0
  76. data/lib/calabash/ios/device/keyboard_mixin.rb +133 -0
  77. data/lib/calabash/ios/device/physical_device_mixin.rb +266 -0
  78. data/lib/calabash/ios/device/rotation_mixin.rb +124 -0
  79. data/lib/calabash/ios/device/routes/backdoor_route_mixin.rb +86 -0
  80. data/lib/calabash/ios/device/routes/condition_route_mixin.rb +62 -0
  81. data/lib/calabash/ios/device/routes/error.rb +8 -0
  82. data/lib/calabash/ios/device/routes/handle_route_mixin.rb +102 -0
  83. data/lib/calabash/ios/device/routes/map_route_mixin.rb +38 -0
  84. data/lib/calabash/ios/device/routes/playback_route_mixin.rb +70 -0
  85. data/lib/calabash/ios/device/routes/response_parser.rb +48 -0
  86. data/lib/calabash/ios/device/routes/uia_route_mixin.rb +238 -0
  87. data/lib/calabash/ios/device/runtime_attributes.rb +184 -0
  88. data/lib/calabash/ios/device/status_bar_mixin.rb +17 -0
  89. data/lib/calabash/ios/device/text_mixin.rb +19 -0
  90. data/lib/calabash/ios/device/uia_keyboard_mixin.rb +188 -0
  91. data/lib/calabash/ios/device/uia_mixin.rb +12 -0
  92. data/lib/calabash/ios/environment.rb +41 -0
  93. data/lib/calabash/ios/interactions.rb +10 -0
  94. data/lib/calabash/ios/lib/.irbrc +55 -0
  95. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_ipad.base64 +2 -0
  96. data/lib/calabash/ios/lib/recordings/rotate_left_home_down_iphone.base64 +2 -0
  97. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_ipad.base64 +2 -0
  98. data/lib/calabash/ios/lib/recordings/rotate_left_home_left_iphone.base64 +2 -0
  99. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_ipad.base64 +2 -0
  100. data/lib/calabash/ios/lib/recordings/rotate_left_home_right_iphone.base64 +2 -0
  101. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_ipad.base64 +2 -0
  102. data/lib/calabash/ios/lib/recordings/rotate_left_home_up_iphone.base64 +2 -0
  103. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_ipad.base64 +2 -0
  104. data/lib/calabash/ios/lib/recordings/rotate_right_home_down_iphone.base64 +2 -0
  105. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_ipad.base64 +2 -0
  106. data/lib/calabash/ios/lib/recordings/rotate_right_home_left_iphone.base64 +2 -0
  107. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_ipad.base64 +2 -0
  108. data/lib/calabash/ios/lib/recordings/rotate_right_home_right_iphone.base64 +2 -0
  109. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_ipad.base64 +2 -0
  110. data/lib/calabash/ios/lib/recordings/rotate_right_home_up_iphone.base64 +2 -0
  111. data/lib/calabash/ios/orientation.rb +117 -0
  112. data/lib/calabash/ios/scroll.rb +504 -0
  113. data/lib/calabash/ios/server.rb +73 -0
  114. data/lib/calabash/ios/text.rb +248 -0
  115. data/lib/calabash/ios/uia.rb +24 -0
  116. data/lib/calabash/lib/skeleton/config/cucumber.yml +6 -0
  117. data/lib/calabash/lib/skeleton/features/sample.feature +5 -0
  118. data/lib/calabash/lib/skeleton/features/step_definitions/calabash_steps.rb +29 -0
  119. data/lib/calabash/lib/skeleton/features/support/env.rb +54 -0
  120. data/lib/calabash/lib/skeleton/features/support/hooks.rb +83 -0
  121. data/lib/calabash/life_cycle.rb +111 -0
  122. data/lib/calabash/location.rb +51 -0
  123. data/lib/calabash/logger.rb +87 -0
  124. data/lib/calabash/orientation.rb +84 -0
  125. data/lib/calabash/page.rb +35 -0
  126. data/lib/calabash/patch.rb +14 -0
  127. data/lib/calabash/patch/array.rb +16 -0
  128. data/lib/calabash/patch/run_loop.rb +90 -0
  129. data/lib/calabash/query.rb +160 -0
  130. data/lib/calabash/query_result.rb +85 -0
  131. data/lib/calabash/screenshot.rb +89 -0
  132. data/lib/calabash/server.rb +16 -0
  133. data/lib/calabash/text.rb +76 -0
  134. data/lib/calabash/utility.rb +58 -0
  135. data/lib/calabash/version.rb +3 -1
  136. data/lib/calabash/wait.rb +474 -0
  137. metadata +462 -24
@@ -0,0 +1,8 @@
1
+ module Calabash
2
+ # @!visibility private
3
+ module HTTP
4
+ require 'calabash/http/retriable_client'
5
+ require 'calabash/http/request'
6
+ require 'calabash/http/error'
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ module Calabash
2
+ module HTTP
3
+
4
+ # Raised when there is a problem communicating with the Calabash test
5
+ # server.
6
+ class Error < StandardError
7
+
8
+ end
9
+
10
+ # Raised when there is a problem creating an HTTP request.
11
+ class RequestError < StandardError
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ module Calabash
2
+ module HTTP
3
+
4
+ # A representation of an HTTP request that can be passed passed to the HTTP
5
+ # client as an argument for `get` or `post`.
6
+ class Request
7
+ attr_reader :route, :params
8
+
9
+ def initialize(route, params={})
10
+ @route = route
11
+ @params = params
12
+ end
13
+
14
+ # Create a new Request from `route` and `parameters`.
15
+ #
16
+ # @param [String] route The http route for the new request.
17
+ # @param [Array, Hash] parameters An Array or Hash of parameters.
18
+ # @return [Request] A new Request for `route` with `parameters`.
19
+ # @raise [RequestError] Raises an error if the parameters cannot be
20
+ # converted to JSON
21
+ def self.request(route, parameters)
22
+ Request.new(route, Request.data(parameters))
23
+ end
24
+
25
+ private
26
+
27
+ # Converts `parameters` to JSON.
28
+ #
29
+ # @param [Array, Hash] parameters An Array or Hash of parameters.
30
+ # @return [String] A JSON formatted string that represents the parameters.
31
+ # @raise [RequestError] Raises an error if the parameters cannot be
32
+ # converted to JSON
33
+ def self.data(parameters)
34
+ begin
35
+ JSON.generate(parameters)
36
+ rescue *[TypeError, JSON::GeneratorError] => e
37
+ raise RequestError, "#{e}: could not generate JSON from '#{parameters}'"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,156 @@
1
+ require 'httpclient'
2
+
3
+ module Calabash
4
+ module HTTP
5
+
6
+ # An HTTP client that retries its connection on errors and can time out.
7
+ class RetriableClient
8
+ attr_reader :client
9
+
10
+ # @!visibility private
11
+ RETRY_ON =
12
+ [
13
+ # The connection, request, or response timed out
14
+ #HTTPClient::TimeoutError,
15
+ # The proxy could not connect to the server (Android)
16
+ # or the server is not running (iOS)
17
+ HTTPClient::KeepAliveDisconnected,
18
+ # No proxy has been set up (Android)
19
+ Errno::ECONNREFUSED,
20
+ # The server sent a partial response
21
+ #Errno::ECONNRESET,
22
+ # Client sent TCP reset (RST) before server has accepted the
23
+ # connection requested by client.
24
+ Errno::ECONNABORTED,
25
+ # The foreign function call call timed out
26
+ #Errno::ETIMEDOUT
27
+ ]
28
+
29
+ # @!visibility private
30
+ HEADER =
31
+ {
32
+ 'Content-Type' => 'application/json;charset=utf-8'
33
+ }
34
+
35
+ # Creates a new retriable client.
36
+ #
37
+ # This initializer takes multiple options. If the option is not
38
+ # documented, it should be considered _private_. You use undocumented
39
+ # options at your own risk.
40
+ #
41
+ # @param [Calabash::Server] server The server to make the HTTP request
42
+ # on.
43
+ # @param [Hash] options Control the retry, timeout, and interval.
44
+ # @option options [Number] :retries (5) How often to retry.
45
+ # @option options [Number] :timeout (5) How long to wait for a response
46
+ # before timing out.
47
+ # @option options [Number] :interval (0.5) How long to sleep between
48
+ # retries.
49
+ def initialize(server, options = {})
50
+ @client = options[:client] || ::HTTPClient.new
51
+ @server = server
52
+ @retries = options.fetch(:retries, 5)
53
+ @timeout = options.fetch(:timeout, 5)
54
+ @interval = options.fetch(:interval, 0.5)
55
+ @logger = options[:logger] || Calabash::Logger.new
56
+ @on_error = {}
57
+ end
58
+
59
+ def on_error(type, &block)
60
+ @on_error[type] = block
61
+ end
62
+
63
+ def change_server(new_server)
64
+ @server = new_server
65
+ end
66
+
67
+ # Make an HTTP get request.
68
+ #
69
+ # This method takes multiple options. If the option is not documented,
70
+ # it should be considered _private_. You use undocumented options at
71
+ # your own risk.
72
+ #
73
+ # @param [Calabash::HTTP::Request] request The request.
74
+ # @param [Hash] options Control the retry, timeout, and interval.
75
+ # @option options [Number] :retries (5) How often to retry.
76
+ # @option options [Number] :timeout (5) How long to wait for a response
77
+ # before timing out.
78
+ # @option options [Number] :interval (0.5) How long to sleep between
79
+ # retries.
80
+ def get(request, options={})
81
+ request(request, :get, options)
82
+ end
83
+
84
+ # Make an HTTP post request.
85
+ #
86
+ # This method takes multiple options. If the option is not documented,
87
+ # it should be considered _private_. You use undocumented options at
88
+ # your own risk.
89
+ #
90
+ # @param [Calabash::HTTP::Request] request The request.
91
+ # @param [Hash] options Control the retry, timeout, and interval.
92
+ # @option options [Number] :retries (5) How often to retry.
93
+ # @option options [Number] :timeout (5) How long to wait for a response
94
+ # before timing out.
95
+ # @option options [Number] :interval (0.5) How long to sleep between
96
+ # retries.
97
+ def post(request, options={})
98
+ request(request, :post, options)
99
+ end
100
+
101
+ private
102
+
103
+ def request(request, request_method, options={})
104
+ retries = options.fetch(:retries, @retries)
105
+ timeout = options.fetch(:timeout, @timeout)
106
+ interval = options.fetch(:interval, @interval)
107
+ header = options.fetch(:header, HEADER)
108
+
109
+ @logger.log "Getting: #{@server.endpoint + request.route}"
110
+
111
+ start_time = Time.now
112
+ last_error = nil
113
+
114
+ client = @client.dup
115
+ client.receive_timeout = timeout
116
+
117
+ retries.times do |i|
118
+ first_try = i == 0
119
+
120
+ # Subtract the aggregate time we've spent thus far to make sure we're
121
+ # not exceeding the request timeout across retries.
122
+ time_diff = start_time + timeout - Time.now
123
+
124
+ if time_diff <= 0
125
+ raise HTTP::Error, 'Timeout exceeded'
126
+ end
127
+
128
+ client.receive_timeout = [time_diff, client.receive_timeout].min
129
+
130
+ begin
131
+ return client.send(request_method, @server.endpoint + request.route,
132
+ request.params, header)
133
+ rescue *RETRY_ON => e
134
+ @logger.log "Http error: #{e}"
135
+
136
+ if first_try
137
+ if @on_error[e.class]
138
+ @on_error[e.class].call(@server)
139
+ end
140
+ end
141
+
142
+ last_error = e
143
+ sleep interval
144
+ end
145
+ end
146
+
147
+ # We should raise helpful messages
148
+ if last_error.is_a?(HTTPClient::KeepAliveDisconnected)
149
+ raise HTTP::Error, "#{last_error}: It is likely your application has crashed"
150
+ end
151
+
152
+ raise HTTP::Error, last_error
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,105 @@
1
+ module Calabash
2
+ module Interactions
3
+ # @todo Needs docs!
4
+ def query(query, *args)
5
+ Calabash::Device.default.map_route(Query.new(query), :query, *args)
6
+ end
7
+
8
+ # @todo Needs docs!
9
+ def flash(query)
10
+ Calabash::Device.default.map_route(Query.new(query), :flash)
11
+ end
12
+
13
+ # Evaluate javascript in a Web View. On iOS, an implicit return is
14
+ # inserted, on Android an explicit return is needed.
15
+ #
16
+ # @example
17
+ # # iOS
18
+ # evaluate_javascript_in("UIWebView", "2+2")
19
+ # # Android
20
+ # evaluate_javascript_in("WebView", "return 2+2"
21
+ #
22
+ # @example
23
+ # # iOS
24
+ # evaluate_javascript_in("WKWebView",
25
+ # "document.body.style.backgroundColor = 'red';")
26
+ #
27
+ # # Android
28
+ # evaluate_javascript_in("XWalkContent",
29
+ # "document.body.style.backgroundColor = 'red';")
30
+ #
31
+ # @note No error will be raised if the javascript given is invalid, or
32
+ # throws an exception.
33
+ #
34
+ # @param [String, Hash, Calabash::Query] query Query that matches the view
35
+ # @param [String] javascript The javascript to evaluate
36
+ #
37
+ # @raise ViewNotFoundError If no views are found matching `query`
38
+ def evaluate_javascript_in(query, javascript)
39
+ wait_for_view(query,
40
+ timeout: Calabash::Gestures::DEFAULT_GESTURE_WAIT_TIMEOUT)
41
+
42
+ _evaluate_javascript_in(query, javascript)
43
+ end
44
+
45
+ # Invoke a method in your application.
46
+ #
47
+ # This is an escape hatch for calling an arbitrary hook inside
48
+ # (the test build) of your app. Commonly used to "go around" the UI for
49
+ # speed purposes or reset the app to a good known state.
50
+ #
51
+ # For iOS this method calls a method on the app's AppDelegate object.
52
+ #
53
+ # For Android this method tries to invoke a method on the current Activity
54
+ # instance. If the method is not defined in the current activity, Calabash
55
+ # tries to invoke the method on the current Application instance.
56
+ #
57
+ # @note The Android implementation accepts any number of arguments, of any
58
+ # type including null (Ruby nil). The iOS implementation does not accept
59
+ # more than one argument, of the type NSString (Ruby String) or
60
+ # NSDictionary (Ruby Hash).
61
+ #
62
+ #
63
+ # ### For iOS
64
+ #
65
+ # You must create a method on you app delegate of the form:
66
+ #
67
+ # - (NSString *) calabashBackdoor:(NSString *)aIgnorable;
68
+ #
69
+ # or if you want to pass parameters
70
+ #
71
+ # - (NSString *) calabashBackdoor:(NSDictionary *)params;
72
+ #
73
+ # ### For Android
74
+ #
75
+ # You must create a public method in your current Activity or Application.
76
+ #
77
+ # public <return type> calabashBackdoor(String param1, int param2)
78
+ #
79
+ # @example
80
+ # # iOS
81
+ # backdoor('calabashBackdoor:'', '')
82
+ #
83
+ # @example
84
+ # # iOS
85
+ # backdoor('calabashBackdoor:', {example:'param'})
86
+ #
87
+ # @example
88
+ # # Android
89
+ # backdoor('calabashBackdoor', 'first argument', 2)
90
+ #
91
+ # @param [String] name The selector/method name.
92
+ # @param [Object] *arguments A comma separated list of arguments to be
93
+ # passed to the backdoor selector/method.
94
+ # @return [Object] the result of performing the selector/method with the
95
+ # arguments (serialized)
96
+ def backdoor(name, *arguments)
97
+ Device.default.backdoor(name, *arguments)
98
+ end
99
+
100
+ # @!visibility private
101
+ def _evaluate_javascript_in(query, javascript)
102
+ abstract_method!
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,37 @@
1
+ module Calabash
2
+ # Contains the iOS implementations of the Calabash APIs.
3
+ module IOS
4
+ require 'calabash'
5
+ include Calabash
6
+
7
+ # @!visibility private
8
+ def self.extended(base)
9
+ Calabash.send(:extended, base)
10
+ end
11
+
12
+ # @!visibility private
13
+ def self.included(base)
14
+ Calabash.send(:included, base)
15
+ end
16
+
17
+ require 'calabash/ios/environment'
18
+ require 'calabash/ios/application'
19
+ require 'calabash/ios/device'
20
+ require 'calabash/ios/conditions'
21
+ require 'calabash/ios/interactions'
22
+ require 'calabash/ios/orientation'
23
+ require 'calabash/ios/server'
24
+ require 'calabash/ios/text'
25
+ require 'calabash/ios/console_helpers'
26
+ require 'calabash/ios/uia'
27
+ require 'calabash/ios/scroll'
28
+
29
+ include Calabash::IOS::Conditions
30
+ include Calabash::IOS::Orientation
31
+ include Calabash::IOS::Interactions
32
+ include Calabash::IOS::Text
33
+ include Calabash::IOS::UIA
34
+ include Calabash::IOS::Scroll
35
+
36
+ end
37
+ end
@@ -0,0 +1,119 @@
1
+ module Calabash
2
+ module IOS
3
+
4
+ # A class to represent an iOS application. An application can be a
5
+ # simulator bundle (.app) or a device binary (.ipa).
6
+ class Application < Calabash::Application
7
+
8
+ # The path to the application under test deduced by analysing the
9
+ # environment.
10
+ #
11
+ # You can control the default application path by setting the `CAL_APP`
12
+ # environment variable. This is the best way of ensuring Calabash
13
+ # can find your application.
14
+ #
15
+ # @todo We have a chicken and egg problem. If the device under test
16
+ # is a simulator, we have been analyzing the Xcode or Xamarin Studio
17
+ # project for the likely location of the .app. I think we still want
18
+ # to do this. The problem is that Xcode buries the .app in a
19
+ # DerivedData directory deep in the user's ~/Library/ and the correct
20
+ # directory path is very difficult to find. I overcome this problem
21
+ # with command-line build scripts that put the .app (or .ipa) in a
22
+ # directory local to my project. Others devs use Xcode Custom Build
23
+ # locations. I don't think we we want to branch here on whether or not
24
+ # the DEVICE_ID points to a simulator or physical device. This is
25
+ # wicked expensive.
26
+ def self.default_from_environment
27
+ application_path = Environment::APP_PATH
28
+
29
+ if application_path.nil?
30
+ raise 'No application path is set'
31
+ end
32
+
33
+ Application.new(application_path)
34
+ end
35
+
36
+ # Create a new Application.
37
+ #
38
+ # @param [String] application_path The path to the ipa or app.
39
+ # @param [Hash] options Optional arguments.
40
+ # @option options [Calabash::Logger] :logger An optional logger. It is
41
+ # not recommended that you set this yourself.
42
+ # @return [Calabash::IOS::Application] A new application.
43
+ # @raise [RuntimeError] If the `application_path` does not indicate a
44
+ # file that exists.
45
+ # @raise [RuntimeError] If the `application_path` does not end with .ipa
46
+ # or .app.
47
+ def initialize(application_path, options = {})
48
+ super(application_path, options)
49
+
50
+ @simulator_bundle = File.extname(path) == '.app'
51
+ @device_binary = File.extname(path) == '.ipa'
52
+
53
+ unless @simulator_bundle || @device_binary
54
+ raise "Expected #{path} to be an .ipa or .app, but found '#{File.extname(path)}'"
55
+ end
56
+ end
57
+
58
+ # Return true if this application is for an iOS Simulator.
59
+ # @return [Boolean] Is this a .app?
60
+ def simulator_bundle?
61
+ @simulator_bundle
62
+ end
63
+
64
+ # Return true if this application is for a physical iOS device.
65
+ # @return [Boolean] Is this a .ipa?
66
+ def device_binary?
67
+ @device_binary
68
+ end
69
+
70
+ # Returns the sha1 of the directory or binary of this app's path.
71
+ # @return [String] A checksum.
72
+ def sha1
73
+ RunLoop::Directory.directory_digest(path)
74
+ end
75
+
76
+ # Does this app have the same checksum as another app?
77
+ # @param [Calabash::IOS::Application] other The other app to compare to.
78
+ # @return [Boolean] Is the checksum the same for the two apps?
79
+ def same_sha1_as?(other)
80
+ sha1 == other.sha1
81
+ end
82
+
83
+ private
84
+
85
+ # @!visibility private
86
+ def run_loop_ipa
87
+ @run_loop_ipa ||= lambda do
88
+ if device_binary?
89
+ RunLoop::Ipa.new(path)
90
+ else
91
+ nil
92
+ end
93
+ end.call
94
+ end
95
+
96
+ # @!visibility private
97
+ def run_loop_app
98
+ @run_loop_app ||= lambda do
99
+ if simulator_bundle?
100
+ RunLoop::App.new(path)
101
+ else
102
+ nil
103
+ end
104
+ end.call
105
+ end
106
+
107
+ # @!visibility private
108
+ def extract_identifier
109
+ if simulator_bundle?
110
+ run_loop_app.bundle_identifier
111
+ elsif device_binary?
112
+ run_loop_ipa.bundle_identifier
113
+ else
114
+ raise "Unknown app type '#{File.extname(path)}', cannot extract bundle identifier"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end