tp-blather 0.8.2

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 (150) hide show
  1. data/.autotest +13 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +8 -0
  6. data/CHANGELOG.md +249 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +5 -0
  9. data/LICENSE +22 -0
  10. data/README.md +413 -0
  11. data/Rakefile +20 -0
  12. data/TODO.md +2 -0
  13. data/blather.gemspec +51 -0
  14. data/examples/certs/README +20 -0
  15. data/examples/certs/ca-bundle.crt +3987 -0
  16. data/examples/echo.rb +19 -0
  17. data/examples/execute.rb +17 -0
  18. data/examples/ping_pong.rb +38 -0
  19. data/examples/print_hierarchy.rb +77 -0
  20. data/examples/rosterprint.rb +15 -0
  21. data/examples/stream_only.rb +28 -0
  22. data/examples/trusted_echo.rb +21 -0
  23. data/examples/xmpp4r/echo.rb +36 -0
  24. data/lib/blather.rb +112 -0
  25. data/lib/blather/cert_store.rb +53 -0
  26. data/lib/blather/client.rb +95 -0
  27. data/lib/blather/client/client.rb +345 -0
  28. data/lib/blather/client/dsl.rb +320 -0
  29. data/lib/blather/client/dsl/pubsub.rb +174 -0
  30. data/lib/blather/core_ext/eventmachine.rb +125 -0
  31. data/lib/blather/core_ext/ipaddr.rb +20 -0
  32. data/lib/blather/errors.rb +69 -0
  33. data/lib/blather/errors/sasl_error.rb +44 -0
  34. data/lib/blather/errors/stanza_error.rb +110 -0
  35. data/lib/blather/errors/stream_error.rb +84 -0
  36. data/lib/blather/file_transfer.rb +107 -0
  37. data/lib/blather/file_transfer/ibb.rb +68 -0
  38. data/lib/blather/file_transfer/s5b.rb +114 -0
  39. data/lib/blather/jid.rb +141 -0
  40. data/lib/blather/roster.rb +118 -0
  41. data/lib/blather/roster_item.rb +146 -0
  42. data/lib/blather/stanza.rb +167 -0
  43. data/lib/blather/stanza/disco.rb +32 -0
  44. data/lib/blather/stanza/disco/capabilities.rb +161 -0
  45. data/lib/blather/stanza/disco/disco_info.rb +205 -0
  46. data/lib/blather/stanza/disco/disco_items.rb +134 -0
  47. data/lib/blather/stanza/iq.rb +144 -0
  48. data/lib/blather/stanza/iq/command.rb +339 -0
  49. data/lib/blather/stanza/iq/ibb.rb +86 -0
  50. data/lib/blather/stanza/iq/ping.rb +50 -0
  51. data/lib/blather/stanza/iq/query.rb +53 -0
  52. data/lib/blather/stanza/iq/roster.rb +185 -0
  53. data/lib/blather/stanza/iq/s5b.rb +208 -0
  54. data/lib/blather/stanza/iq/si.rb +415 -0
  55. data/lib/blather/stanza/iq/vcard.rb +149 -0
  56. data/lib/blather/stanza/message.rb +428 -0
  57. data/lib/blather/stanza/message/muc_user.rb +119 -0
  58. data/lib/blather/stanza/muc/muc_user_base.rb +54 -0
  59. data/lib/blather/stanza/presence.rb +172 -0
  60. data/lib/blather/stanza/presence/c.rb +100 -0
  61. data/lib/blather/stanza/presence/muc.rb +35 -0
  62. data/lib/blather/stanza/presence/muc_user.rb +147 -0
  63. data/lib/blather/stanza/presence/status.rb +218 -0
  64. data/lib/blather/stanza/presence/subscription.rb +100 -0
  65. data/lib/blather/stanza/pubsub.rb +119 -0
  66. data/lib/blather/stanza/pubsub/affiliations.rb +79 -0
  67. data/lib/blather/stanza/pubsub/create.rb +65 -0
  68. data/lib/blather/stanza/pubsub/errors.rb +18 -0
  69. data/lib/blather/stanza/pubsub/event.rb +139 -0
  70. data/lib/blather/stanza/pubsub/items.rb +103 -0
  71. data/lib/blather/stanza/pubsub/publish.rb +103 -0
  72. data/lib/blather/stanza/pubsub/retract.rb +92 -0
  73. data/lib/blather/stanza/pubsub/subscribe.rb +68 -0
  74. data/lib/blather/stanza/pubsub/subscription.rb +135 -0
  75. data/lib/blather/stanza/pubsub/subscriptions.rb +83 -0
  76. data/lib/blather/stanza/pubsub/unsubscribe.rb +84 -0
  77. data/lib/blather/stanza/pubsub_owner.rb +51 -0
  78. data/lib/blather/stanza/pubsub_owner/delete.rb +52 -0
  79. data/lib/blather/stanza/pubsub_owner/purge.rb +52 -0
  80. data/lib/blather/stanza/x.rb +416 -0
  81. data/lib/blather/stream.rb +266 -0
  82. data/lib/blather/stream/client.rb +32 -0
  83. data/lib/blather/stream/component.rb +39 -0
  84. data/lib/blather/stream/features.rb +70 -0
  85. data/lib/blather/stream/features/register.rb +38 -0
  86. data/lib/blather/stream/features/resource.rb +63 -0
  87. data/lib/blather/stream/features/sasl.rb +190 -0
  88. data/lib/blather/stream/features/session.rb +45 -0
  89. data/lib/blather/stream/features/tls.rb +29 -0
  90. data/lib/blather/stream/parser.rb +102 -0
  91. data/lib/blather/version.rb +3 -0
  92. data/lib/blather/xmpp_node.rb +94 -0
  93. data/spec/blather/client/client_spec.rb +687 -0
  94. data/spec/blather/client/dsl/pubsub_spec.rb +492 -0
  95. data/spec/blather/client/dsl_spec.rb +266 -0
  96. data/spec/blather/errors/sasl_error_spec.rb +33 -0
  97. data/spec/blather/errors/stanza_error_spec.rb +129 -0
  98. data/spec/blather/errors/stream_error_spec.rb +108 -0
  99. data/spec/blather/errors_spec.rb +33 -0
  100. data/spec/blather/file_transfer_spec.rb +135 -0
  101. data/spec/blather/jid_spec.rb +87 -0
  102. data/spec/blather/roster_item_spec.rb +134 -0
  103. data/spec/blather/roster_spec.rb +107 -0
  104. data/spec/blather/stanza/discos/disco_info_spec.rb +247 -0
  105. data/spec/blather/stanza/discos/disco_items_spec.rb +154 -0
  106. data/spec/blather/stanza/iq/command_spec.rb +206 -0
  107. data/spec/blather/stanza/iq/ibb_spec.rb +124 -0
  108. data/spec/blather/stanza/iq/ping_spec.rb +45 -0
  109. data/spec/blather/stanza/iq/query_spec.rb +64 -0
  110. data/spec/blather/stanza/iq/roster_spec.rb +139 -0
  111. data/spec/blather/stanza/iq/s5b_spec.rb +57 -0
  112. data/spec/blather/stanza/iq/si_spec.rb +98 -0
  113. data/spec/blather/stanza/iq/vcard_spec.rb +93 -0
  114. data/spec/blather/stanza/iq_spec.rb +61 -0
  115. data/spec/blather/stanza/message/muc_user_spec.rb +152 -0
  116. data/spec/blather/stanza/message_spec.rb +282 -0
  117. data/spec/blather/stanza/presence/c_spec.rb +56 -0
  118. data/spec/blather/stanza/presence/muc_spec.rb +37 -0
  119. data/spec/blather/stanza/presence/muc_user_spec.rb +83 -0
  120. data/spec/blather/stanza/presence/status_spec.rb +144 -0
  121. data/spec/blather/stanza/presence/subscription_spec.rb +102 -0
  122. data/spec/blather/stanza/presence_spec.rb +125 -0
  123. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  124. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  125. data/spec/blather/stanza/pubsub/event_spec.rb +98 -0
  126. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  127. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  128. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  129. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  130. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  131. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  132. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +74 -0
  133. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  134. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  135. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  136. data/spec/blather/stanza/pubsub_spec.rb +68 -0
  137. data/spec/blather/stanza/x_spec.rb +231 -0
  138. data/spec/blather/stanza_spec.rb +134 -0
  139. data/spec/blather/stream/client_spec.rb +1090 -0
  140. data/spec/blather/stream/component_spec.rb +108 -0
  141. data/spec/blather/stream/parser_spec.rb +152 -0
  142. data/spec/blather/stream/ssl_spec.rb +32 -0
  143. data/spec/blather/xmpp_node_spec.rb +47 -0
  144. data/spec/blather_spec.rb +34 -0
  145. data/spec/fixtures/pubsub.rb +311 -0
  146. data/spec/spec_helper.rb +17 -0
  147. data/yard/templates/default/class/html/handlers.erb +18 -0
  148. data/yard/templates/default/class/setup.rb +10 -0
  149. data/yard/templates/default/class/text/handlers.erb +1 -0
  150. metadata +459 -0
