calabash-cucumber 0.16.4 → 0.17.0

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/bin/calabash-ios-generate.rb +61 -10
  3. data/dylibs/libCalabashDyn.dylib +0 -0
  4. data/dylibs/libCalabashDynSim.dylib +0 -0
  5. data/features-skeleton/sample.feature +7 -0
  6. data/features-skeleton/steps/sample_steps.rb +45 -0
  7. data/features-skeleton/support/01_launch.rb +31 -33
  8. data/features-skeleton/support/dry_run.rb +2 -0
  9. data/features-skeleton/support/env.rb +1 -0
  10. data/features-skeleton/support/patches/cucumber.rb +15 -0
  11. data/lib/calabash-cucumber.rb +4 -0
  12. data/lib/calabash-cucumber/actions/instruments_actions.rb +0 -5
  13. data/lib/calabash-cucumber/actions/playback_actions.rb +1 -6
  14. data/lib/calabash-cucumber/connection_helpers.rb +50 -1
  15. data/lib/calabash-cucumber/core.rb +94 -72
  16. data/lib/calabash-cucumber/dot_dir.rb +18 -0
  17. data/lib/calabash-cucumber/launch/simulator_launcher.rb +35 -3
  18. data/lib/calabash-cucumber/launcher.rb +46 -99
  19. data/lib/calabash-cucumber/logging.rb +79 -0
  20. data/lib/calabash-cucumber/playback_helpers.rb +2 -2
  21. data/lib/calabash-cucumber/store/preferences.rb +223 -0
  22. data/lib/calabash-cucumber/uia.rb +0 -43
  23. data/lib/calabash-cucumber/usage_tracker.rb +192 -0
  24. data/lib/calabash-cucumber/version.rb +2 -2
  25. data/lib/calabash-cucumber/wait_helpers.rb +32 -0
  26. data/scripts/.irbrc +19 -4
  27. data/staticlib/calabash.framework.zip +0 -0
  28. data/staticlib/libFrankCalabash.a +0 -0
  29. metadata +31 -19
  30. data/features-skeleton/my_first.feature +0 -12
  31. data/features-skeleton/step_definitions/calabash_steps.rb +0 -1
  32. data/features-skeleton/step_definitions/my_first_steps.rb +0 -4
  33. data/features-skeleton/support/02_pre_stop_hooks.rb +0 -0
@@ -0,0 +1,18 @@
1
+ module Calabash
2
+ module Cucumber
3
+ # A module for managing the ~/.calabash directory.
4
+ module DotDir
5
+ require "run_loop"
6
+
7
+ def self.directory
8
+ home = RunLoop::Environment.user_home_directory
9
+ dir = File.join(home, ".calabash")
10
+ if !File.exist?(dir)
11
+ FileUtils.mkdir_p(dir)
12
+ end
13
+ dir
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -34,6 +34,10 @@ module Calabash
34
34
  # The file path to the default Xcode DerivedData directory.
35
35
  DERIVED_DATA = File.expand_path('~/Library/Developer/Xcode/DerivedData')
36
36
 
37
+ # @!visibility private]
38
+ # The file path to the default Xcode preferences plist.
39
+ XCODE_PREFS = File.expand_path('~/Library/Preferences/com.apple.dt.Xcode.plist')
40
+
37
41
  # @!visibility private
38
42
  # REGEX for finding application Info.plist.
39
43
  DEFAULT_DERIVED_DATA_INFO = File.expand_path("#{DERIVED_DATA}/*/info.plist")
@@ -161,6 +165,33 @@ module Calabash
161
165
  end
162
166
  end
163
167
 
168
+ # @!visibility private
169
+ # Returns the absolute build path to the project directory.
170
+ #
171
+ # @return [String] absolute path to the projects build directory
172
+ def build_output_dir_for_project
173
+ xcode_temp_prefs = File.join(project_dir, '.cal_xcode_prefs')
174
+ FileUtils.cp(XCODE_PREFS, xcode_temp_prefs)
175
+ `plutil -convert xml1 "#{xcode_temp_prefs}"`
176
+
177
+ plist = CFPropertyList::List.new(:file => xcode_temp_prefs)
178
+ hash = CFPropertyList.native_types(plist.value)
179
+
180
+ if hash.has_key?('IDESharedBuildFolderName')
181
+ build_folder_name = hash['IDESharedBuildFolderName']
182
+ output_dir = "#{DERIVED_DATA}/#{build_folder_name}/Products"
183
+ elsif hash.has_key?('IDECustomBuildProductsPath')
184
+ products_path = hash['IDECustomBuildProductsPath']
185
+ File.join(project_dir, products_path)
186
+ else
187
+ output_dir = derived_data_dir_for_project
188
+ end
189
+
190
+ FileUtils.rm(xcode_temp_prefs)
191
+
192
+ output_dir
193
+ end
194
+
164
195
  # @!visibility private
