blather 0.2.1 → 0.2.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 (84) hide show
  1. data/LICENSE +2 -0
  2. data/README.rdoc +54 -29
  3. data/Rakefile +94 -13
  4. data/VERSION.yml +4 -0
  5. data/examples/drb_client.rb +2 -4
  6. data/examples/echo.rb +13 -8
  7. data/examples/pubsub/cli.rb +64 -0
  8. data/examples/pubsub/ping_pong.rb +18 -0
  9. data/examples/pubsub/pubsub_dsl.rb +52 -0
  10. data/examples/pubsub_client.rb +39 -0
  11. data/examples/rosterprint.rb +14 -0
  12. data/examples/xmpp4r/echo.rb +35 -0
  13. data/ext/extconf.rb +65 -0
  14. data/lib/blather.rb +18 -121
  15. data/lib/blather/client.rb +13 -0
  16. data/lib/blather/client/client.rb +165 -0
  17. data/lib/blather/client/dsl.rb +99 -0
  18. data/lib/blather/client/pubsub.rb +53 -0
  19. data/lib/blather/client/pubsub/node.rb +27 -0
  20. data/lib/blather/core_ext/active_support.rb +1 -0
  21. data/lib/blather/core_ext/libxml.rb +7 -1
  22. data/lib/blather/errors.rb +39 -18
  23. data/lib/blather/errors/sasl_error.rb +87 -0
  24. data/lib/blather/errors/stanza_error.rb +262 -0
  25. data/lib/blather/errors/stream_error.rb +253 -0
  26. data/lib/blather/jid.rb +9 -16
  27. data/lib/blather/roster.rb +9 -0
  28. data/lib/blather/roster_item.rb +7 -4
  29. data/lib/blather/stanza.rb +19 -25
  30. data/lib/blather/stanza/disco.rb +9 -0
  31. data/lib/blather/stanza/disco/disco_info.rb +84 -0
  32. data/lib/blather/stanza/disco/disco_items.rb +59 -0
  33. data/lib/blather/stanza/iq.rb +16 -4
  34. data/lib/blather/stanza/iq/query.rb +6 -4
  35. data/lib/blather/stanza/iq/roster.rb +38 -38
  36. data/lib/blather/stanza/pubsub.rb +33 -0
  37. data/lib/blather/stanza/pubsub/affiliations.rb +52 -0
  38. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  39. data/lib/blather/stanza/pubsub/event.rb +21 -0
  40. data/lib/blather/stanza/pubsub/items.rb +59 -0
  41. data/lib/blather/stanza/pubsub/owner.rb +9 -0
  42. data/lib/blather/stanza/pubsub/subscriptions.rb +57 -0
  43. data/lib/blather/stream.rb +125 -57
  44. data/lib/blather/stream/client.rb +26 -0
  45. data/lib/blather/stream/component.rb +34 -0
  46. data/lib/blather/stream/parser.rb +17 -27
  47. data/lib/blather/stream/resource.rb +21 -24
  48. data/lib/blather/stream/sasl.rb +60 -37
  49. data/lib/blather/stream/session.rb +12 -19
  50. data/lib/blather/stream/stream_handler.rb +39 -0
  51. data/lib/blather/stream/tls.rb +22 -18
  52. data/lib/blather/xmpp_node.rb +91 -17
  53. data/spec/blather/core_ext/libxml_spec.rb +58 -0
  54. data/spec/blather/errors/sasl_error_spec.rb +56 -0
  55. data/spec/blather/errors/stanza_error_spec.rb +148 -0
  56. data/spec/blather/errors/stream_error_spec.rb +114 -0
  57. data/spec/blather/errors_spec.rb +40 -0
  58. data/spec/blather/jid_spec.rb +0 -7
  59. data/spec/blather/roster_item_spec.rb +5 -0
  60. data/spec/blather/roster_spec.rb +6 -6
  61. data/spec/blather/stanza/discos/disco_info_spec.rb +207 -0
  62. data/spec/blather/stanza/discos/disco_items_spec.rb +136 -0
  63. data/spec/blather/stanza/iq/query_spec.rb +9 -2
  64. data/spec/blather/stanza/iq/roster_spec.rb +117 -1
  65. data/spec/blather/stanza/iq_spec.rb +29 -0
  66. data/spec/blather/stanza/presence/subscription_spec.rb +12 -1
  67. data/spec/blather/stanza/presence_spec.rb +29 -0
  68. data/spec/blather/stanza/pubsub/affiliations_spec.rb +46 -0
  69. data/spec/blather/stanza/pubsub/items_spec.rb +59 -0
  70. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +63 -0
  71. data/spec/blather/stanza/pubsub_spec.rb +26 -0
  72. data/spec/blather/stanza_spec.rb +13 -1
  73. data/spec/blather/stream/client_spec.rb +787 -0
  74. data/spec/blather/stream/component_spec.rb +86 -0
  75. data/spec/blather/xmpp_node_spec.rb +75 -22
  76. data/spec/fixtures/pubsub.rb +157 -0
  77. data/spec/spec_helper.rb +6 -14
  78. metadata +86 -74
  79. data/CHANGELOG +0 -5
  80. data/Manifest +0 -47
  81. data/blather.gemspec +0 -41
  82. data/lib/blather/stanza/error.rb +0 -31
  83. data/spec/blather/stream_spec.rb +0 -462
  84. data/spec/build_safe.rb +0 -20
