calabash 1.2.1 → 1.9.9.pre1

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.
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