165
196
  # Returns the absolute path to the project directory.
166
197
  #
@@ -220,12 +251,13 @@ module Calabash
220
251
  puts('-'*37)
221
252
  end
222
253
  else
223
- dd_dir = derived_data_dir_for_project
224
- sim_dirs = Dir.glob(File.join(dd_dir, 'Build', 'Products', '*-iphonesimulator', '*.app'))
254
+ bo_dir = build_output_dir_for_project
255
+ sim_dirs = Dir.glob(File.join(bo_dir, '*-iphonesimulator', '*.app'))
256
+
225
257
  if sim_dirs.empty?
226
258
  msg = ['Unable to auto detect APP_BUNDLE_PATH.']
227
259
  msg << 'Have you built your app for simulator?'
228
- msg << "Searched dir: #{dd_dir}/Build/Products"
260
+ msg << "Searched dir: #{bo_dir}"
229
261
  msg << 'Please build your app from Xcode'
230
262
  msg << 'You should build the -cal target.'
231
263
  msg << ''
@@ -8,6 +8,7 @@ require 'run_loop'
8
8
  require 'cfpropertylist'
9
9
  require 'calabash-cucumber/utils/logging'
10
10
  require 'calabash/dylibs'
11
+ require "calabash-cucumber/usage_tracker"
11
12
 
12
13
  # Used to launch apps for testing in iOS Simulator or on iOS Devices. By default
13
14
  # it uses Apple's `instruments` process to launch your app, but has legacy support
@@ -56,6 +57,7 @@ class Calabash::Cucumber::Launcher
56
57
  attr_accessor :launch_args
57
58
  attr_accessor :simulator_launcher
58
59
  attr_reader :xcode
60
+ attr_reader :usage_tracker
59
61
 
60
62
  # @!visibility private
61
63
  # Generated when calabash cannot launch the app.
@@ -81,6 +83,10 @@ class Calabash::Cucumber::Launcher
81
83
  @xcode ||= RunLoop::Xcode.new
82
84
  end
83
85
 
86
+ def usage_tracker
87
+ @usage_tracker ||= Calabash::Cucumber::UsageTracker.new
88
+ end
89
+
84
90
  # @!visibility private
85
91
  def initialize
86
92
  @simulator_launcher = Calabash::Cucumber::SimulatorLauncher.new
@@ -147,12 +153,15 @@ class Calabash::Cucumber::Launcher
147
153
  self.run_loop = run_loop
148
154
  major = self.device.ios_major_version
149
155
  if major.to_i >= 7 && self.actions.is_a?(Calabash::Cucumber::PlaybackActions)
150
- puts "\n\n WARNING \n\n"
151
- puts 'Warning Trying to connect to simulator that was not launched by Calabash/instruments.'
152
- puts 'To fix this you must let Calabash or instruments launch the app.'
153
- puts 'Query will work, but gestures will not.'
154
- puts "\n\n WARNING \n\n"
155
- puts 'Please read: https://github.com/calabash/calabash-ios/wiki/A0-UIAutomation---instruments-problems'
156
+ puts %Q{
157
+
158
+ WARNING
159
+
160
+ Connected to simulator that was not launched by Calabash.
161
+
162
+ Queries will work, but gestures will not.
163
+
164
+ }
156
165
  end
157
166
  self
158
167
  end
@@ -267,56 +276,24 @@ class Calabash::Cucumber::Launcher
267
276
  # `:all` is passed, then the sandboxes for all sdks will be deleted.
268
277
  # @option opts [String] :path (nil) path to the application bundle
269
278
  def reset_app_sandbox(opts={})