@@ -0,0 +1,207 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. .. 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
+ <feature var='jabber:iq:time'/>
15
+ <feature var='jabber:iq:version'/>
16
+ </query>
17
+ </iq>
18
+ XML
19
+ end
20
+
21
+ describe 'Blather::Stanza::Iq::DiscoInfo' do
22
+ it 'registers itself' do
23
+ XMPPNode.class_from_registration(:query, 'http://jabber.org/protocol/disco#info').must_equal Blather::Stanza::Iq::DiscoInfo
24
+ end
25
+
26
+ it 'has a node attribute' do
27
+ n = Blather::Stanza::Iq::DiscoInfo.new nil, 'music', [], []
28
+ n.node.must_equal 'music'
29
+ n.node = :foo
30
+ n.node.must_equal 'foo'
31
+ end
32
+
33
+ it 'inherits a list of identities' do
34
+ n = XML::Document.string disco_info_xml
35
+ r = Stanza::Iq::DiscoInfo.new.inherit n.root
36
+ r.identities.size.must_equal 1
37
+ r.identities.map { |i| i.class }.uniq.must_equal [Stanza::Iq::DiscoInfo::Identity]
38
+ end
39
+
40
+ it 'inherits a list of features' do
41
+ n = XML::Document.string disco_info_xml
42
+ r = Stanza::Iq::DiscoInfo.new.inherit n.root
43
+ r.features.size.must_equal 2
44
+ r.features.map { |i| i.class }.uniq.must_equal [Stanza::Iq::DiscoInfo::Feature]
45
+ end
46
+ end
47
+
48
+ describe 'Blather::Stanza::Iq::DiscoInfo identities' do
49
+ it 'takes a list of hashes for identities' do
50
+ ids = [
51
+ {:name => 'name', :type => 'type', :category => 'category'},
52
+ {:name => 'name1', :type => 'type1', :category => 'category1'},
53
+ ]
54
+
55
+ control = [ Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
56
+ Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
57
+
58
+ di = Stanza::Iq::DiscoInfo.new nil, nil, ids
59
+ di.identities.size.must_equal 2
60
+ di.identities.each { |i| control.include?(i).must_equal true }
61
+ end
62
+
63
+ it 'takes a list of Identity objects as identities' do
64
+ control = [ Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
65
+ Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
66
+
67
+ di = Stanza::Iq::DiscoInfo.new nil, nil, control
68
+ di.identities.size.must_equal 2
69
+ di.identities.each { |i| control.include?(i).must_equal true }
70
+ end
71
+
72
+ it 'takes a single hash as identity' do
73
+ control = [Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
74
+
75
+ di = Stanza::Iq::DiscoInfo.new nil, nil, {:name => 'name', :type => 'type', :category => 'category'}
76
+ di.identities.size.must_equal 1
77
+ di.identities.each { |i| control.include?(i).must_equal true }
78
+ end
79
+
80
+ it 'takes a single identity object as identity' do
81
+ control = [Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category])]
82
+
83
+ di = Stanza::Iq::DiscoInfo.new nil, nil, control.first
84
+ di.identities.size.must_equal 1
85
+ di.identities.each { |i| control.include?(i).must_equal true }
86
+ end
87
+
88
+ it 'takes a mix of hashes and identity objects as identities' do
89
+ ids = [
90
+ {:name => 'name', :type => 'type', :category => 'category'},
91
+ Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1]),
92
+ ]
93
+
94
+ control = [ Stanza::Iq::DiscoInfo::Identity.new(*%w[name type category]),
95
+ Stanza::Iq::DiscoInfo::Identity.new(*%w[name1 type1 category1])]
96
+
97
+ di = Stanza::Iq::DiscoInfo.new nil, nil, ids
98
+ di.identities.size.must_equal 2
99
+ di.identities.each { |i| control.include?(i).must_equal true }
100
+ end
101
+ end
102
+
103
+ describe 'Blather::Stanza::Iq::DiscoInfo features' do
104
+ it 'takes a list of features as strings' do
105
+ features = %w[feature1 feature2 feature3]
106
+ control = features.map { |f| Stanza::Iq::DiscoInfo::Feature.new f }
107
+
108
+ di = Stanza::Iq::DiscoInfo.new nil, nil, [], features
109
+ di.features.size.must_equal 3
110
+ di.features.each { |f| control.include?(f).must_equal true }
111
+ end
112
+
113
+ it 'takes a list of features as Feature objects' do
114
+ features = %w[feature1 feature2 feature3]
115
+ control = features.map { |f| Stanza::Iq::DiscoInfo::Feature.new f }
116
+
117
+ di = Stanza::Iq::DiscoInfo.new nil, nil, [], control
118
+ di.features.size.must_equal 3
119
+ di.features.each { |f| control.include?(f).must_equal true }
120
+ end
121
+
122
+ it 'takes a single string' do
123
+ control = [Stanza::Iq::DiscoInfo::Feature.new('feature1')]
124
+
125
+ di = Stanza::Iq::DiscoInfo.new nil, nil, [], 'feature1'
126
+ di.features.size.must_equal 1
127
+ di.features.each { |f| control.include?(f).must_equal true }
128
+ end
129
+
130
+ it 'takes a single Feature object' do
131
+ control = [Stanza::Iq::DiscoInfo::Feature.new('feature1')]
132
+
133
+ di = Stanza::Iq::DiscoInfo.new nil, nil, [], control.first
134
+ di.features.size.must_equal 1
135
+ di.features.each { |f| control.include?(f).must_equal true }
136
+ end
137
+
138
+ it 'takes a mixed list of features as Feature objects and strings' do
139
+ features = %w[feature1 feature2 feature3]
140
+ control = features.map { |f| Stanza::Iq::DiscoInfo::Feature.new f }
141
+ features[1] = control[1]
142
+
143
+ di = Stanza::Iq::DiscoInfo.new nil, nil, [], features
144
+ di.features.size.must_equal 3
145
+ di.features.each { |f| control.include?(f).must_equal true }
146
+ end
147
+ end
148
+
149
+ describe 'Blather::Stanza::Iq::DiscoInfo::Identity' do
150
+ it 'will auto-inherit nodes' do
151
+ n = XML::Document.string "<identity name='Personal Events' type='pep' category='pubsub' node='publish' />"
152
+ i = Stanza::Iq::DiscoInfo::Identity.new n.root
153
+ i.name.must_equal 'Personal Events'
154
+ i.type.must_equal :pep
155
+ i.category.must_equal :pubsub
156
+ end
157
+
158
+ it 'has a category attribute' do
159
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
160
+ n.category.must_equal :cat
161
+ n.category = :foo
162
+ n.category.must_equal :foo
163
+ end
164
+
165
+ it 'has a type attribute' do
166
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
167
+ n.type.must_equal :type
168
+ n.type = :foo
169
+ n.type.must_equal :foo
170
+ end
171
+
172
+ it 'has a name attribute' do
173
+ n = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
174
+ n.name.must_equal 'name'
175
+ n.name = :foo
176
+ n.name.must_equal 'foo'
177
+ end
178
+
179
+ it 'can determine equality' do
180
+ a = Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
181
+ a.must_respond_to :eql?
182
+ a.must_equal Blather::Stanza::Iq::DiscoInfo::Identity.new(*%w[name type cat])
183
+ a.wont_equal "<identity name='Personal Events' type='pep' category='pubsub' node='publish' />"
184
+ end
185
+ end
186
+
187
+ describe 'Blather::Stanza::Iq::DiscoInfo::Feature' do
188
+ it 'will auto-inherit nodes' do
189
+ n = XML::Document.string "<feature var='ipv6' />"
190
+ i = Stanza::Iq::DiscoInfo::Feature.new n.root
191
+ i.var.must_equal 'ipv6'
192
+ end
193
+
194
+ it 'has a var attribute' do
195
+ n = Blather::Stanza::Iq::DiscoInfo::Feature.new 'var'
196
+ n.var.must_equal 'var'
197
+ n.var = :foo
198
+ n.var.must_equal 'foo'
199
+ end
200
+
201
+ it 'can determine equality' do
202
+ a = Blather::Stanza::Iq::DiscoInfo::Feature.new('var')
203
+ a.must_respond_to :eql?
204
+ a.must_equal Blather::Stanza::Iq::DiscoInfo::Feature.new('var')
205
+ a.wont_equal "<feature var='ipv6' />"
206
+ end
207
+ end
@@ -0,0 +1,136 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. .. 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
+ XMPPNode.class_from_registration(:query, 'http://jabber.org/protocol/disco#items').must_equal Blather::Stanza::Iq::DiscoItems
27
+ end
28
+
29
+ it 'has a node attribute' do
30
+ n = Blather::Stanza::Iq::DiscoItems.new nil, 'music', []
31
+ n.node.must_equal 'music'
32
+ n.node = :foo
33
+ n.node.must_equal 'foo'
34
+ end
35
+
36
+ it 'inherits a list of identities' do
37
+ n = XML::Document.string disco_items_xml
38
+ r = Stanza::Iq::DiscoItems.new.inherit n.root
39
+ r.items.size.must_equal 3
40
+ r.items.map { |i| i.class }.uniq.must_equal [Stanza::Iq::DiscoItems::Item]
41
+ end
42
+ end
43
+
44
+ describe 'Blather::Stanza::Iq::DiscoItems items' do
45
+ it 'takes a list of hashes for items' do
46
+ items = [
47
+ {:jid => 'foo@bar/baz', :node => 'node', :name => 'name'},
48
+ {:jid => 'baz@foo/bar', :node => 'node1', :name => 'name1'},
49
+ ]
50
+
51
+ control = [ Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name]),
52
+ Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1])]
53
+
54
+ di = Stanza::Iq::DiscoItems.new nil, nil, items
55
+ di.items.size.must_equal 2
56
+ di.items.each { |i| control.include?(i).must_equal true }
57
+ end
58
+
59
+ it 'takes a list of Item objects as items' do
60
+ control = [ Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name]),
61
+ Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1])]
62
+
63
+ di = Stanza::Iq::DiscoItems.new nil, nil, control
64
+ di.items.size.must_equal 2
65
+ di.items.each { |i| control.include?(i).must_equal true }
66
+ end
67
+
68
+ it 'takes a single hash as identity' do
69
+ control = [Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name])]
70
+
71
+ di = Stanza::Iq::DiscoItems.new nil, nil, {:jid => 'foo@bar/baz', :node => 'node', :name => 'name'}
72
+ di.items.size.must_equal 1
73
+ di.items.each { |i| control.include?(i).must_equal true }
74
+ end
75
+
76
+ it 'takes a single identity object as identity' do
77
+ control = [Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name])]
78
+
79
+ di = Stanza::Iq::DiscoItems.new nil, nil, control.first
80
+ di.items.size.must_equal 1
81
+ di.items.each { |i| control.include?(i).must_equal true }
82
+ end
83
+
84
+ it 'takes a mix of hashes and identity objects as items' do
85
+ items = [
86
+ {:jid => 'foo@bar/baz', :node => 'node', :name => 'name'},
87
+ Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1]),
88
+ ]
89
+
90
+ control = [ Stanza::Iq::DiscoItems::Item.new(*%w[foo@bar/baz node name]),
91
+ Stanza::Iq::DiscoItems::Item.new(*%w[baz@foo/bar node1 name1])]
92
+
93
+ di = Stanza::Iq::DiscoItems.new nil, nil, items
94
+ di.items.size.must_equal 2
95
+ di.items.each { |i| control.include?(i).must_equal true }
96
+ end
97
+ end
98
+
99
+ describe 'Blather::Stanza::Iq::DiscoItems::Item' do
100
+ it 'will auto-inherit nodes' do
101
+ n = XML::Document.string "<item jid='foo@bar/baz' node='music' name='Music from the time of Shakespeare' />"
102
+ i = Stanza::Iq::DiscoItems::Item.new n.root
103
+ i.jid.must_equal JID.new('foo@bar/baz')
104
+ i.node.must_equal 'music'
105
+ i.name.must_equal 'Music from the time of Shakespeare'
106
+ end
107
+
108
+ it 'has a jid attribute' do
109
+ n = Stanza::Iq::DiscoItems::Item.new 'foo@bar/baz'
110
+ n.jid.must_be_kind_of JID
111
+ n.jid.must_equal JID.new('foo@bar/baz')
112
+ n.jid = 'baz@foo/bar'
113
+ n.jid.must_equal JID.new('baz@foo/bar')
114
+ end
115
+
116
+ it 'has a node attribute' do
117
+ n = Stanza::Iq::DiscoItems::Item.new 'foo@bar/baz', 'music'
118
+ n.node.must_equal 'music'
119
+ n.node = 'book'
120
+ n.node.must_equal 'book'
121
+ end
122
+
123
+ it 'has a name attribute' do
124
+ n = Stanza::Iq::DiscoItems::Item.new 'foo@bar/baz', nil, 'Music from the time of Shakespeare'
125
+ n.name.must_equal 'Music from the time of Shakespeare'
126
+ n.name = 'Books by and about Shakespeare'
127
+ n.name.must_equal 'Books by and about Shakespeare'
128
+ end
129
+
130
+ it 'can determine equality' do
131
+ a = Stanza::Iq::DiscoItems::Item.new('foo@bar/baz')
132
+ a.must_respond_to :eql?
133
+ a.must_equal Stanza::Iq::DiscoItems::Item.new('foo@bar/baz')
134
+ a.wont_equal "<item jid='foo@bar/baz' node='music' name='Music from the time of Shakespeare' />"
135
+ end
136
+ end
@@ -19,13 +19,20 @@ describe 'Blather::Stanza::Iq::Query' do
19
19
  query.children.detect { |n| n.element_name == 'query' }.wont_be_nil
