blather 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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