279
+ calabash_warn(%Q{
280
+ Starting in Calabash 0.17.0, this method does nothing.
270
281
 
271
- if device_target?
272
- calabash_warn("calling 'reset_app_sandbox' when targeting a device.")
273
- return
274
- end
275
-
276
- default_opts = {:sdk => nil, :path => nil}
277
- merged_opts = default_opts.merge opts
282
+ You can still control whether or not your app's sandbox is
283
+ reset between Scenarios using RESET_BETWEEN_SCENARIOS=1 or
284
+ by passing :reset => true as a launch option.
278
285
 
279
- sim_control = opts.fetch(:sim_control, RunLoop::SimControl.new)
280
- xcode = sim_control.xcode
286
+ options = {
287
+ :reset => true
288
+ }
281
289
 
282
- if sim_control.xcode_version_gte_6?
283
- default_sim = RunLoop::Core.default_simulator(xcode)
284
- name_or_udid = merged_opts[:udid] || ENV['DEVICE_TARGET'] || default_sim
290
+ launcher.relaunch(options)
285
291
 
286
- target_simulator = sim_control.simulators.find do |sim|
287
- [name_or_udid == sim.instruments_identifier(xcode),
288
- name_or_udid == sim.udid,
289
- name_or_udid == sim.name].any?
290
- end
292
+ Please do not ignore this message.
291
293
 
292
- if target_simulator.nil?
293
- raise "Could not find a simulator that matches '#{name_or_udid}'"
294
- end
295
-
296
- sim_control.reset_sim_content_and_settings({:sim_udid => target_simulator.udid})
297
- else
298
- sdk ||= merged_opts[:sdk] || sdk_version || self.simulator_launcher.sdk_detector.latest_sdk_version
299
- path ||= merged_opts[:path] || self.simulator_launcher.app_bundle_or_raise(app_path)
294
+ Remove direct calls to reset_app_sandbox.
300
295
 
301
- app = File.basename(path)
302
-
303
- directories_for_sdk_prefix(sdk).each do |sdk_dir|
304
- app_dir = File.expand_path("#{sdk_dir}/Applications")
305
- next unless File.exists?(app_dir)
306
-
307
- bundle = `find "#{app_dir}" -type d -depth 2 -name "#{app}" | head -n 1`
308
-
309
- next if bundle.empty? # Assuming we're already clean
310
-
311
- if debug_logging?
312
- puts "Reset app state for #{bundle}"
313
- end
314
- sandbox = File.dirname(bundle)
315
- ['Library', 'Documents', 'tmp'].each do |content_dir|
316
- FileUtils.rm_rf(File.join(sandbox, content_dir))
317
- end
318
- end
319
- end
296
+ })
320
297
  end
321
298
 
322
299
  # Erases the contents and setting for every available simulator.
@@ -503,36 +480,27 @@ class Calabash::Cucumber::Launcher
503
480
  end
504
481
  end
505
482
 
506
- # Launches your app on the connected device or simulator. Stops the app if it is already running.
507
- # `relaunch` does a lot of error detection and handling to reliably start the app and test. Instruments (particularly the cli)
508
- # has stability issues which we workaround by restarting the simulator process and checking that UIAutomation is correctly
509
- # attaching.
483
+ # Launches your app on the connected device or simulator.
510
484
  #
511
- # Takes optional args to specify details of the launch (e.g. device or simulator, sdk version, target device, launch method...).
512
- # @note an important part of relaunch behavior is controlled by environment variables, specified below
485
+ # `relaunch` does a lot of error detection and handling to reliably start the
486
+ # app and test. Instruments (particularly the cli) has stability issues which
487
+ # we workaround by restarting the simulator process and checking that
488
+ # UIAutomation is correctly attaching to your application.
513
489
  #
514
- # The two most important environment variables are `DEVICE_TARGET` and `APP_BUNDLE_PATH`.
490
+ # Use the `args` parameter to to control:
515
491
  #
516
- # - `DEVICE_TARGET` controls which device you're running on. To see the options run: `instruments -s devices`.
517
- # In addition you can specify `DEVICE_TARGET=device` to run on a (unique) usb-connected device.
518
- # - `APP_BUNDLE_PATH` controls which `.app` bundle to launch in simulator (don't use for on-device testing, instead use `BUNDLE_ID`).
519
- # - `BUNDLE_ID` used with `DEVICE_TARGET=device` to specify which app to launch on device
520
- # - `DEBUG` - set to "1" to obtain debug info (typically used to debug launching, UIAutomation and other issues)
521
- # - `DEBUG_HTTP` - set to "1" to show raw HTTP traffic
492
+ # * `:app` - which app to launch.
493
+ # * `:device_target` - simulator or device to target.
494
+ # * `:reset_app_sandbox - reset he app's data (sandbox) before testing
522
495
  #
496
+ # and many other behaviors.
523
497
  #