@@ -0,0 +1,247 @@
1
+ require 'spec_helper'
2
+
3
+ def disco_info_xml
4
+ <<-XML
5
+ <iq type='result'
6
+ from='romeo@montague.net/orchard'
7
+ to='juliet@capulet.com/balcony'
8
+ id='info4'>
9
+ <query xmlns='http://jabber.org/protocol/disco#info'>
10
+ <identity
11
+ category='client'
12
+ type='pc'
13
+ name='Gabber'
14
+ xml:lang='en'/>
15
+ <feature var='jabber:iq:time'/>
16
+ <feature var='jabber:iq:version'/>
17
+ </query>
18
+ </iq>
19
+ XML
20
+ end
21
+
22
+ describe Blather::Stanza::Iq::DiscoInfo do
23
+ it 'registers itself' do
24
+ Blather::XMPPNode.class_from_registration(:query, 'http://jabber.org/protocol/disco#info').should == Blather::Stanza::Iq::DiscoInfo
25
+ end
26
+
27
+ it 'must be importable' do
28
+ Blather::XMPPNode.parse(disco_info_xml).should be_instance_of Blather::Stanza::Iq::DiscoInfo
29
+ end
30
+
31
+ it 'has a node attribute' do
32
+ n = Blather::Stanza::Iq::DiscoInfo.new nil, 'music', [], []
33
+ n.node.should == 'music'
34
+ n.node = :foo
35
+ n.node.should == 'foo'
36
+ end
37
+
38
+ it 'inherits a list of identities' do
39
+ n = parse_stanza disco_info_xml
40
+ r = Blather::Stanza::Iq::DiscoInfo.new.inherit n.root
41
+ r.identities.size.should == 1
42
+ r.identities.map { |i| i.class }.uniq.should == [Blather::Stanza::Iq::DiscoInfo::Identity]
43
+ end
44
+
45
+ it 'inherits a list of features' do
46
+ n = parse_stanza disco_info_xml
47
+ r = Blather::Stanza::Iq::DiscoInfo.new.inherit n.root
48
+ r.features.size.should == 2
49
+ r.features.map { |i| i.class }.uniq.should == [Blather::Stanza::Iq::DiscoInfo::Feature]
50
+ end
51
+
52
+ it 'is constructed properly' do
53
+ n = Blather::Stanza::Iq::DiscoInfo.new :get, '/path/to/node'
54
+ n.to = 'to@jid.com'
55
+ n.find("/iq[@to='to@jid.com' and @type='get' and @id='#{n.id}']/ns:query[@node='/path/to/node']", :ns => Blather::Stanza::Iq::DiscoInfo.registered_ns).should_not be_empty
56
+ end
57
+
58
+ it 'allows adding of identities' do
59
+ di = Blather::Stanza::Iq::DiscoInfo.new
60
+ di.identities.size.should == 0
61
+ di.identities = [{:name => 'name', :type => 'type', :category => 'category'}]
62
+ di.identities.size.should == 1
63
+ di.identities += [Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
64
+ di.identities.size.should == 2
65
+ di.identities = nil
66
+ di.identities.size.should == 0
67
+ end
68
+
69
+ it 'allows adding of features' do
70
+ di = Blather::Stanza::Iq::DiscoInfo.new
71
+ di.features.size.should == 0
72
+ di.features = ["feature1"]
73
+ di.features.size.should == 1
74
+ di.features += [Blather::Stanza::Iq::DiscoInfo::Feature.new("feature2")]
75
+ di.features.size.should == 2
76
+ di.features = nil
77
+ di.features.size.should == 0
78
+ end
79
+
80
+ end
81
+
82
+ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
83
+ it 'takes a list of hashes for identities' do
84
+ ids = [
85
+ {:name => 'name', :type => 'type', :category => 'category'},
86
+ {:name => 'name1', :type => 'type1', :category => 'category1'},
87
+ ]
88
+
89
+ control = [ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
90
+ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
91
+
92
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, ids
93
+ di.identities.size.should == 2
94
+ di.identities.each { |i| control.include?(i).should == true }
95
+ end
96
+
97
+ it 'takes a list of Identity objects as identities' do
98
+ control = [ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
99
+ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
100
+
101
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, control
102
+ di.identities.size.should == 2
103
+ di.identities.each { |i| control.include?(i).should == true }
104
+ end
105
+
106
+ it 'takes a single hash as identity' do
107
+ control = [Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
108
+
109
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, {:name => 'name', :type => 'type', :category => 'category'}
110
+ di.identities.size.should == 1
111
+ di.identities.each { |i| control.include?(i).should == true }
112
+ end
113
+
114
+ it 'takes a single identity object as identity' do
115
+ control = [Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
116
+
117
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, control.first
118
+ di.identities.size.should == 1
119
+ di.identities.each { |i| control.include?(i).should == true }
120
+ end
121
+
122
+ it 'takes a mix of hashes and identity objects as identities' do
123
+ ids = [
124
+ {:name => 'name', :type => 'type', :category => 'category'},
125
+ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1]),
126
+ ]
127
+
128
+ control = [ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
129
+ Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
130
+
131
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, ids
132
+ di.identities.size.should == 2
133
+ di.identities.each { |i| control.include?(i).should == true }
134
+ end
135
+ end
136
+
137
+ describe 'Blather::Stanza::Iq::DiscoInfo features' do
138
+ it 'takes a list of features as strings' do
139
+ features = %w[feature1 feature2 feature3]
140
+ control = features.map { |f| Blather::Stanza::Iq::DiscoInfo::Feature.new f }
141
+
142
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, [], features
143
+ di.features.size.should == 3
144
+ di.features.each { |f| control.include?(f).should == true }
145
+ end
146
+
147
+ it 'takes a list of features as Feature objects' do
148
+ features = %w[feature1 feature2 feature3]
149
+ control = features.map { |f| Blather::Stanza::Iq::DiscoInfo::Feature.new f }
150
+
151
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, [], control
152
+ di.features.size.should == 3
153
+ di.features.each { |f| control.include?(f).should == true }
154
+ end
155
+
156
+ it 'takes a single string' do
157
+ control = [Blather::Stanza::Iq::DiscoInfo::Feature.new('feature1')]
158
+
159
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, [], 'feature1'
160
+ di.features.size.should == 1
161
+ di.features.each { |f| control.include?(f).should == true }
162
+ end
163
+
164
+ it 'takes a single Feature object' do
165
+ control = [Blather::Stanza::Iq::DiscoInfo::Feature.new('feature1')]
166
+
167
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, [], control.first
168
+ di.features.size.should == 1
169
+ di.features.each { |f| control.include?(f).should == true }
170
+ end
171
+
172
+ it 'takes a mixed list of features as Feature objects and strings' do
173
+ features = %w[feature1 feature2 feature3]
174
+ control = features.map { |f| Blather::Stanza::Iq::DiscoInfo::Feature.new f }
175
+ features[1] = control[1]
176
+
177
+ di = Blather::Stanza::Iq::DiscoInfo.new nil, nil, [], features
178
+ di.features.size.should == 3
179
+ di.features.each { |f| control.include?(f).should == true }
180
+ end
181
+ end
182
+
183
+ describe Blather::Stanza::Iq::DiscoInfo::Identity do
184
+ it 'will auto-inherit nodes' do
185
+ n = parse_stanza "<identity name='Personal Events' type='pep' category='pubsub' node='publish' xml:lang='en' />"
186
+ i = Blather::Stanza::Iq::DiscoInfo::Identity.new n.root
187
+ i.name.should == 'Personal Events'
188
+ i.type.should == :pep
189
+ i.category.should == :pubsub
190
+ i.xml_lang.should == 'en'
191
+ end
192
+
193
+ it 'has a category attribute' do
194
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
195
+ n.category.should == :cat
196
+ n.category = :foo
197
+ n.category.should == :foo
198
+ end
199
+
200
+ it 'has a type attribute' do
201
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
202
+ n.type.should == :type
203
+ n.type = :foo
204
+ n.type.should == :foo
205
+ end
206
+
207
+ it 'has a name attribute' do
208
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
209
+ n.name.should == 'name'
210
+ n.name = :foo
211
+ n.name.should == 'foo'
212
+ end
213
+
214
+ it 'has an xml:lang attribute' do
215
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat en])
216
+ n.xml_lang.should == 'en'
217
+ n.xml_lang = 'de'
218
+ n.xml_lang.should == 'de'
219
+ end
220
+
221
+ it 'can determine equality' do
222
+ a = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
223
+ a.should == Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
224
+ a.should_not equal Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[not-name not-type not-cat])
225
+ end
226
+ end
227
+
228
+ describe Blather::Stanza::Iq::DiscoInfo::Feature do
229
+ it 'will auto-inherit nodes' do
230
+ n = parse_stanza "<feature var='ipv6' />"
231
+ i = Blather::Stanza::Iq::DiscoInfo::Feature.new n.root
232
+ i.var.should == 'ipv6'
233
+ end
234
+
235
+ it 'has a var attribute' do
236
+ n = Blather::Stanza::Iq::DiscoInfo::Feature.new 'var'
237
+ n.var.should == 'var'
238
+ n.var = :foo
239
+ n.var.should == 'foo'
240
+ end
241
+
242
+ it 'can determine equality' do
243
+ a = Blather::Stanza::Iq::DiscoInfo::Feature.new('var')
244
+ a.should == Blather::Stanza::Iq::DiscoInfo::Feature.new('var')
245
+ a.should_not equal Blather::Stanza::Iq::DiscoInfo::Feature.new('not-var')
246
+ end
247
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ def disco_items_xml
4
+ <<-XML
5
+ <iq type='result'
6
+ from='catalog.shakespeare.lit'
7
+ to='romeo@montague.net/orchard'
8
+ id='items2'>
9
+ <query xmlns='http://jabber.org/protocol/disco#items'>
10
+ <item jid='catalog.shakespeare.lit'
11
+ node='books'
12
+ name='Books by and about Shakespeare'/>
13
+ <item jid='catalog.shakespeare.lit'
14
+ node='clothing'
15
+ name='Wear your literary taste with pride'/>
16
+ <item jid='catalog.shakespeare.lit'
17
+ node='music'
18
+ name='Music from the time of Shakespeare'/>
19
+ </query>
20
+ </iq>
21
+ XML
22
+ end
23
+
24
+ describe Blather::Stanza::Iq::DiscoItems do
25
+ it 'registers itself' do
26
+ Blather::XMPPNode.class_from_registration(:query, 'http://jabber.org/protocol/disco#items').should == Blather::Stanza::Iq::DiscoItems
27
+ end
28
+
29
+ it 'must be importable' do
30
+ Blather::XMPPNode.parse(disco_items_xml).should be_instance_of Blather::Stanza::Iq::DiscoItems
31
+ end
32
+
33
+ it 'is constructed properly' do
34
+ n = Blather::Stanza::Iq::DiscoItems.new :get, '/path/to/node'
35
+ n.to = 'to@jid.com'
36
+ n.find("/iq[@to='to@jid.com' and @type='get' and @id='#{n.id}']/ns:query[@node='/path/to/node']", :ns => Blather::Stanza::Iq::DiscoItems.registered_ns).should_not be_empty
37
+ end
38
+
39
+ it 'has a node attribute' do
40
+ n = Blather::Stanza::Iq::DiscoItems.new nil, 'music', []
41
+ n.node.should == 'music'
42
+ n.node = :foo
43
+ n.node.should == 'foo'
44
+ end
45
+
46
+ it 'inherits a list of identities' do
47
+ n = parse_stanza disco_items_xml
48
+ r = Blather::Stanza::Iq::DiscoItems.new.inherit n.root
49
+ r.items.size.should == 3
50
+ r.items.map { |i| i.class }.uniq.should == [Blather::Stanza::Iq::DiscoItems::Item]
51
+ end
52
+
53
+ it 'takes a list of hashes for items' do
54
+ items = [
55
+ {:jid => 'foo@bar/baz', :node => 'node', :name => 'name'},
56
+ {:jid => 'baz@foo/bar', :node => 'node1', :name => 'name1'},
57
+ ]
58
+
59
+ control = [ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name]),
60
+ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1])]
61
+
62
+ di = Blather::Stanza::Iq::DiscoItems.new nil, nil, items
63
+ di.items.size.should == 2
64
+ di.items.each { |i| control.include?(i).should == true }
65
+ end
66
+
67
+ it 'takes a list of Item objects as items' do
68
+ control = [ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name]),
69
+ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1])]
70
+
71
+ di = Blather::Stanza::Iq::DiscoItems.new nil, nil, control
72
+ di.items.size.should == 2
73
+ di.items.each { |i| control.include?(i).should == true }
74
+ end
75
+
76
+ it 'takes a single hash as identity' do
77
+ control = [Blather::Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name])]
78
+
79
+ di = Blather::Stanza::Iq::DiscoItems.new nil, nil, {:jid => 'foo@bar/baz', :node => 'node', :name => 'name'}
80
+ di.items.size.should == 1
81
+ di.items.each { |i| control.include?(i).should == true }
82
+ end
83
+
84
+ it 'takes a single identity object as identity' do
85
+ control = [Blather::Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name])]
86
+
87
+ di = Blather::Stanza::Iq::DiscoItems.new nil, nil, control.first
88
+ di.items.size.should == 1
89
+ di.items.each { |i| control.include?(i).should == true }
90
+ end
91
+
92
+ it 'takes a mix of hashes and identity objects as items' do
93
+ items = [
94
+ {:jid => 'foo@bar/baz', :node => 'node', :name => 'name'},
95
+ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1]),
96
+ ]
97
+
98
+ control = [ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name]),
99
+ Blather::Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1])]
100
+
101
+ di = Blather::Stanza::Iq::DiscoItems.new nil, nil, items
102
+ di.items.size.should == 2
103
+ di.items.each { |i| control.include?(i).should == true }
104
+ end
105
+
106
+ it 'allows adding of items' do
107
+ di = Blather::Stanza::Iq::DiscoItems.new
108
+ di.items.size.should == 0
109
+ di.items = [{:jid => 'foo@bar/baz', :node => 'node', :name => 'name'}]
110
+ di.items.size.should == 1
111
+ di.items += [Blather::Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name])]
112
+ di.items.size.should == 2
113
+ di.items = nil
114
+ di.items.size.should == 0
115
+ end
116
+ end
117
+
118
+ describe Blather::Stanza::Iq::DiscoItems::Item do
119
+ it 'will auto-inherit nodes' do
120
+ n = parse_stanza "<item jid='foo@bar/baz' node='music' name='Music from the time of Shakespeare' />"
121
+ i = Blather::Stanza::Iq::DiscoItems::Item.new n.root
122
+ i.jid.should == Blather::JID.new('foo@bar/baz')
123
+ i.node.should == 'music'
124
+ i.name.should == 'Music from the time of Shakespeare'
125
+ end
126
+
127
+ it 'has a jid attribute' do
128
+ n = Blather::Stanza::Iq::DiscoItems::Item.new 'foo@bar/baz'
129
+ n.jid.should be_kind_of Blather::JID
130
+ n.jid.should == Blather::JID.new('foo@bar/baz')
131
+ n.jid = 'baz@foo/bar'
132
+ n.jid.should == Blather::JID.new('baz@foo/bar')
133
+ end
134
+
135
+ it 'has a node attribute' do
136
+ n = Blather::Stanza::Iq::DiscoItems::Item.new 'foo@bar/baz', 'music'
137
+ n.node.should == 'music'
138
+ n.node = 'book'
139
+ n.node.should == 'book'
140
+ end
141
+
142
+ it 'has a name attribute' do
143
+ n = Blather::Stanza::Iq::DiscoItems::Item.new 'foo@bar/baz', nil, 'Music from the time of Shakespeare'
144
+ n.name.should == 'Music from the time of Shakespeare'
145
+ n.name = 'Books by and about Shakespeare'
146
+ n.name.should == 'Books by and about Shakespeare'
147
+ end
148
+
149
+ it 'can determine equality' do
150
+ a = Blather::Stanza::Iq::DiscoItems::Item.new('foo@bar/baz')
151
+ a.should == Blather::Stanza::Iq::DiscoItems::Item.new('foo@bar/baz')
152
+ a.should_not equal Blather::Stanza::Iq::DiscoItems::Item.new('not-foo@bar/baz')
153
+ end
154
+ end
@@ -0,0 +1,206 @@
1
+ require 'spec_helper'
2
+
3
+ def command_xml
4
+ <<-XML
5
+ <iq type='result'
6
+ from='catalog.shakespeare.lit'
7
+ to='romeo@montague.net/orchard'
8
+ id='form2'>
9
+ <command xmlns='http://jabber.org/protocol/commands'
10
+ node='node1'
11
+ sessionid='dqjiodmqlmakm'>
12
+ <x xmlns='jabber:x:data' type='form'>
13
+ <field var='field-name' type='text-single' label='description' />
14
+ </x>
15
+ </command>
16
+ </iq>
17
+ XML
18
+ end
19
+
20
+ describe Blather::Stanza::Iq::Command do
21
+ it 'registers itself' do
22
+ Blather::XMPPNode.class_from_registration(:command, 'http://jabber.org/protocol/commands').should == Blather::Stanza::Iq::Command
23
+ end
24
+
25
+ it 'must be importable' do
26
+ Blather::XMPPNode.parse(command_xml).should be_instance_of Blather::Stanza::Iq::Command
27
+ end
28
+
29
+ it 'ensures a command node is present on create' do
30
+ c = Blather::Stanza::Iq::Command.new
31
+ c.xpath('xmlns:command', :xmlns => Blather::Stanza::Iq::Command.registered_ns).should_not be_empty
32
+ end
33
+
34
+ it 'ensures a command node exists when calling #command' do
35
+ c = Blather::Stanza::Iq::Command.new
36
+ c.remove_children :command
37
+ c.xpath('ns:command', :ns => Blather::Stanza::Iq::Command.registered_ns).should be_empty
38
+
39
+ c.command.should_not be_nil
40
+ c.xpath('ns:command', :ns => Blather::Stanza::Iq::Command.registered_ns).should_not be_empty
41
+ end
42
+
43
+ Blather::Stanza::Iq::Command::VALID_ACTIONS.each do |valid_action|
44
+ it "provides a helper (#{valid_action}?) for action #{valid_action}" do
45
+ Blather::Stanza::Iq::Command.new.should respond_to :"#{valid_action}?"
46
+ end
47
+ end
48
+
49
+ Blather::Stanza::Iq::Command::VALID_STATUS.each do |valid_status|
50
+ it "provides a helper (#{valid_status}?) for status #{valid_status}" do
51
+ Blather::Stanza::Iq::Command.new.should respond_to :"#{valid_status}?"
52
+ end
53
+ end
54
+
55
+ Blather::Stanza::Iq::Command::VALID_NOTE_TYPES.each do |valid_note_type|
56
+ it "provides a helper (#{valid_note_type}?) for note_type #{valid_note_type}" do
57
+ Blather::Stanza::Iq::Command.new.should respond_to :"#{valid_note_type}?"
58
+ end
59
+ end
60
+
61
+ [:cancel, :execute, :complete, :next, :prev].each do |action|
62
+ it "action can be set as \"#{action}\"" do
63
+ c = Blather::Stanza::Iq::Command.new nil, nil, action
64
+ c.action.should == action
65
+ end
66
+ end
67
+
68
+ [:get, :set, :result, :error].each do |type|
69
+ it "can be set as \"#{type}\"" do
70
+ c = Blather::Stanza::Iq::Command.new type
71
+ c.type.should == type
72
+ end
73
+ end
74
+
75
+ it 'sets type to "result" on reply' do
76
+ c = Blather::Stanza::Iq::Command.new
77
+ c.type.should == :set
78
+ reply = c.reply.type.should == :result
79
+ end
80
+
81
+ it 'sets type to "result" on reply!' do
82
+ c = Blather::Stanza::Iq::Command.new
83
+ c.type.should == :set
84
+ c.reply!
85
+ c.type.should == :result
86
+ end
87
+
88
+ it 'removes action on reply' do
89
+ c = Blather::XMPPNode.parse command_xml
90
+ c.action.should == :execute
91
+ c.reply.action.should == nil
92
+ end
93
+
94
+ it 'removes action on reply!' do
95
+ c = Blather::XMPPNode.parse command_xml
96
+ c.action.should == :execute
97
+ c.reply!
98
+ c.action.should == nil
99
+ end
100
+
101
+ it 'can be registered under a namespace' do
102
+ class CommandNs < Blather::Stanza::Iq::Command; register :command_ns, nil, 'command:ns'; end
103
+ Blather::XMPPNode.class_from_registration(:command, 'command:ns').should == CommandNs
104
+ c_ns = CommandNs.new
105
+ c_ns.xpath('command').should be_empty
106
+ c_ns.xpath('ns:command', :ns => 'command:ns').size.should == 1
107
+
108
+ c_ns.command
109
+ c_ns.command
110
+ c_ns.xpath('ns:command', :ns => 'command:ns').size.should == 1
111
+ end
112
+
113
+ it 'is constructed properly' do
114
+ n = Blather::Stanza::Iq::Command.new :set, "node", :execute
115
+ n.to = 'to@jid.com'
116
+ n.find("/iq[@to='to@jid.com' and @type='set' and @id='#{n.id}']/ns:command[@node='node' and @action='execute']", :ns => Blather::Stanza::Iq::Command.registered_ns).should_not be_empty
117
+ end
118
+
119
+ it 'has an action attribute' do
120
+ n = Blather::Stanza::Iq::Command.new
121
+ n.action.should == :execute
122
+ n.action = :cancel
123
+ n.action.should == :cancel
124
+ end
125
+
126
+ it 'must default action to :execute on import' do
127
+ n = Blather::XMPPNode.parse(command_xml)
128
+ n.action.should == :execute
129
+ end
130
+
131
+ it 'has a status attribute' do
132
+ n = Blather::Stanza::Iq::Command.new
133
+ n.status.should == :executing
134
+ n.status = :completed
135
+ n.status.should == :completed
136
+ end
137
+
138
+ it 'has a sessionid attribute' do
139
+ n = Blather::Stanza::Iq::Command.new
140
+ n.sessionid.should == nil
141
+ n.sessionid = "somerandomstring"
142
+ n.sessionid.should == Digest::SHA1.hexdigest("somerandomstring")
143
+ end
144
+
145
+ it 'has a sessionid? attribute' do
146
+ n = Blather::Stanza::Iq::Command.new
147
+ n.sessionid?.should == false
148
+ n.new_sessionid!
149
+ n.sessionid?.should == true
150
+ end
151
+
152
+ it 'has an allowed_actions attribute' do
153
+ n = Blather::XMPPNode.parse command_xml
154
+ n.allowed_actions.should == [:execute]
155
+ n.allowed_actions = [:next, :prev]
156
+ (n.allowed_actions - [:next, :prev, :execute]).should be_empty
157
+ n.remove_allowed_actions!
158
+ n.allowed_actions.should == [:execute]
159
+ n.allowed_actions += [:next]
160
+ (n.allowed_actions - [:next, :execute]).should be_empty
161
+
162
+ r = Blather::Stanza::Iq::Command.new
163
+ r.allowed_actions.should == [:execute]
164
+ r.allowed_actions += [:prev]
165
+ (r.allowed_actions - [:prev, :execute]).should be_empty
166
+ end
167
+
168
+ it 'has a primary_allowed_action attribute' do
169
+ n = Blather::XMPPNode.parse command_xml
170
+ n.primary_allowed_action.should == :execute
171
+ n.primary_allowed_action = :next
172
+ n.primary_allowed_action.should == :next
173
+ end
174
+
175
+ it 'has a note_type attribute' do
176
+ n = Blather::Stanza::Iq::Command.new
177
+ n.note_type.should == nil
178
+ n.note_type = :info
179
+ n.note_type.should == :info
180
+ end
181
+
182
+ it 'has a note_text attribute' do
183
+ n = Blather::Stanza::Iq::Command.new
184
+ n.note_text.should == nil
185
+ n.note_text = "Some text"
186
+ n.note_text.should == "Some text"
187
+ end
188
+
189
+ it 'makes a form child available' do
190
+ n = Blather::XMPPNode.parse(command_xml)
191
+ n.form.fields.size.should == 1
192
+ n.form.fields.map { |f| f.class }.uniq.should == [Blather::Stanza::X::Field]
193
+ n.form.should be_instance_of Blather::Stanza::X
194
+
195
+ r = Blather::Stanza::Iq::Command.new
196
+ r.form.type = :form
197
+ r.form.type.should == :form
198
+ end
199
+
200
+ it 'ensures the form child is a child of command' do
201
+ r = Blather::Stanza::Iq::Command.new
202
+ r.form
203
+ r.command.xpath('ns:x', :ns => Blather::Stanza::X.registered_ns).should_not be_empty
204
+ r.xpath('ns:x', :ns => Blather::Stanza::X.registered_ns).should be_empty
205
+ end
206
+ end