bubble-wrap 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +6 -14
  2. data/.travis.yml +2 -1
  3. data/CHANGELOG.md +26 -2
  4. data/GETTING_STARTED.md +1 -1
  5. data/Gemfile.lock +1 -1
  6. data/HACKING.md +6 -4
  7. data/README.md +83 -3
  8. data/Rakefile +9 -7
  9. data/lib/bubble-wrap/all.rb +2 -2
  10. data/lib/bubble-wrap/mail.rb +9 -0
  11. data/lib/bubble-wrap/sms.rb +9 -0
  12. data/lib/bubble-wrap/ui.rb +6 -2
  13. data/lib/bubble-wrap/version.rb +1 -1
  14. data/motion/core.rb +1 -1
  15. data/motion/core/app.rb +7 -2
  16. data/motion/core/device/ios/camera.rb +3 -2
  17. data/motion/core/device/ios/screen.rb +19 -0
  18. data/motion/core/ios/app.rb +13 -1
  19. data/motion/core/ios/device.rb +5 -0
  20. data/motion/core/json.rb +1 -3
  21. data/motion/core/kvo.rb +11 -13
  22. data/motion/core/persistence.rb +8 -1
  23. data/motion/core/string.rb +3 -3
  24. data/motion/core/time.rb +5 -0
  25. data/motion/http.rb +1 -1
  26. data/motion/http/query.rb +39 -19
  27. data/motion/http/response.rb +4 -4
  28. data/motion/mail/mail.rb +59 -0
  29. data/motion/mail/result.rb +29 -0
  30. data/motion/reactor/eventable.rb +3 -2
  31. data/motion/reactor/periodic_timer.rb +12 -8
  32. data/motion/reactor/timer.rb +11 -7
  33. data/motion/sms/result.rb +24 -0
  34. data/motion/sms/sms.rb +47 -0
  35. data/motion/ui/pollute.rb +4 -1
  36. data/motion/ui/ui_alert_view.rb +15 -8
  37. data/motion/ui/ui_control_wrapper.rb +16 -0
  38. data/motion/ui/ui_view_controller_wrapper.rb +13 -0
  39. data/motion/ui/ui_view_wrapper.rb +55 -0
  40. data/resources/Localizable.strings +1 -0
  41. data/samples/gesture/Gemfile +2 -2
  42. data/samples/location/Gemfile +1 -1
  43. data/samples/osx/Gemfile +2 -2
  44. data/spec/motion/core/app_spec.rb +6 -0
  45. data/spec/motion/core/device/ios/camera_spec.rb +3 -3
  46. data/spec/motion/core/device/ios/screen_spec.rb +45 -0
  47. data/spec/motion/core/ios/app_spec.rb +29 -0
  48. data/spec/motion/core/persistence_spec.rb +25 -0
  49. data/spec/motion/core/string_spec.rb +2 -2
  50. data/spec/motion/core/time_spec.rb +14 -4
  51. data/spec/motion/core_spec.rb +9 -8
  52. data/spec/motion/http/query_spec.rb +92 -15
  53. data/spec/motion/http/response_spec.rb +4 -3
  54. data/spec/motion/location/location_spec.rb +1 -1
  55. data/spec/motion/mail/mail_spec.rb +125 -0
  56. data/spec/motion/mail/result_spec.rb +53 -0
  57. data/spec/motion/reactor/eventable_spec.rb +85 -0
  58. data/spec/motion/reactor_spec.rb +0 -20
  59. data/spec/motion/sms/result_spec.rb +38 -0
  60. data/spec/motion/sms/sms_spec.rb +71 -0
  61. data/spec/motion/ui/pollute_spec.rb +13 -0
  62. data/spec/motion/ui/ui_bar_button_item_spec.rb +8 -8
  63. data/spec/motion/ui/ui_control_wrapper_spec.rb +35 -0
  64. data/spec/motion/ui/ui_view_controller_wrapper_spec.rb +34 -0
  65. data/spec/motion/ui/ui_view_wrapper_spec.rb +62 -0
  66. data/travis.sh +7 -0
  67. metadata +52 -22
  68. data/motion/ui/gestures.rb +0 -57
  69. data/motion/ui/ui_control.rb +0 -14
  70. data/motion/ui/ui_view_controller.rb +0 -11
  71. data/spec/motion/ui/gestures_spec.rb +0 -62
  72. data/spec/motion/ui/ui_control_spec.rb +0 -42