20
20
  end
21
21
 
22
- it 'sets type to "reslut" on reply' do
22
+ [:get, :set, :result, :error].each do |type|
23
+ it "can be set as \"#{type}\"" do
24
+ query = Stanza::Iq::Query.new type
25
+ query.type.must_equal type
26
+ end
27
+ end
28
+
29
+ it 'sets type to "result" on reply' do
23
30
  query = Stanza::Iq::Query.new
24
31
  query.type.must_equal :get
25
32
  reply = query.reply.type.must_equal :result
26
33
  end
27
34
 
28
- it 'sets type to "reslut" on reply!' do
35
+ it 'sets type to "result" on reply!' do
29
36
  query = Stanza::Iq::Query.new
30
37
  query.type.must_equal :get
31
38
  query.reply!
@@ -1,7 +1,123 @@
1
1
  require File.join(File.dirname(__FILE__), *%w[.. .. .. spec_helper])
2
2
 
3
+ def roster_xml
4
+ <<-XML
5
+ <iq to='juliet@example.com/balcony' type='result' id='roster_1'>
6
+ <query xmlns='jabber:iq:roster'>
7
+ <item jid='romeo@example.net'
8
+ name='Romeo'
9
+ subscription='both'>
10
+ <group>Friends</group>
11
+ </item>
12
+ <item jid='mercutio@example.org'
13
+ name='Mercutio'
14
+ subscription='from'>
15
+ <group>Friends</group>
16
+ </item>
17
+ <item jid='benvolio@example.org'
18
+ name='Benvolio'
19
+ subscription='both'>
20
+ <group>Friends</group>
21
+ </item>
22
+ </query>
23
+ </iq>
24
+ XML
25
+ end
26
+
3
27
  describe 'Blather::Stanza::Iq::Roster' do
