shingara-blather 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +162 -0
  3. data/examples/echo.rb +18 -0
  4. data/examples/execute.rb +16 -0
  5. data/examples/ping_pong.rb +37 -0
  6. data/examples/print_hierarchy.rb +76 -0
  7. data/examples/rosterprint.rb +14 -0
  8. data/examples/stream_only.rb +27 -0
  9. data/examples/xmpp4r/echo.rb +35 -0
  10. data/lib/blather/client/client.rb +310 -0
  11. data/lib/blather/client/dsl/pubsub.rb +170 -0
  12. data/lib/blather/client/dsl.rb +264 -0
  13. data/lib/blather/client.rb +87 -0
  14. data/lib/blather/core_ext/nokogiri.rb +40 -0
  15. data/lib/blather/errors/sasl_error.rb +43 -0
  16. data/lib/blather/errors/stanza_error.rb +107 -0
  17. data/lib/blather/errors/stream_error.rb +82 -0
  18. data/lib/blather/errors.rb +69 -0
  19. data/lib/blather/jid.rb +142 -0
  20. data/lib/blather/roster.rb +111 -0
  21. data/lib/blather/roster_item.rb +122 -0
  22. data/lib/blather/stanza/disco/disco_info.rb +176 -0
  23. data/lib/blather/stanza/disco/disco_items.rb +132 -0
  24. data/lib/blather/stanza/disco.rb +25 -0
  25. data/lib/blather/stanza/iq/query.rb +53 -0
  26. data/lib/blather/stanza/iq/roster.rb +179 -0
  27. data/lib/blather/stanza/iq.rb +138 -0
  28. data/lib/blather/stanza/message.rb +332 -0
  29. data/lib/blather/stanza/presence/status.rb +212 -0
  30. data/lib/blather/stanza/presence/subscription.rb +101 -0
  31. data/lib/blather/stanza/presence.rb +163 -0
  32. data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
  33. data/lib/blather/stanza/pubsub/create.rb +65 -0
  34. data/lib/blather/stanza/pubsub/errors.rb +18 -0
  35. data/lib/blather/stanza/pubsub/event.rb +123 -0
  36. data/lib/blather/stanza/pubsub/items.rb +103 -0
  37. data/lib/blather/stanza/pubsub/publish.rb +103 -0
  38. data/lib/blather/stanza/pubsub/retract.rb +92 -0
  39. data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
  40. data/lib/blather/stanza/pubsub/subscription.rb +134 -0
  41. data/lib/blather/stanza/pubsub/subscriptions.rb +81 -0
  42. data/lib/blather/stanza/pubsub/unsubscribe.rb +68 -0
  43. data/lib/blather/stanza/pubsub.rb +129 -0
  44. data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
  45. data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
  46. data/lib/blather/stanza/pubsub_owner.rb +51 -0
  47. data/lib/blather/stanza.rb +149 -0
  48. data/lib/blather/stream/client.rb +31 -0
  49. data/lib/blather/stream/component.rb +38 -0
  50. data/lib/blather/stream/features/resource.rb +63 -0
  51. data/lib/blather/stream/features/sasl.rb +187 -0
  52. data/lib/blather/stream/features/session.rb +44 -0
  53. data/lib/blather/stream/features/tls.rb +28 -0
  54. data/lib/blather/stream/features.rb +53 -0
  55. data/lib/blather/stream/parser.rb +102 -0
  56. data/lib/blather/stream.rb +231 -0
  57. data/lib/blather/xmpp_node.rb +218 -0
  58. data/lib/blather.rb +78 -0
  59. data/spec/blather/client/client_spec.rb +559 -0
  60. data/spec/blather/client/dsl/pubsub_spec.rb +462 -0
  61. data/spec/blather/client/dsl_spec.rb +143 -0
  62. data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
  63. data/spec/blather/errors/sasl_error_spec.rb +33 -0
  64. data/spec/blather/errors/stanza_error_spec.rb +129 -0
  65. data/spec/blather/errors/stream_error_spec.rb +108 -0
  66. data/spec/blather/errors_spec.rb +33 -0
  67. data/spec/blather/jid_spec.rb +87 -0
  68. data/spec/blather/roster_item_spec.rb +96 -0
  69. data/spec/blather/roster_spec.rb +103 -0
  70. data/spec/blather/stanza/discos/disco_info_spec.rb +226 -0
  71. data/spec/blather/stanza/discos/disco_items_spec.rb +148 -0
  72. data/spec/blather/stanza/iq/query_spec.rb +64 -0
  73. data/spec/blather/stanza/iq/roster_spec.rb +140 -0
  74. data/spec/blather/stanza/iq_spec.rb +45 -0
  75. data/spec/blather/stanza/message_spec.rb +132 -0
  76. data/spec/blather/stanza/presence/status_spec.rb +132 -0
  77. data/spec/blather/stanza/presence/subscription_spec.rb +105 -0
  78. data/spec/blather/stanza/presence_spec.rb +66 -0
  79. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  80. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  81. data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
  82. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  83. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  84. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  85. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  86. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  87. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  88. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
  89. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  90. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  91. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  92. data/spec/blather/stanza/pubsub_spec.rb +67 -0
  93. data/spec/blather/stanza_spec.rb +116 -0
  94. data/spec/blather/stream/client_spec.rb +1011 -0
  95. data/spec/blather/stream/component_spec.rb +95 -0
  96. data/spec/blather/stream/parser_spec.rb +145 -0
  97. data/spec/blather/xmpp_node_spec.rb +231 -0
  98. data/spec/fixtures/pubsub.rb +311 -0
  99. data/spec/spec_helper.rb +43 -0
  100. metadata +249 -0