524
- # @example Launching on iPad simulator with DEBUG settings
525
- # DEBUG_HTTP=1 DEVICE_TARGET="iPad - Simulator - iOS 7.1" DEBUG=1 APP_BUNDLE_PATH=FieldServiceiOS.app bundle exec calabash-ios console
526
- # @param {Hash} args optional args to specify details of the launch (e.g. device or simulator, sdk version,
527
- # target device, launch method...).
528
- # @option args {String} :app (detect the location of the bundle from project settings) app bundle path
529
- # @option args {String} :bundle_id if launching on device, specify this or env `BUNDLE_ID` to be the bundle identifier
530
- # of the application to launch
531
- # @option args {Hash} :privacy_settings preset privacy settings for the, e.g., `{:photos => {:allow => true}}`.
532
- # See {KNOWN_PRIVACY_SETTINGS}
498
+ # Many of these behaviors can be be controlled by environment variables. The
499
+ # most important environment variables are `APP`, `DEVICE_TARGET`, and
500
+ # `DEVICE_ENDPOINT`.
501
+ #
502
+ # @param {Hash} args optional arguments to control the how the app is launched
533
503
  def relaunch(args={})
534
- #TODO stopping is currently broken, but this works anyway because instruments stop the process before relaunching
535
- RunLoop.stop(run_loop) if run_loop
536
504
 
537
505
  # @todo Don't overwrite the _args_ parameter!
538
506
  args = default_launch_args.merge(args)
@@ -577,34 +545,11 @@ class Calabash::Cucumber::Launcher
577
545
 
578
546
  args[:device] ||= detect_device_from_args(args)
579
547
 
580
- if simulator_target?(args) and args[:reset]
581
- # attempt to find the sdk version from the :device_target
582
- sdk = sdk_version_for_simulator_target(args)
583
-
584
- # *** LEGACY SUPPORT ***
585
- # If DEVICE_TARGET has not been set and is not a device UDID, then
586
- # :device_target will be 'simulator'. In that case, we cannot know what
587
- # SDK version of the app sandbox we should reset. The user _might_ give
588
- # us a hint with SDK_VERSION, but we want to deprecate that variable ASAP.
589
- #
590
- # If passed a nil SDK arg, reset_app_sandbox will reset the _latest_ SDK.
591
- # This is not good, because this is probably _not_ the SDK that should be
592
- # reset. Our only option is to reset every sandbox for all SDKs by
593
- # passing :sdk => :all to reset_app_sandbox.
594
- if sdk.nil? and args[:device_target] == 'simulator'
595
- sdk = :all
596
- end
597
- reset_app_sandbox({:sdk => sdk,
598
- :path => args[:app],
599
- :udid => args[:udid],
600
- :sim_control => args[:sim_control]})
601
- end
602
-
603
548
  if args[:privacy_settings]
604
549
  if simulator_target?(args)
605
550
  update_privacy_settings(args[:bundle_id], args[:privacy_settings])
606
551
  else
607
- #Not supported on device
552
+ # Not supported on device
608
553
  puts 'Warning: :privacy_settings not supported on device'
609
554
  end
610
555
  end
@@ -649,6 +594,8 @@ class Calabash::Cucumber::Launcher
649
594
  check_server_gem_compatibility
650
595
  end
651
596
  end
597
+
598
+ usage_tracker.post_usage_async
652
599
  end
653
600
 
654
601
  # @!visibility private
@@ -1083,7 +1030,7 @@ class Calabash::Cucumber::Launcher
1083
1030
  msgs = [
1084
1031
  'The server version is not compatible with gem version.',
1085
1032
  'Please update your server.',
1086
- 'https://github.com/calabash/calabash-ios/wiki/B1-Updating-your-Calabash-iOS-version',
1033
+ 'https://github.com/calabash/calabash-ios/wiki/Updating-your-Calabash-iOS-version',
1087
1034
  " gem version: '#{gem_version}'",
1088
1035
  "min server version: '#{min_server_version}'",
1089
1036
  " server version: '#{server_version}'"]