@@ -1,8 +1,8 @@
1
1
  describe BubbleWrap::String do
2
2
 
3
- describe ::String do
3
+ describe ::NSString do
4
4
  it 'should include BubbleWrap::String' do
5
- ::String.ancestors.member?(BubbleWrap::String).should == true
5
+ ::NSString.ancestors.member?(BubbleWrap::String).should == true
6
6
  end
7
7
  end
8
8
 
@@ -17,39 +17,49 @@ describe "Time" do
17
17
  describe "parsing an iso8601 formatted time to a Time object" do
18
18
  before do
19
19
  @time = Time.iso8601("2012-05-31T19:41:33Z")
20
+ @time_with_timezone = Time.iso8601_with_timezone("1987-08-10T06:00:00+02:00")
20
21
  end
21
22
 
22
23
  it "should be a time" do
23
24
  @time.instance_of?(Time).should == true
25
+ @time_with_timezone.instance_of?(Time).should == true
24
26
  end
25
27
 
26
- # # Crashes Buggy RubyMotion 1.18
27
- # it "should be converted to the local timezone automatically" do
28
- # @time.zone.should == Time.now.zone
29
- # end
28
+ # Crashes Buggy RubyMotion 1.18
29
+ it "should be converted to the local timezone automatically" do
30
+ local_zone = Time.now.zone
31
+ @time.zone.should == local_zone
32
+ @time_with_timezone.zone == local_zone
33
+ end
30
34
 
31
35
  it "should have a valid year" do
32
36
  @time.utc.year.should == 2012
37
+ @time_with_timezone.utc.year.should == 1987
33
38
  end
34
39
 
35
40
  it "should have a valid month" do
36
41
  @time.utc.month.should == 5
42
+ @time_with_timezone.utc.month.should == 8
37
43
  end
38
44
 
39
45
  it "should have a valid day" do
40
46
  @time.utc.day.should == 31
47
+ @time_with_timezone.utc.day.should == 10
41
48
  end
42
49
 
43
50
  it "should have a valid hour" do
44
51
  @time.utc.hour.should == 19
52
+ @time_with_timezone.utc.hour.should == 4
45
53
  end
46
54
 
47
55
  it "should have a valid minute" do
48
56
  @time.utc.min.should == 41
57
+ @time_with_timezone.utc.min.should == 0
49
58
  end
50
59
 
51
60
  it "should have a valid second" do
52
61
  @time.utc.sec.should == 33
62
+ @time_with_timezone.utc.sec.should == 0
53
63
  end
54
64
  end
55
65
 
@@ -54,15 +54,16 @@ describe 'BubbleWrap' do
54
54
  describe "Localized string" do
55
55
 
56
56
  it "loads the string from NSBundle" do
57
+ key = 'real_key'
58
+ value = 'Real Key'
59
+
60
+ BubbleWrap::localized_string(key, value).should == value
61
+ end
62
+
63
+ it "returns the key if localization not found and no value is given" do
57
64
  key = 'fake_key'
58
- value = 'fake_value'
59
-
60
- bundle = NSBundle.mainBundle
61
- def bundle.arguments; @arguments; end
62
- def bundle.localizedStringForKey(key, value:value, table:table); @arguments = [key, value, table]; end
63
-
64
- BubbleWrap::localized_string(key, value)
65
- bundle.arguments.should.equal [key, value, nil]
65
+
66
+ BubbleWrap::localized_string(key).should == key
66
67
  end
67
68
 
68
69
  end
@@ -1,5 +1,31 @@
1
+ # -*- coding: utf-8 -*-
1
2
  describe BubbleWrap::HTTP::Query do
2
3
 