4
28
  it 'registers itself' do
5
29
  XMPPNode.class_from_registration(:query, 'jabber:iq:roster').must_equal Stanza::Iq::Roster
6
30
  end
7
- end
31
+
32
+ it 'ensures newly inherited items are RosterItem objects' do
33
+ n = XML::Document.string roster_xml
34
+ r = Stanza::Iq::Roster.new.inherit n.root
35
+ r.items.map { |i| i.class }.uniq.must_equal [Stanza::Iq::Roster::RosterItem]
36
+ end
37
+ end
38
+
39
+ describe 'Blather::Stanza::Iq::Roster::RosterItem' do
40
+ it 'can be initialized with just a JID' do
41
+ i = Stanza::Iq::Roster::RosterItem.new 'n@d/r'
42
+ i.jid.must_equal JID.new('n@d/r')
43
+ end
44
+
45
+ it 'can be initialized with a name' do
46
+ i = Stanza::Iq::Roster::RosterItem.new nil, 'foobar'
47
+ i.name.must_equal 'foobar'
48
+ end
49
+
50
+ it 'can be initialized with a subscription' do
51
+ i = Stanza::Iq::Roster::RosterItem.new nil, nil, :both
52
+ i.subscription.must_equal :both
53
+ end
54
+
55
+ it 'can be initialized with ask (subscription sub-type)' do
56
+ i = Stanza::Iq::Roster::RosterItem.new nil, nil, nil, :subscribe
57
+ i.ask.must_equal :subscribe
58
+ end
59
+
60
+ it 'inherits a node when initialized with one' do
61
+ n = XMPPNode.new 'item'
62
+ n['jid'] = 'n@d/r'
63
+ n['subscription'] = 'both'
64
+
65
+ i = Stanza::Iq::Roster::RosterItem.new n
66
+ i.jid.must_equal JID.new('n@d/r')
67
+ i.subscription.must_equal :both
68
+ end
69
+
70
+ it 'has a #groups helper that gives an array of groups' do
71
+ n = XML::Document.string "<item jid='romeo@example.net' subscription='both'><group>foo</group><group>bar</group><group>baz</group></item>"
72
+ i = Stanza::Iq::Roster::RosterItem.new n.root
73
+ i.must_respond_to :groups
74
+ i.groups.sort.must_equal %w[bar baz foo]
75
+ end
76
+
77
+ it 'has a helper to set the groups' do
78
+ n = XML::Document.string "<item jid='romeo@example.net' subscription='both'><group>foo</group><group>bar</group><group>baz</group></item>"
79
+ i = Stanza::Iq::Roster::RosterItem.new n.root
80
+ i.must_respond_to :groups=
81
+ i.groups.sort.must_equal %w[bar baz foo]
82
+ i.groups = %w[a b c]
83
+ i.groups.sort.must_equal %w[a b c]
84
+ end
85
+
86
+ it 'can be easily converted into a proper stanza' do
87
+ xml = "<item jid='romeo@example.net' subscription='both'><group>foo</group><group>bar</group><group>baz</group></item>"
88
+ n = XML::Document.string xml
89
+ i = Stanza::Iq::Roster::RosterItem.new n.root
90
+ i.must_respond_to :to_stanza
91
+ s = i.to_stanza
92
+ s.must_be_kind_of Stanza::Iq::Roster
93
+ s.items.first.jid.must_equal JID.new('romeo@example.net')
94
+ s.items.first.groups.sort.must_equal %w[bar baz foo]
95
+ end
96
+
97
+ it 'has an "attr_accessor" for jid' do
98
+ i = Stanza::Iq::Roster::RosterItem.new
99
+ i.must_respond_to :jid
100
+ i.jid.must_be_nil
101
+ i.must_respond_to :jid=
102
+ i.jid = 'n@d/r'
103
+ i.jid.must_equal JID.new('n@d/r')
104
+ end
105
+
106
+ it 'has a name attribute' do
107
+ i = Stanza::Iq::Roster::RosterItem.new
108
+ i.name = 'name'
109
+ i.name.must_equal 'name'
110
+ end
111
+
112
+ it 'has a subscription attribute' do
113
+ i = Stanza::Iq::Roster::RosterItem.new
114
+ i.subscription = :both
115
+ i.subscription.must_equal :both
116
+ end
117
+
118
+ it 'has an ask attribute' do
119
+ i = Stanza::Iq::Roster::RosterItem.new
120
+ i.ask = :subscribe
121
+ i.ask.must_equal :subscribe
122
+ end
123
+ end