@@ -0,0 +1,559 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
2
+ require 'blather/client/client'
3
+
4
+ describe Blather::Client do
5
+ before do
6
+ @client = Blather::Client.new
7
+ @stream = mock()
8
+ @stream.stubs(:send)
9
+ @jid = Blather::JID.new('n@d/r')
10
+ @client.post_init @stream, @jid
11
+ end
12
+
13
+ it 'provides a Blather::JID reader' do
14
+ @client.must_respond_to :jid
15
+ @client.jid.must_equal @jid
16
+ end
17
+
18
+ it 'provides a reader for the roster' do
19
+ @client.must_respond_to :roster
20
+ @client.roster.must_be_kind_of Blather::Roster
21
+ end
22
+
23
+ it 'provides a status reader' do
24
+ @client.must_respond_to :status
25
+ @client.status = :away
26
+ @client.status.must_equal :away
27
+ end
28
+
29
+ it 'can be setup' do
30
+ @client.must_respond_to :setup
31
+ @client.setup('me@me.com', 'pass').must_equal @client
32
+ end
33
+
34
+ it 'knows if it has been setup' do
35
+ @client.must_respond_to :setup?
36
+ @client.setup?.must_equal false
37
+ @client.setup 'me@me.com', 'pass'
38
+ @client.setup?.must_equal true
39
+ end
40
+
41
+ it 'cannot be run before being setup' do
42
+ lambda { @client.run }.must_raise RuntimeError
43
+ end
44
+
45
+ it 'starts up a Component connection when setup without a node' do
46
+ setup = 'pubsub.jabber.local', 'secret'
47
+ @client.setup *setup
48
+ Blather::Stream::Component.expects(:start).with @client, *setup
49
+ @client.run
50
+ end
51
+
52
+ it 'starts up a Client connection when setup with a node' do
53
+ setup = 'test@jabber.local', 'secret'
54
+ @client.setup *setup
55
+ Blather::Stream::Client.expects(:start).with @client, *setup
56
+ @client.run
57
+ end
58
+
59
+ it 'writes to the connection the closes when #close is called' do
60
+ stream = mock()
61
+ stream.expects(:close_connection_after_writing)
62
+ @client.setup('me.com', 'secret')
63
+ @client.post_init stream, Blather::JID.new('me.com')
64
+ @client.close
65
+ end
66
+
67
+ it 'shuts down EM when #unbind is called if it is running' do
68
+ EM.expects(:reactor_running?).returns true
69
+ EM.expects(:stop)
70
+ @client.unbind
71
+ end
72
+
73
+ it 'does nothing when #unbind is called and EM is not running' do
74
+ EM.expects(:reactor_running?).returns false
75
+ EM.expects(:stop).never
76
+ @client.unbind
77
+ end
78
+
79
+ it 'calls the :disconnected handler with #unbind is called' do
80
+ EM.expects(:reactor_running?).returns false
81
+ disconnected = mock()
82
+ disconnected.expects(:call)
83
+ @client.register_handler(:disconnected) { disconnected.call }
84
+ @client.unbind
85
+ end
86
+
87
+ it 'does not call EM.stop on #unbind if a handler returns positive' do
88
+ EM.expects(:reactor_running?).never
89
+ EM.expects(:stop).never
90
+ disconnected = mock()
91
+ disconnected.expects(:call).returns true
92
+ @client.register_handler(:disconnected) { disconnected.call }
93
+ @client.unbind
94
+ end
95
+
96
+ it 'calls EM.stop on #unbind if a handler returns negative' do
97
+ EM.expects(:reactor_running?).returns true
98
+ EM.expects(:stop)
99
+ disconnected = mock()
100
+ disconnected.expects(:call).returns false
101
+ @client.register_handler(:disconnected) { disconnected.call }
102
+ @client.unbind
103
+ end
104
+
105
+ it 'can register a temporary handler based on stanza ID' do
106
+ stanza = Blather::Stanza::Iq.new
107
+ response = mock()
108
+ response.expects(:call)
109
+ @client.register_tmp_handler(stanza.id) { |_| response.call }
110
+ @client.receive_data stanza
111
+ end
112
+
113
+ it 'removes a tmp handler as soon as it is used' do
114
+ stanza = Blather::Stanza::Iq.new
115
+ response = mock()
116
+ response.expects(:call)
117
+ @client.register_tmp_handler(stanza.id) { |_| response.call }
118
+ @client.receive_data stanza
119
+ @client.receive_data stanza
120
+ end
121
+
122
+ it 'will create a handler then write the stanza' do
123
+ stanza = Blather::Stanza::Iq.new
124
+ response = mock()
125
+ response.expects(:call)
126
+ @client.expects(:write).with do |s|
127
+ @client.receive_data stanza
128
+ s.must_equal stanza
129
+ end
130
+ @client.write_with_handler(stanza) { |_| response.call }
131
+ end
132
+
133
+ it 'can register a handler' do
134
+ stanza = Blather::Stanza::Iq.new
135
+ response = mock()
136
+ response.expects(:call).times(2)
137
+ @client.register_handler(:iq) { |_| response.call }
138
+ @client.receive_data stanza
139
+ @client.receive_data stanza
140
+ end
141
+
142
+ it 'allows for breaking out of handlers' do
143
+ stanza = Blather::Stanza::Iq.new
144
+ response = mock(:iq => nil)
145
+ @client.register_handler(:iq) do |_|
146
+ response.iq
147
+ throw :halt
148
+ response.fail
149
+ end
150
+ @client.receive_data stanza
151
+ end
152
+
153
+ it 'allows for passing to the next handler of the same type' do
154
+ stanza = Blather::Stanza::Iq.new
155
+ response = mock(:iq1 => nil, :iq2 => nil)
156
+ @client.register_handler(:iq) do |_|
157
+ response.iq1
158
+ throw :pass
159
+ response.fail
160
+ end
161
+ @client.register_handler(:iq) do |_|
162
+ response.iq2
163
+ end
164
+ @client.receive_data stanza
165
+ end
166
+
167
+ it 'allows for passing to the next handler in the hierarchy' do
168
+ stanza = Blather::Stanza::Iq::Query.new
169
+ response = mock(:query => nil, :iq => nil)
170
+ @client.register_handler(:query) do |_|
171
+ response.query
172
+ throw :pass
173
+ response.fail
174
+ end
175
+ @client.register_handler(:iq) { |_| response.iq }
176
+ @client.receive_data stanza
177
+ end
178
+ end
179
+
180
+ describe 'Blather::Client#write' do
181
+ before do
182
+ @client = Blather::Client.new
183
+ end
184
+
185
+ it 'writes to the stream' do
186
+ stanza = Blather::Stanza::Iq.new
187
+ stream = mock()
188
+ stream.expects(:send).with stanza
189
+ @client.setup('me@me.com', 'me')
190
+ @client.post_init stream, Blather::JID.new('me.com')
191
+ @client.write stanza
192
+ end
193
+ end
194
+
195
+ describe 'Blather::Client#status=' do
196
+ before do
197
+ @client = Blather::Client.new
198
+ @stream = mock()
199
+ @stream.stubs(:send)
200
+ @client.post_init @stream, Blather::JID.new('n@d/r')
201
+ end
202
+
203
+ it 'updates the state when not sending to a Blather::JID' do
204
+ @stream.stubs(:write)
205
+ @client.status.wont_equal :away
206
+ @client.status = :away, 'message'
207
+ @client.status.must_equal :away
208
+ end
209
+
210
+ it 'does not update the state when sending to a Blather::JID' do
211
+ @stream.stubs(:write)
212
+ @client.status.wont_equal :away
213
+ @client.status = :away, 'message', 'me@me.com'
214
+ @client.status.wont_equal :away
215
+ end
216
+
217
+ it 'writes the new status to the stream' do
218
+ Blather::Stanza::Presence::Status.stubs(:next_id).returns 0
219
+ status = [:away, 'message']
220
+ @stream.expects(:send).with do |s|
221
+ s.must_be_kind_of Blather::Stanza::Presence::Status
222
+ s.to_s.must_equal Blather::Stanza::Presence::Status.new(*status).to_s
223
+ end
224
+ @client.status = status
225
+ end
226
+ end
227
+
228
+ describe 'Blather::Client default handlers' do
229
+ before do
230
+ @client = Blather::Client.new
231
+ @stream = mock()
232
+ @stream.stubs(:send)
233
+ @client.post_init @stream, Blather::JID.new('n@d/r')
234
+ end
235
+
236
+ it 're-raises errors' do
237
+ err = Blather::BlatherError.new
238
+ lambda { @client.receive_data err }.must_raise Blather::BlatherError
239
+ end
240
+
241
+ # it 'responds to iq:get with a "service-unavailable" error' do
242
+ # get = Blather::Stanza::Iq.new :get
243
+ # err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
244
+ # @client.expects(:write).with err
245
+ # @client.receive_data get
246
+ # end
247
+
248
+ # it 'responds to iq:get with a "service-unavailable" error' do
249
+ # get = Blather::Stanza::Iq.new :get
250
+ # err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
251
+ # @client.expects(:write).with { |n| n.to_s.must_equal err.to_s }
252
+ # @client.receive_data get
253
+ # end
254
+
255
+ # it 'responds to iq:set with a "service-unavailable" error' do
256
+ # get = Blather::Stanza::Iq.new :set
257
+ # err = Blather::StanzaError.new(get, 'service-unavailable', :cancel).to_node
258
+ # @client.expects(:write).with { |n| n.to_s.must_equal err.to_s }
259
+ # @client.receive_data get
260
+ # end
261
+
262
+ it 'handles status changes by updating the roster if the status is from a Blather::JID in the roster' do
263
+ jid = 'friend@jabber.local'
264
+ status = Blather::Stanza::Presence::Status.new :away
265
+ status.stubs(:from).returns jid
266
+ roster_item = mock()
267
+ roster_item.expects(:status=).with status
268
+ @client.stubs(:roster).returns({status.from => roster_item})
269
+ @client.receive_data status
270
+ end
271
+
272
+ it 'lets status stanzas fall through to other handlers' do
273
+ jid = 'friend@jabber.local'
274
+ status = Blather::Stanza::Presence::Status.new :away
275
+ status.stubs(:from).returns jid
276
+ roster_item = mock()
277
+ roster_item.expects(:status=).with status
278
+ @client.stubs(:roster).returns({status.from => roster_item})
279
+
280
+ response = mock()
281
+ response.expects(:call).with jid
282
+ @client.register_handler(:status) { |s| response.call s.from.to_s }
283
+ @client.receive_data status
284
+ end
285
+
286
+ it 'handles an incoming roster node by processing it through the roster' do
287
+ roster = Blather::Stanza::Iq::Roster.new
288
+ client_roster = mock()
289
+ client_roster.expects(:process).with roster
290
+ @client.stubs(:roster).returns client_roster
291
+ @client.receive_data roster
292
+ end
293
+
294
+ it 'handles an incoming roster node by processing it through the roster' do
295
+ roster = Blather::Stanza::Iq::Roster.new
296
+ client_roster = mock()
297
+ client_roster.expects(:process).with roster
298
+ @client.stubs(:roster).returns client_roster
299
+
300
+ response = mock()
301
+ response.expects(:call)
302
+ @client.register_handler(:roster) { |_| response.call }
303
+ @client.receive_data roster
304
+ end
305
+ end
306
+
307
+ describe 'Blather::Client with a Component stream' do
308
+ before do
309
+ class MockComponent < Blather::Stream::Component; def initialize(); end; end
310
+ @stream = MockComponent.new('')
311
+ @stream.stubs(:send_data)
312
+ @client = Blather::Client.new
313
+ @client.setup('me.com', 'secret')
314
+ end
315
+
316
+ it 'calls the ready handler when sent post_init' do
317
+ ready = mock()
318
+ ready.expects(:call)
319
+ @client.register_handler(:ready) { ready.call }
320
+ @client.post_init @stream
321
+ end
322
+ end
323
+
324
+ describe 'Blather::Client with a Client stream' do
325
+ before do
326
+ class MockClientStream < Blather::Stream::Client; def initialize(); end; end
327
+ @stream = MockClientStream.new('')
328
+ @client = Blather::Client.new
329
+ Blather::Stream::Client.stubs(:start).returns @stream
330
+ @client.setup('me@me.com', 'secret').run
331
+ end
332
+
333
+ it 'sends a request for the roster when post_init is called' do
334
+ @stream.expects(:send).with { |stanza| stanza.must_be_kind_of Blather::Stanza::Iq::Roster }
335
+ @client.post_init @stream, Blather::JID.new('n@d/r')
336
+ end
337
+
338
+ it 'calls the ready handler after post_init and roster is received' do
339
+ result_roster = Blather::Stanza::Iq::Roster.new :result
340
+ @stream.stubs(:send).with { |s| result_roster.id = s.id; @client.receive_data result_roster; true }
341
+
342
+ ready = mock()
343
+ ready.expects(:call)
344
+ @client.register_handler(:ready) { ready.call }
345
+ @client.post_init @stream, Blather::JID.new('n@d/r')
346
+ end
347
+ end
348
+
349
+ describe 'Blather::Client filters' do
350
+ before do
351
+ @client = Blather::Client.new
352
+ @stream = mock()
353
+ @stream.stubs(:send)
354
+ @client.post_init @stream, Blather::JID.new('n@d/r')
355
+ end
356
+
357
+ it 'raises an error when an invalid filter type is registered' do
358
+ lambda { @client.register_filter(:invalid) {} }.must_raise RuntimeError
359
+ end
360
+
361
+ it 'can be guarded' do
362
+ stanza = Blather::Stanza::Iq.new
363
+ ready = mock()
364
+ ready.expects(:call).once
365
+ @client.register_filter(:before, :iq, :id => stanza.id) { |_| ready.call }
366
+ @client.register_filter(:before, :iq, :id => 'not-id') { |_| ready.call }
367
+ @client.receive_data stanza
368
+ end
369
+
370
+ it 'can pass to the next handler' do
371
+ stanza = Blather::Stanza::Iq.new
372
+ ready = mock()
373
+ ready.expects(:call).once
374
+ @client.register_filter(:before) { |_| throw :pass; ready.call }
375
+ @client.register_filter(:before) { |_| ready.call }
376
+ @client.receive_data stanza
377
+ end
378
+
379
+ it 'runs them in order' do
380
+ stanza = Blather::Stanza::Iq.new
381
+ count = 0
382
+ @client.register_filter(:before) { |_| count.must_equal 0; count = 1 }
383
+ @client.register_filter(:before) { |_| count.must_equal 1; count = 2 }
384
+ @client.register_handler(:iq) { |_| count.must_equal 2; count = 3 }
385
+ @client.register_filter(:after) { |_| count.must_equal 3; count = 4 }
386
+ @client.register_filter(:after) { |_| count.must_equal 4 }
387
+ @client.receive_data stanza
388
+ end
389
+
390
+ it 'can modify the stanza' do
391
+ stanza = Blather::Stanza::Iq.new
392
+ stanza.from = 'from@test.local'
393
+ new_jid = 'before@filter.local'
394
+ ready = mock()
395
+ ready.expects(:call).with new_jid
396
+ @client.register_filter(:before) { |s| s.from = new_jid }
397
+ @client.register_handler(:iq) { |s| ready.call s.from.to_s }
398
+ @client.receive_data stanza
399
+ end
400
+
401
+ it 'can halt the handler chain' do
402
+ stanza = Blather::Stanza::Iq.new
403
+ ready = mock()
404
+ ready.expects(:call).never
405
+ @client.register_filter(:before) { |_| throw :halt }
406
+ @client.register_handler(:iq) { |_| ready.call }
407
+ @client.receive_data stanza
408
+ end
409
+
410
+ it 'can be specific to a handler' do
411
+ stanza = Blather::Stanza::Iq.new
412
+ ready = mock()
413
+ ready.expects(:call).once
414
+ @client.register_filter(:before, :iq) { |_| ready.call }
415
+ @client.register_filter(:before, :message) { |_| ready.call }
416
+ @client.receive_data stanza
417
+ end
418
+ end
419
+
420
+ describe 'Blather::Client guards' do
421
+ before do
422
+ stream = mock()
423
+ stream.stubs(:send)
424
+ @client = Blather::Client.new
425
+ @client.post_init stream, Blather::JID.new('n@d/r')
426
+ @stanza = Blather::Stanza::Iq.new
427
+ @response = mock()
428
+ end
429
+
430
+ it 'can be a symbol' do
431
+ @response.expects :call
432
+ @client.register_handler(:iq, :chat?) { |_| @response.call }
433
+
434
+ @stanza.expects(:chat?).returns true
435
+ @client.receive_data @stanza
436
+
437
+ @stanza.expects(:chat?).returns false
438
+ @client.receive_data @stanza
439
+ end
440
+
441
+ it 'can be a hash with string match' do
442
+ @response.expects :call
443
+ @client.register_handler(:iq, :body => 'exit') { |_| @response.call }
444
+
445
+ @stanza.expects(:body).returns 'exit'
446
+ @client.receive_data @stanza
447
+
448
+ @stanza.expects(:body).returns 'not-exit'
449
+ @client.receive_data @stanza
450
+ end
451
+
452
+ it 'can be a hash with a value' do
453
+ @response.expects :call
454
+ @client.register_handler(:iq, :number => 0) { |_| @response.call }
455
+
456
+ @stanza.expects(:number).returns 0
457
+ @client.receive_data @stanza
458
+
459
+ @stanza.expects(:number).returns 1
460
+ @client.receive_data @stanza
461
+ end
462
+
463
+ it 'can be a hash with a regexp' do
464
+ @response.expects :call
465
+ @client.register_handler(:iq, :body => /exit/) { |_| @response.call }
466
+
467
+ @stanza.expects(:body).returns 'more than just exit, but exit still'
468
+ @client.receive_data @stanza
469
+
470
+ @stanza.expects(:body).returns 'keyword not found'
471
+ @client.receive_data @stanza
472
+
473
+ @stanza.expects(:body).returns nil
474
+ @client.receive_data @stanza
475
+ end
476
+
477
+ it 'can be a hash with an array' do
478
+ @response.expects(:call).times(2)
479
+ @client.register_handler(:iq, :type => [:result, :error]) { |_| @response.call }
480
+
481
+ stanza = Blather::Stanza::Iq.new
482
+ stanza.expects(:type).at_least_once.returns :result
483
+ @client.receive_data stanza
484
+
485
+ stanza = Blather::Stanza::Iq.new
486
+ stanza.expects(:type).at_least_once.returns :error
487
+ @client.receive_data stanza
488
+
489
+ stanza = Blather::Stanza::Iq.new
490
+ stanza.expects(:type).at_least_once.returns :get
491
+ @client.receive_data stanza
492
+ end
493
+
494
+ it 'chained are treated like andand (short circuited)' do
495
+ @response.expects :call
496
+ @client.register_handler(:iq, :type => :get, :body => 'test') { |_| @response.call }
497
+
498
+ stanza = Blather::Stanza::Iq.new
499
+ stanza.expects(:type).at_least_once.returns :get
500
+ stanza.expects(:body).returns 'test'
501
+ @client.receive_data stanza
502
+
503
+ stanza = Blather::Stanza::Iq.new
504
+ stanza.expects(:type).at_least_once.returns :set
505
+ stanza.expects(:body).never
506
+ @client.receive_data stanza
507
+ end
508
+
509
+ it 'within an Array are treated as oror (short circuited)' do
510
+ @response.expects(:call).times 2
511
+ @client.register_handler(:iq, [{:type => :get}, {:body => 'test'}]) { |_| @response.call }
512
+
513
+ stanza = Blather::Stanza::Iq.new
514
+ stanza.expects(:type).at_least_once.returns :set
515
+ stanza.expects(:body).returns 'test'
516
+ @client.receive_data stanza
517
+
518
+ stanza = Blather::Stanza::Iq.new
519
+ stanza.stubs(:type).at_least_once.returns :get
520
+ stanza.expects(:body).never
521
+ @client.receive_data stanza
522
+ end
523
+
524
+ it 'can be a lambda' do
525
+ @response.expects :call
526
+ @client.register_handler(:iq, lambda { |s| s.number % 3 == 0 }) { |_| @response.call }
527
+
528
+ @stanza.expects(:number).at_least_once.returns 3
529
+ @client.receive_data @stanza
530
+
531
+ @stanza.expects(:number).at_least_once.returns 2
532
+ @client.receive_data @stanza
533
+ end
534
+
535
+ it 'can be an xpath and will send the result to the handler' do
536
+ @response.expects(:call).with do |stanza, xpath|
537
+ xpath.must_be_instance_of Nokogiri::XML::NodeSet
538
+ xpath.wont_be_empty
539
+ stanza.must_equal @stanza
540
+ end
541
+ @client.register_handler(:iq, "/iq[@id='#{@stanza.id}']") { |stanza, xpath| @response.call stanza, xpath }
542
+ @client.receive_data @stanza
543
+ end
544
+
545
+ it 'can be an xpath with namespaces and will send the result to the handler' do
546
+ @stanza = Blather::Stanza.import(parse_stanza('<message><foo xmlns="http://bar.com"></message>').root)
547
+ @response.expects(:call).with do |stanza, xpath|
548
+ xpath.must_be_instance_of Nokogiri::XML::NodeSet
549
+ xpath.wont_be_empty
550
+ stanza.must_equal @stanza
551
+ end
552
+ @client.register_handler(:message, "/message/bar:foo", :bar => 'http://bar.com') { |stanza, xpath| @response.call stanza, xpath }
553
+ @client.receive_data @stanza
554
+ end
555
+
556
+ it 'raises an error when a bad guard is tried' do
557
+ lambda { @client.register_handler(:iq, 0) {} }.must_raise RuntimeError
558
+ end
559
+ end