4
+ describe "json parameter encoding" do
5
+ before do
6
+ @json_payload = {"foo" => "bar"}
7
+ @json_options = {
8
+ payload: @json_payload,
9
+ format: :json
10
+ }
11
+ @json_query = BubbleWrap::HTTP::Query.new( "http://localhost:3000" , :post, @json_options )
12
+ end
13
+
14
+ it "should generate json body" do
15
+ BW::JSON.parse(@json_query.request.HTTPBody).should == @json_payload
16
+ end
17
+ end
18
+
19
+ describe "false value" do
20
+ before do
21
+ @query = BubbleWrap::HTTP::Query.new("http://www.google.com", :get, {payload: {following: false}})
22
+ end
23
+
24
+ it "should have right url" do
25
+ @query.request.URL.absoluteString.should == "http://www.google.com?following=false"
26
+ end
27
+ end
28
+
3
29
  before do
4
30
  @localhost_url = 'http://localhost'
5
31
  @fake_url = 'http://fake.url'
@@ -137,14 +163,14 @@ describe BubbleWrap::HTTP::Query do
137
163
  }.should.not.raise NoMethodError
138
164
  end
139
165
 
140
- it "should set the payload in URL only for GET and HEAD requests" do
166
+ it "should set the payload in URL only for GET/HEAD/OPTIONS requests" do
141
167
  [:post, :put, :delete, :patch].each do |method|
142
168
  query = BubbleWrap::HTTP::Query.new( @localhost_url , method, { payload: @payload } )
143
169
  query.instance_variable_get(:@url).description.should.equal @localhost_url
144
170
  end
145
171
 
146
172
  payload = {name: 'marin'}
147
- [:get, :head].each do |method|
173
+ [:get, :head, :options].each do |method|
148
174
  query = BubbleWrap::HTTP::Query.new( @localhost_url , method, { payload: payload } )
149
175
  query.instance_variable_get(:@url).description.should.equal "#{@localhost_url}?name=marin"
150
176
  end
@@ -179,11 +205,10 @@ describe BubbleWrap::HTTP::Query do
179
205
  }.should.raise InvalidFileError
180
206
  end
181
207
 
182
- it "sets the HTTPBody DATA to @request for all methods except GET and HEAD" do
208
+ it "sets the HTTPBody DATA to @request for all methods except GET/HEAD/OPTIONS" do
183
209
  payload = { name: 'apple', model: 'macbook'}
184
210
  files = { twitter: sample_data, site: "mneorr.com".dataUsingEncoding(NSUTF8StringEncoding) }
185
211
 
186
- puts "\n"
187
212
  [:post, :put, :delete, :patch].each do |method|
188
213
  puts " - #{method}\n"
189
214
  query = BubbleWrap::HTTP::Query.new( @fake_url , method, { payload: payload, files: files } )
@@ -192,7 +217,7 @@ describe BubbleWrap::HTTP::Query do
192
217
  real_payload.should.equal "--#{uuid}\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\napple\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nmacbook\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"twitter\"; filename=\"twitter\"\r\nContent-Type: application/octet-stream\r\n\r\ntwitter:@mneorr\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"site\"; filename=\"site\"\r\nContent-Type: application/octet-stream\r\n\r\nmneorr.com\r\n--#{uuid}--\r\n"
193
218
  end
194
219
 
195
- [:get, :head].each do |method|
220
+ [:get, :head, :options].each do |method|
196
221
  puts " - #{method}\n"
197
222
  query = BubbleWrap::HTTP::Query.new( @fake_url , method, { payload: payload } )
198
223
  real_payload = NSString.alloc.initWithData(query.request.HTTPBody, encoding:NSUTF8StringEncoding)
@@ -202,12 +227,11 @@ describe BubbleWrap::HTTP::Query do
202
227
 
203
228
  it "sets the payload without conversion to-from NSString if the payload was NSData" do
204
229
  data = sample_data
205
- lambda { query = create_query(data, nil) }.should.not.raise NoMethodError
230
+ lambda { create_query(data, nil) }.should.not.raise NoMethodError
206
231
  end
207
232
 
208
233
  it "sets the payload as a string if JSON" do
209
234
  json = "{\"foo\":42,\"bar\":\"BubbleWrap\"}"
210
- puts "\n"
211
235
  [:put, :post, :delete, :patch].each do |method|