@@ -0,0 +1,79 @@
1
+ module Calabash
2
+ module Cucumber
3
+ require "run_loop"
4
+
5
+ # These methods are not part of the API.
6
+ #
7
+ # They may change at any time.
8
+
9
+ # !@visibility private
10
+ # blue
11
+ def self.log_warn(msg)
12
+ puts self.blue(" WARN: #{msg}") if msg
13
+ end
14
+
15
+ # !@visibility private
16
+ # magenta
17
+ def self.log_debug(msg)
18
+ if RunLoop::Environment.debug?
19
+ puts self.magenta("DEBUG: #{msg}") if msg
20
+ end
21
+ end
22
+
23
+ # !@visibility private
24
+ # green
25
+ def self.log_info(msg)
26
+ puts self.green(" INFO: #{msg}") if msg
27
+ end
28
+
29
+ # !@visibility private
30
+ # red
31
+ def self.log_error(msg)
32
+ puts self.red("ERROR: #{msg}") if msg
33
+ end
34
+
35
+ private
36
+
37
+ # @!visibility private
38
+ def self.windows_env?
39
+ RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
40
+ end
41
+
42
+ # @!visibility private
43
+ def self.colorize(string, color)
44
+ if self.windows_env?
45
+ string
46
+ elsif RunLoop::Environment.xtc?
47
+ string
48
+ else
49
+ "\033[#{color}m#{string}\033[0m"
50
+ end
51
+ end
52
+
53
+ # @!visibility private
54
+ def self.red(string)
55
+ colorize(string, 31)
56
+ end
57
+
58
+ # @!visibility private
59
+ def self.blue(string)
60
+ colorize(string, 34)
61
+ end
62
+
63
+ # @!visibility private
64
+ def self.magenta(string)
65
+ colorize(string, 35)
66
+ end
67
+
68
+ # @!visibility private
69
+ def self.cyan(string)
70
+ colorize(string, 36)
71
+ end
72
+
73
+ # @!visibility private
74
+ def self.green(string)
75
+ colorize(string, 32)
76
+ end
77
+ end
78
+ end
79
+
@@ -75,7 +75,7 @@ module Calabash
75
75
  Most likely you have updated your calabash-cucumber client
76
76
  but not your server. Please follow closely:
77
77
 
78
- https://github.com/calabash/calabash-ios/wiki/B1-Updating-your-Calabash-iOS-version
78
+ https://github.com/calabash/calabash-ios/wiki/Updating-your-Calabash-iOS-version
79
79
 
80
80
  If you are running version 0.9.120+ then please report this message as a bug.
81
81
  EOF
@@ -194,7 +194,7 @@ EOF
194
194
  Most likely you have updated your calabash-cucumber client
195
195
  but not your server. Please follow closely:
196
196
 
197
- https://github.com/calabash/calabash-ios/wiki/B1-Updating-your-Calabash-iOS-version
197
+ https://github.com/calabash/calabash-ios/wiki/Updating-your-Calabash-iOS-version
198
198
 
199
199
  If you are running version 0.9.120+ then please report this message as a bug.
200
200
  EOF