212
236
  puts " - #{method}\n"
213
237
  query = BubbleWrap::HTTP::Query.new( @fake_url , method, { payload: json } )
@@ -224,6 +248,19 @@ describe BubbleWrap::HTTP::Query do
224
248
  real_payload.should.equal "--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[name]\"\r\n\r\napple\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[model]\"\r\n\r\nmacbook\r\n--#{uuid}--\r\n"
225
249
  end
226
250
 
251
+ [["NSUTF8StringEncoding", NSUTF8StringEncoding],
252
+ ["NSJapaneseEUCStringEncoding", NSJapaneseEUCStringEncoding],
253
+ ["NSShiftJISStringEncoding", NSShiftJISStringEncoding],
254
+ ["NSISO2022JPStringEncoding", NSISO2022JPStringEncoding]].each do |enc_name, encoding|
255
+ it "sets the japanese characters payload encoded in #{enc_name}" do
256
+ payload = { computer: { name: '名前', model: 'モデル'} }
257
+ query = BubbleWrap::HTTP::Query.new( @fake_url, :post, { payload: payload, encoding: encoding })
258
+ uuid = query.instance_variable_get(:@boundary)
259
+ real_payload = NSString.alloc.initWithData(query.request.HTTPBody, encoding:encoding)
260
+ real_payload.should.equal "--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[name]\"\r\n\r\n#{payload[:computer][:name]}\r\n--#{uuid}\r\nContent-Disposition: form-data; name=\"computer[model]\"\r\n\r\n#{payload[:computer][:model]}\r\n--#{uuid}--\r\n"
261
+ end
262
+ end
263
+
227
264
  end
228
265
 
229
266
  it "should set default timeout to 30s or the one from hash" do
@@ -479,6 +516,12 @@ describe BubbleWrap::HTTP::Query do
479
516
  @query.response.error_message.should.equal @fake_error.localizedDescription
480
517
  end
481
518
 
519
+ it "should set the error object to response object" do
520
+ @query.response.error.should.equal nil
521
+ @query.connection(nil, didFailWithError:@fake_error)
522
+ @query.response.error.code.should.equal @fake_error.code
523
+ end
524
+
482
525
  it "should check if there's a callback block and pass the response in" do
483
526
  expected_response = BubbleWrap::HTTP::Response.new
484
527
  real_response = nil
@@ -577,8 +620,9 @@ describe BubbleWrap::HTTP::Query do
577
620
  end
578
621
  end
579
622
 
580
- it "sets the error message on response" do
623
+ it "sets the error message/code on response" do
581
624
  @real_response.error_message.should.equal "Too many redirections"
625
+ @real_response.error.code.should.equal NSURLErrorHTTPTooManyRedirects
582
626
  end
583
627
 
584
628
  it "sets the request.done_loading" do
@@ -608,10 +652,18 @@ describe BubbleWrap::HTTP::Query do
608
652
  @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
609
653
  end
610
654
 
611
- it "should cancel the authentication if the failure count was not 0" do
612
- @challenge.previousFailureCount = 1
613
- @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
614
- @challenge.sender.was_cancelled.should.equal true
655
+ describe "given the failure count was not 0" do
656
+ before { @challenge.previousFailureCount = 1 }
657
+
658
+ it "should cancel the authentication" do
659
+ @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
660
+ @challenge.sender.was_cancelled.should.equal true
661
+ end
662
+
663
+ it "should set the response fields" do
664
+ @query.connection(nil, didReceiveAuthenticationChallenge:@challenge)
665
+ @query.response.status_code.should.equal @challenge.failureResponse.statusCode
666
+ end
615
667
  end
616
668
 
617
669
  it "should pass in Credentials and the challenge itself to the sender" do
@@ -633,6 +685,23 @@ describe BubbleWrap::HTTP::Query do
633
685
 
634
686
  end
635
687
 
688
+ describe 'cancel' do
689
+ before do
690
+ @doa_query = BubbleWrap::HTTP::Query.new(@localhost_url, :get)
691
+ @doa_query.cancel
692
+ end
693
+
694
+ it "should cancel the connection" do
695
+ @doa_query.connection.was_cancelled.should.equal true
696
+ end
697
+
698
+ if App.ios?
699
+ it "should turn off the network indicator" do
700
+ UIApplication.sharedApplication.isNetworkActivityIndicatorVisible.should.equal false
701
+ end
702
+ end
703
+ end
704
+
636
705
  describe "empty payload" do
637
706
 
638
707
  before do
@@ -695,11 +764,15 @@ describe BubbleWrap::HTTP::Query do
695
764
  end
696
765
 
697
766
  class FakeChallenge
698
- attr_accessor :previousFailureCount
767
+ attr_accessor :previousFailureCount, :failureResponse
699
768
 
700
769
  def sender
701
770
  @fake_sender ||= FakeSender.new
702
771
  end
772
+
773
+ def failureResponse
774
+ @failureResponse ||= FakeURLResponse.new(401, { bla: "123" }, 123)
775
+ end
703
776
  end
704
777
 
705
778
  class BubbleWrap::HTTP::Query
@@ -707,7 +780,7 @@ describe BubbleWrap::HTTP::Query do
707
780
  end
708
781
 
709
782
  class FakeURLConnection < NSURLConnection
710
- attr_reader :delegate, :request, :was_started
783
+ attr_reader :delegate, :request, :was_started, :was_cancelled
711
784
  def initialize(request, delegate)
712
785
  @request = request
713
786
  @delegate = delegate
@@ -715,8 +788,12 @@ describe BubbleWrap::HTTP::Query do
715
788
  end
716
789
  def start
717
790
  @was_started = true
791
+ @was_cancelled = false
718
792
  super
719
793
  end
794
+ def cancel
795
+ @was_cancelled = true
796
+ end
720
797
  end
721
798
 
722
799
  class FakeURLResponse < NSHTTPURLResponse
@@ -728,4 +805,4 @@ describe BubbleWrap::HTTP::Query do
728
805
  end
729
806
  end
730
807
 
731
- end
808
+ end
@@ -9,12 +9,12 @@ describe BubbleWrap::HTTP::Response do
9
9
  @response.instance_variable_get(:@url).should == 'http://localhost'
10
10
  end
11
11
 
12
- it "says OK status code 20x" do
12
+ it "says OK status code 2xx" do
13
13
  @response.ok?.should.equal true
14
- (200..209).each do |code|
14
+ (200..211).each do |code|
15
15
  BubbleWrap::HTTP::Response.new(status_code: code).ok?.should.be.true
16
16
  end
17
- [100..101, 300..307, 400..417, 500..505].inject([]){|codes, rg| codes += rg.to_a}.each do |code|
17
+ [100..101, 300..307, 400..417, 500..505].inject([]){|codes, rg| codes + rg.to_a}.each do |code|
18
18
  BubbleWrap::HTTP::Response.new(status_code: code).ok?.should.be.false
19
19
  end
20
20
  end
@@ -39,6 +39,7 @@ describe BubbleWrap::HTTP::Response do
39
39
  @response.should.respond_to :url
40
40
  @response.should.respond_to :status_code=
41
41
  @response.should.respond_to :error_message=
42
+ @response.should.respond_to :error=
42
43
  end
43
44
 
44
45
  end
@@ -162,7 +162,7 @@ describe BubbleWrap::Location do
162
162
  end
163
163
 
164
164
  it "should use significant update functions with get_significant" do
165
- BW::Location.get_significant do |result|
165
+ BW::Location.get_significant do
166
166
  end
167
167
 
168
168
  BW::Location.stop