@@ -0,0 +1,223 @@
1
+ module Calabash
2
+ module Cucumber
3
+
4
+ require "fileutils"
5
+ require "securerandom"
6
+
7
+ # Users preferences persisted across runs:
8
+ #
9
+ # ~/.calabash/preferences/preferences.json
10
+ class Preferences
11
+
12
+ def initialize
13
+ dot_dir = Calabash::Cucumber::DotDir.directory
14
+ @path = File.join(dot_dir, "preferences", "preferences.json")
15
+ end
16
+
17
+ def to_s
18
+ puts "Preferences:"
19
+ ap read
20
+ end
21
+
22
+ def inspect
23
+ to_s
24
+ end
25
+
26
+ # !@visibility private
27
+ def usage_tracking
28
+ preferences = read
29
+
30
+ unless valid_user_tracking_value?(preferences[:usage_tracking])
31
+ log_defaults_reset
32
+ preferences[:usage_tracking] = defaults[:usage_tracking]
33
+ write(preferences)
34
+ end
35
+
36
+ preferences[:usage_tracking]
37
+ end
38
+
39
+ # !@visibility private
40
+ def usage_tracking=(value)
41
+ if !valid_user_tracking_value?(value)
42
+ raise ArgumentError,
43
+ "Expected '#{value}' to be one of #{VALID_USAGE_TRACKING_VALUES.join(", ")}"
44
+ end
45
+
46
+ preferences = read
47
+ preferences[:usage_tracking] = value
48
+ write(preferences)
49
+ end
50
+
51
+ # !@visibility private
52
+ def user_id
53
+ preferences = read
54
+
55
+ unless valid_user_id?(preferences[:user_id])
56
+ preferences[:user_id] = SecureRandom.uuid
57
+ write(preferences)
58
+ end
59
+
60
+ preferences[:user_id]
61
+ end
62
+
63
+ # !@visibility private
64
+ def user_id=(value)
65
+ if !valid_user_id?(value)
66
+ raise ArgumentError,
67
+ "Expected '#{value}' to not be nil and not an empty string"
68
+ end
69
+
70
+ preferences = read
71
+ preferences[:user_id] = value
72
+ write(preferences)
73
+ end
74
+
75
+ private
76
+
77
+ # @!visibility private
78
+ def valid_user_tracking_value?(value)
79
+ VALID_USAGE_TRACKING_VALUES.include?(value)
80
+ end
81
+
82
+ # @!visibility private
83
+ def valid_user_id?(value)
84
+ !value.nil? && value != "" && value.is_a?(String)
85
+ end
86
+
87
+ # @!visibility private
88
+ #
89
+ # The preferences version
90
+ VERSION = "1.0"
91
+
92
+ # @!visibility private
93
+ #
94
+ # Ordered by permissiveness left to right ascending.
95
+ #
96
+ # "system_info" implies that "events" are also allowed.
97
+ VALID_USAGE_TRACKING_VALUES = ["none", "events", "system_info"]
98
+
99
+ # @!visibility private
100
+ def version
101
+ read[:version]
102
+ end
103
+
104
+ # @!visibility private
105
+ attr_reader :path
106
+
107
+ # @!visibility private
108
+ def ensure_preferences_dir
109
+ dir = File.dirname(@path)
110
+ unless File.exist?(dir)
111
+ FileUtils.mkdir_p(dir)
112
+ end
113
+ end
114
+
115
+ # @!visibility private
116
+ def defaults
117
+ {
118
+ :version => VERSION,
119
+ :usage_tracking => "system_info",
120
+ :user_id => SecureRandom.uuid
121
+ }
122
+ end
123
+
124
+ # @!visibility private
125
+ def write(hash)
126
+ if hash.nil?
127
+ raise ArgumentError, "Hash to write cannot be nil"
128
+ end
129
+
130
+ if !hash.is_a?(Hash)
131
+ raise ArgumentError, "Expected a Hash argument"
132
+ end
133
+
134
+ if hash.count == 0
135
+ raise ArgumentError, "Hash to write cannot be empty"
136
+ end
137
+
138
+ string = generate_json(hash)
139
+
140
+ ensure_preferences_dir
141
+
142
+ File.open(path, "w:UTF-8") do |file|
143
+ file.write(string)
144
+ end
145
+
146
+ true
147
+ end
148
+
149
+ # @!visibility private
150
+ def generate_json(hash)
151
+ begin
152
+ JSON.pretty_generate(hash)
153
+ rescue TypeError, JSON::UnparserError => e
154
+ write_to_log(
155
+ %Q{Error generating JSON from:
156
+ hash: #{hash}
157
+ error: #{e}
158
+ })
159
+ log_defaults_reset
160
+
161
+ # Will always generate valid JSON
162
+ generate_json(defaults)
163
+ end
164
+ end
165
+
166
+ # @!visibility private
167
+ def read
168
+ if File.exist?(path)
169
+
170
+ string = File.read(path).force_encoding("UTF-8")
171
+
172
+ parse_json(string)
173
+ else
174
+ hash = defaults
175
+ write(hash)
176
+ hash
177
+ end
178
+ end
179
+
180
+ # @!visibility private
181
+ def parse_json(string)
182
+ begin
183
+ JSON.parse(string, {:symbolize_names => true})
184
+ rescue TypeError, JSON::ParserError => e
185
+ write_to_log(
186
+ %Q{Error parsing JSON from:
187
+ string: #{string}
188
+ error: #{e}
189
+ })
190
+ log_defaults_reset
191
+
192
+ hash = defaults
193
+ write(hash)
194
+ hash
195
+ end
196
+ end
197
+
198
+ # @!visibility private
199
+ def write_to_log(error_message)
200
+ # TODO write to a log file?
201
+ end
202
+
203
+ # @!visibility private
204
+ def log_defaults_reset
205
+ Calabash::Cucumber.log_warn(
206
+ %q{An error occurred while accessing your user preferences.
207
+
208
+ We have reset the preferences to the default settings.
209
+
210
+ If this happens on a regular basis, please create a GitHub issue.
211
+
212
+ Your preferences control various Calabash behaviors. In particular, they tell
213
+ us how much usage information you are willing to share. If you have previously
214
+ turned off usage tracking, you will need to disable it again using the command
215
+ line tools or the irb.
216
+
217
+ We do not recommend that edit the preferences file by hand.
218
+ })
219
+ end
220
+ end
221
+ end
222
+ end
223
+