@@ -0,0 +1,125 @@
1
+ # Mocking the presentViewController
2
+ class MailViewController < UIViewController
3
+ attr_accessor :expectation
4
+
5
+ def presentModalViewController(modal, animated: animated)
6
+ expectation.call modal, animated
7
+ end
8
+ end
9
+
10
+ # Monkey-patching MFMailComposeViewController
11
+ # So we can access the values that are set.
12
+ # This of course breaks MFMailComposeViewController from actually working,
13
+ # but it's testable.
14
+ class MFMailComposeViewController
15
+ attr_accessor :toRecipients, :ccRecipients, :bccRecipients, :subject, :message, :html
16
+
17
+ def setToRecipients(r)
18
+ self.toRecipients = r
19
+ end
20
+
21
+ def setCcRecipients(r)
22
+ self.ccRecipients = r
23
+ end
24
+
25
+ def setBccRecipients(r)
26
+ self.bccRecipients = r
27
+ end
28
+
29
+ def setSubject(r)
30
+ self.subject = r
31
+ end
32
+
33
+ def setMessageBody(message, isHTML: html)
34
+ self.message = message
35
+ self.html = html
36
+ end
37
+ end
38
+
39
+ describe BW::Mail do
40
+ describe ".compose" do
41
+ before do
42
+ @view_controller = MailViewController.new
43
+ @standard_mail_options = {
44
+ delegate: @view_controller,
45
+ to: [ "tom@example.com" ],
46
+ cc: [ "itchy@example.com", "scratchy@example.com" ],
47
+ bcc: [ "jerry@example.com" ],
48
+ html: false,
49
+ subject: "My Subject",
50
+ message: "This is my message. It isn't very long.",
51
+ animated: false
52
+ }
53
+ end
54
+
55
+ it "should open the mail controller in a modal" do
56
+ @view_controller.expectation = lambda { |mail_controller, animated|
57
+ mail_controller.should.be.kind_of(MFMailComposeViewController)
58
+ }
59
+
60
+ BubbleWrap::Mail.compose @standard_mail_options
61
+ end
62
+
63
+ it "should create a mail controller with the right to: address set" do
64
+ @view_controller.expectation = lambda { |mail_controller, animated|
65
+ mail_controller.toRecipients.should.be.kind_of(Array)
66
+ mail_controller.toRecipients.should == @standard_mail_options[:to]
67
+ }
68
+
69
+ BubbleWrap::Mail.compose @standard_mail_options
70
+ end
71
+
72
+ it "should create a mail controller with the right cc: address set" do
73
+ @view_controller.expectation = lambda { |mail_controller, animated|
74
+ mail_controller.ccRecipients.should.be.kind_of(Array)
75
+ mail_controller.ccRecipients.should == @standard_mail_options[:cc]
76
+ }
77
+
78
+ BubbleWrap::Mail.compose @standard_mail_options
79
+ end
80
+
81
+ it "should create a mail controller with the right bcc: address set" do
82
+ @view_controller.expectation = lambda { |mail_controller, animated|
83
+ mail_controller.bccRecipients.should.be.kind_of(Array)
84
+ mail_controller.bccRecipients.should == @standard_mail_options[:bcc]
85
+ }
86
+
87
+ BubbleWrap::Mail.compose @standard_mail_options
88
+ end
89
+
90
+ it "should create a mail controller with the right subject: set" do
91
+ @view_controller.expectation = lambda { |mail_controller, animated|
92
+ mail_controller.subject.should.be.kind_of(String)
93
+ mail_controller.subject.should == @standard_mail_options[:subject]
94
+ }
95
+
96
+ BubbleWrap::Mail.compose @standard_mail_options
97
+ end
98
+
99
+ it "should create a mail controller with the right message: set" do
100
+ @view_controller.expectation = lambda { |mail_controller, animated|
101
+ mail_controller.message.should.be.kind_of(String)
102
+ mail_controller.message.should == @standard_mail_options[:message]
103
+ }
104
+
105
+ BubbleWrap::Mail.compose @standard_mail_options
106
+ end
107
+
108
+ it "should create a mail controller with the right html: set" do
109
+ @view_controller.expectation = lambda { |mail_controller, animated|
110
+ mail_controller.html.should == @standard_mail_options[:html]
111
+ }
112
+
113
+ BubbleWrap::Mail.compose @standard_mail_options
114
+ end
115
+
116
+ it "should create a mail controller with the right animation" do
117
+ @view_controller.expectation = lambda { |mail_controller, animated|
118
+ animated.should.be.false
119
+ }
120
+
121
+ BubbleWrap::Mail.compose @standard_mail_options
122
+ end
123
+
124
+ end
125
+ end