sprsquish-blather 0.1 → 0.2.3
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.
- data/LICENSE +2 -0
- data/README.rdoc +100 -0
- data/Rakefile +110 -0
- data/examples/drb_client.rb +5 -0
- data/examples/echo.rb +18 -0
- data/ext/extconf.rb +65 -0
- data/ext/push_parser.c +231 -0
- data/lib/blather/client.rb +219 -44
- data/lib/blather/{core/sugar.rb → core_ext/active_support.rb} +25 -13
- data/lib/blather/core_ext/libxml.rb +28 -0
- data/lib/blather/errors/sasl_error.rb +87 -0
- data/lib/blather/errors/stanza_error.rb +262 -0
- data/lib/blather/errors/stream_error.rb +253 -0
- data/lib/blather/errors.rb +48 -0
- data/lib/blather/{core/jid.rb → jid.rb} +15 -26
- data/lib/blather/{core/roster.rb → roster.rb} +22 -0
- data/lib/blather/{core/roster_item.rb → roster_item.rb} +39 -8
- data/lib/blather/stanza/iq/disco.rb +11 -0
- data/lib/blather/stanza/iq/discos/disco_info.rb +86 -0
- data/lib/blather/stanza/iq/discos/disco_items.rb +61 -0
- data/lib/blather/stanza/iq/query.rb +51 -0
- data/lib/blather/stanza/iq/roster.rb +90 -0
- data/lib/blather/stanza/iq.rb +38 -0
- data/lib/blather/stanza/message.rb +58 -0
- data/lib/blather/stanza/presence/status.rb +78 -0
- data/lib/blather/stanza/presence/subscription.rb +72 -0
- data/lib/blather/stanza/presence.rb +45 -0
- data/lib/blather/stanza.rb +101 -0
- data/lib/blather/stream/client.rb +26 -0
- data/lib/blather/stream/component.rb +34 -0
- data/lib/blather/stream/parser.rb +70 -0
- data/lib/blather/stream/resource.rb +48 -0
- data/lib/blather/stream/sasl.rb +173 -0
- data/lib/blather/stream/session.rb +36 -0
- data/lib/blather/stream/stream_handler.rb +39 -0
- data/lib/blather/stream/tls.rb +33 -0
- data/lib/blather/stream.rb +249 -0
- data/lib/blather/xmpp_node.rb +199 -0
- data/lib/blather.rb +40 -41
- data/spec/blather/core_ext/libxml_spec.rb +58 -0
- data/spec/blather/errors/sasl_error_spec.rb +56 -0
- data/spec/blather/errors/stanza_error_spec.rb +148 -0
- data/spec/blather/errors/stream_error_spec.rb +114 -0
- data/spec/blather/errors_spec.rb +40 -0
- data/spec/blather/{core/jid_spec.rb → jid_spec.rb} +9 -1
- data/spec/blather/{core/roster_item_spec.rb → roster_item_spec.rb} +6 -1
- data/spec/blather/{core/roster_spec.rb → roster_spec.rb} +16 -6
- data/spec/blather/stanza/iq/discos/disco_info_spec.rb +207 -0
- data/spec/blather/stanza/iq/discos/disco_items_spec.rb +136 -0
- data/spec/blather/stanza/iq/query_spec.rb +34 -0
- data/spec/blather/stanza/iq/roster_spec.rb +123 -0
- data/spec/blather/stanza/iq_spec.rb +40 -0
- data/spec/blather/stanza/message_spec.rb +52 -0
- data/spec/blather/stanza/presence/status_spec.rb +102 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +85 -0
- data/spec/blather/stanza/presence_spec.rb +53 -0
- data/spec/blather/{core/stanza_spec.rb → stanza_spec.rb} +14 -2
- data/spec/blather/stream/client_spec.rb +787 -0
- data/spec/blather/stream/component_spec.rb +86 -0
- data/spec/blather/{core/xmpp_node_spec.rb → xmpp_node_spec.rb} +76 -23
- data/spec/build_safe.rb +20 -0
- data/spec/spec_helper.rb +7 -17
- metadata +79 -59
- data/CHANGELOG +0 -1
- data/blather.gemspec +0 -73
- data/lib/blather/callback.rb +0 -24
- data/lib/blather/core/errors.rb +0 -24
- data/lib/blather/core/stanza.rb +0 -90
- data/lib/blather/core/stream.rb +0 -179
- data/lib/blather/core/xmpp_node.rb +0 -95
- data/lib/blather/extensions/last_activity.rb +0 -57
- data/lib/blather/extensions/version.rb +0 -85
- data/spec/blather/core/stream_spec.rb +0 -263
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
|
3
|
+
def stanza_error_node(type = 'cancel', error = 'internal-server-error', msg = nil)
|
4
|
+
node = Stanza::Message.new 'error@jabber.local', 'test message', :error
|
5
|
+
XML::Document.new.root = node
|
6
|
+
|
7
|
+
error_node = XMPPNode.new('error')
|
8
|
+
error_node['type'] = type.to_s
|
9
|
+
|
10
|
+
err = XMPPNode.new(error)
|
11
|
+
err.namespace = 'urn:ietf:params:xml:ns:xmpp-stanzas'
|
12
|
+
error_node << err
|
13
|
+
|
14
|
+
if msg
|
15
|
+
text = XMPPNode.new('text')
|
16
|
+
text.namespace = 'urn:ietf:params:xml:ns:xmpp-stanzas'
|
17
|
+
text << msg
|
18
|
+
error_node << text
|
19
|
+
end
|
20
|
+
|
21
|
+
extra = XMPPNode.new('extra-error')
|
22
|
+
extra.namespace = 'blather:stanza:error'
|
23
|
+
extra << 'Blather Error'
|
24
|
+
error_node << extra
|
25
|
+
|
26
|
+
node << error_node
|
27
|
+
node
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'Blather::StanzaError' do
|
31
|
+
it 'can import a node' do
|
32
|
+
StanzaError.must_respond_to :import
|
33
|
+
e = StanzaError.import stanza_error_node
|
34
|
+
e.must_be_kind_of StanzaError
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'knows what class to instantiate' do
|
38
|
+
e = StanzaError.import stanza_error_node
|
39
|
+
e.must_be_instance_of StanzaError::InternalServerError
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'valid types' do
|
43
|
+
before { @original = Stanza::Message.new 'error@jabber.local', 'test message', :error }
|
44
|
+
|
45
|
+
it 'ensures type is one of Stanza::Message::VALID_TYPES' do
|
46
|
+
lambda { StanzaError.new @original, :invalid_type_name }.must_raise(Blather::ArgumentError)
|
47
|
+
|
48
|
+
StanzaError::VALID_TYPES.each do |valid_type|
|
49
|
+
msg = StanzaError.new @original, valid_type
|
50
|
+
msg.type.must_equal valid_type
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'when instantiated' do
|
56
|
+
before do
|
57
|
+
@type = 'cancel'
|
58
|
+
@err_name = 'internal-server-error'
|
59
|
+
@msg = 'the server has experienced a misconfiguration'
|
60
|
+
@err = StanzaError.import stanza_error_node(@type, @err_name, @msg)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'provides a type attribute' do
|
64
|
+
@err.must_respond_to :type
|
65
|
+
@err.type.must_equal @type.to_sym
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'provides a err_name attribute' do
|
69
|
+
@err.must_respond_to :err_name
|
70
|
+
@err.err_name.must_equal @err_name
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'provides a text attribute' do
|
74
|
+
@err.must_respond_to :text
|
75
|
+
@err.text.must_equal @msg
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'provides a reader to the original node' do
|
79
|
+
@err.must_respond_to :original
|
80
|
+
@err.original.must_be_instance_of Stanza::Message
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'provides an extras attribute' do
|
84
|
+
@err.must_respond_to :extras
|
85
|
+
@err.extras.must_be_instance_of Array
|
86
|
+
@err.extras.first.element_name.must_equal 'extra-error'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'describes itself' do
|
90
|
+
@err.to_s.must_match(/#{@err_name}/)
|
91
|
+
@err.to_s.must_match(/#{@msg}/)
|
92
|
+
|
93
|
+
@err.inspect.must_match(/#{@err_name}/)
|
94
|
+
@err.inspect.must_match(/#{@msg}/)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'can be turned into xml' do
|
98
|
+
@err.must_respond_to :to_xml
|
99
|
+
control = "<body>test message</body>\n<error>\n<internal-server-error xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>\n<text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">the server has experienced a misconfiguration</text>\n<extra-error xmlns=\"blather:stanza:error\">Blather Error</extra-error>\n</error>\n</message>".split("\n")
|
100
|
+
test = @err.to_xml.split("\n")
|
101
|
+
test_msg = test.shift
|
102
|
+
test.must_equal control
|
103
|
+
|
104
|
+
test_msg.must_match(/<message[^>]*id="#{@err.original.id}"/)
|
105
|
+
test_msg.must_match(/<message[^>]*from="error@jabber\.local"/)
|
106
|
+
test_msg.must_match(/<message[^>]*type="error"/)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe 'each XMPP stanza error type' do
|
111
|
+
%w[ bad-request
|
112
|
+
conflict
|
113
|
+
feature-not-implemented
|
114
|
+
forbidden
|
115
|
+
gone
|
116
|
+
internal-server-error
|
117
|
+
item-not-found
|
118
|
+
jid-malformed
|
119
|
+
not-acceptable
|
120
|
+
not-allowed
|
121
|
+
not-authorized
|
122
|
+
payment-required
|
123
|
+
recipient-unavailable
|
124
|
+
redirect
|
125
|
+
registration-required
|
126
|
+
remote-server-not-found
|
127
|
+
remote-server-timeout
|
128
|
+
resource-constraint
|
129
|
+
service-unavailable
|
130
|
+
subscription-required
|
131
|
+
undefined-condition
|
132
|
+
unexpected-request
|
133
|
+
].each do |error_type|
|
134
|
+
it "provides a class for #{error_type}" do
|
135
|
+
e = StanzaError.import stanza_error_node(:cancel, error_type)
|
136
|
+
klass = error_type.gsub(/^\w/) { |v| v.upcase }.gsub(/\-(\w)/) { |v| v.delete('-').upcase }
|
137
|
+
e.must_be_instance_of eval("StanzaError::#{klass}")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "registers #{error_type} in the handler heirarchy" do
|
141
|
+
e = StanzaError.import stanza_error_node(:cancel, error_type)
|
142
|
+
e.handler_heirarchy.must_equal ["stanza_#{error_type.gsub('-','_').gsub('_error','')}_error".to_sym, :stanza_error, :error]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
|
3
|
+
def stream_error_node(error = 'internal-server-error', msg = nil)
|
4
|
+
node = XMPPNode.new('stream:error')
|
5
|
+
XML::Document.new.root = node
|
6
|
+
|
7
|
+
err = XMPPNode.new(error)
|
8
|
+
err.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
|
9
|
+
node << err
|
10
|
+
|
11
|
+
if msg
|
12
|
+
text = XMPPNode.new('text')
|
13
|
+
text.namespace = 'urn:ietf:params:xml:ns:xmpp-streams'
|
14
|
+
text << msg
|
15
|
+
node << text
|
16
|
+
end
|
17
|
+
|
18
|
+
extra = XMPPNode.new('extra-error')
|
19
|
+
extra.namespace = 'blather:stream:error'
|
20
|
+
extra << 'Blather Error'
|
21
|
+
|
22
|
+
node << extra
|
23
|
+
node
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'Blather::StreamError' do
|
27
|
+
it 'can import a node' do
|
28
|
+
StreamError.must_respond_to :import
|
29
|
+
e = StreamError.import stream_error_node
|
30
|
+
e.must_be_kind_of StreamError
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'knows what class to instantiate' do
|
34
|
+
e = StreamError.import stream_error_node
|
35
|
+
e.must_be_instance_of StreamError::InternalServerError
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'Blather::StreamError when instantiated' do
|
40
|
+
before do
|
41
|
+
@err_name = 'internal-server-error'
|
42
|
+
@msg = 'the server has experienced a misconfiguration'
|
43
|
+
@err = StreamError.import stream_error_node(@err_name, @msg)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'provides a err_name attribute' do
|
47
|
+
@err.must_respond_to :err_name
|
48
|
+
@err.err_name.must_equal @err_name
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'provides a text attribute' do
|
52
|
+
@err.must_respond_to :text
|
53
|
+
@err.text.must_equal @msg
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'provides an extras attribute' do
|
57
|
+
@err.must_respond_to :extras
|
58
|
+
@err.extras.must_be_instance_of Array
|
59
|
+
@err.extras.size.must_equal 1
|
60
|
+
@err.extras.first.element_name.must_equal 'extra-error'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'describes itself' do
|
64
|
+
@err.to_s.must_match(/#{@type}/)
|
65
|
+
@err.to_s.must_match(/#{@msg}/)
|
66
|
+
|
67
|
+
@err.inspect.must_match(/#{@type}/)
|
68
|
+
@err.inspect.must_match(/#{@msg}/)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'can be turned into xml' do
|
72
|
+
@err.must_respond_to :to_xml
|
73
|
+
@err.to_xml.must_equal "<stream:error>\n<internal-server-error xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>\n<text xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\">the server has experienced a misconfiguration</text>\n<extra-error xmlns=\"blather:stream:error\">Blather Error</extra-error>\n</stream:error>"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'Each XMPP stream error type' do
|
78
|
+
%w[ bad-format
|
79
|
+
bad-namespace-prefix
|
80
|
+
conflict
|
81
|
+
connection-timeout
|
82
|
+
host-gone
|
83
|
+
host-unknown
|
84
|
+
improper-addressing
|
85
|
+
internal-server-error
|
86
|
+
invalid-from
|
87
|
+
invalid-id
|
88
|
+
invalid-namespace
|
89
|
+
invalid-xml
|
90
|
+
not-authorized
|
91
|
+
policy-violation
|
92
|
+
remote-connection-failed
|
93
|
+
resource-constraint
|
94
|
+
restricted-xml
|
95
|
+
see-other-host
|
96
|
+
system-shutdown
|
97
|
+
undefined-condition
|
98
|
+
unsupported-encoding
|
99
|
+
unsupported-stanza-type
|
100
|
+
unsupported-version
|
101
|
+
xml-not-well-formed
|
102
|
+
].each do |error_type|
|
103
|
+
it "provides a class for #{error_type}" do
|
104
|
+
e = StreamError.import stream_error_node(error_type)
|
105
|
+
klass = error_type.gsub(/^\w/) { |v| v.upcase }.gsub(/\-(\w)/) { |v| v.delete('-').upcase }
|
106
|
+
e.must_be_instance_of eval("StreamError::#{klass}")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "registers #{error_type} in the handler heirarchy" do
|
110
|
+
e = StreamError.import stream_error_node(error_type)
|
111
|
+
e.handler_heirarchy.must_equal ["stream_#{error_type.gsub('-','_').gsub('_error','')}_error".to_sym, :stream_error, :error]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. spec_helper])
|
2
|
+
|
3
|
+
describe 'Blather::BlatherError' do
|
4
|
+
it 'is handled by :error' do
|
5
|
+
BlatherError.new.handler_heirarchy.must_equal [:error]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'Blather::ParseError' do
|
10
|
+
before { @error = ParseError.new('</generate-parse-error>"') }
|
11
|
+
|
12
|
+
it 'is registers with the handler heirarchy' do
|
13
|
+
@error.handler_heirarchy.must_equal [:parse_error, :error]
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'contains the error message' do
|
17
|
+
@error.must_respond_to :message
|
18
|
+
@error.message.must_equal '</generate-parse-error>"'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'Blather::TLSFailure' do
|
23
|
+
it 'is registers with the handler heirarchy' do
|
24
|
+
TLSFailure.new.handler_heirarchy.must_equal [:tls_failure, :error]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'Blather::UnknownResponse' do
|
29
|
+
before { @error = UnknownResponse.new(XMPPNode.new('foo-bar')) }
|
30
|
+
|
31
|
+
it 'is registers with the handler heirarchy' do
|
32
|
+
@error.handler_heirarchy.must_equal [:unknown_response_error, :error]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'holds on to a copy of the failure node' do
|
36
|
+
@error.must_respond_to :node
|
37
|
+
@error.node.element_name.must_equal 'foo-bar'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[..
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. spec_helper])
|
2
2
|
|
3
3
|
describe 'Blather::JID' do
|
4
4
|
it 'does nothing if creaded from JID' do
|
@@ -75,4 +75,12 @@ describe 'Blather::JID' do
|
|
75
75
|
JID.new('n', 'd', 'r').to_s.must_equal 'n@d/r'
|
76
76
|
JID.new('n', 'd').to_s.must_equal 'n@d'
|
77
77
|
end
|
78
|
+
|
79
|
+
it 'provides a #stripped? helper' do
|
80
|
+
jid = JID.new 'a@b/c'
|
81
|
+
jid.must_respond_to :stripped?
|
82
|
+
jid.stripped?.wont_equal true
|
83
|
+
jid.strip!
|
84
|
+
jid.stripped?.must_equal true
|
85
|
+
end
|
78
86
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[..
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. spec_helper])
|
2
2
|
|
3
3
|
describe 'Blather::RosterItem' do
|
4
4
|
it 'initializes with JID' do
|
@@ -77,4 +77,9 @@ describe 'Blather::RosterItem' do
|
|
77
77
|
@i.status = @p
|
78
78
|
@i.status = @p2
|
79
79
|
end
|
80
|
+
|
81
|
+
it 'initializes groups to [nil] if the item is not part of a group' do
|
82
|
+
i = RosterItem.new 'n@d'
|
83
|
+
i.groups.must_equal [nil]
|
84
|
+
end
|
80
85
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[..
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. spec_helper])
|
2
2
|
|
3
3
|
describe 'Blather::Roster' do
|
4
4
|
before do
|
@@ -19,27 +19,37 @@ describe 'Blather::Roster' do
|
|
19
19
|
it 'processes @stanzas with remove requests' do
|
20
20
|
s = @roster['n@d/0r']
|
21
21
|
s.subscription = :remove
|
22
|
-
proc { @roster.process(s.to_stanza) }.must_change('@roster.items', :
|
22
|
+
proc { @roster.process(s.to_stanza) }.must_change('@roster.items.length', :by => -1)
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'processes @stanzas with add requests' do
|
26
26
|
s = Stanza::Iq::Roster::RosterItem.new('a@b/c').to_stanza
|
27
|
-
proc { @roster.process(s) }.must_change('@roster.items', :
|
27
|
+
proc { @roster.process(s) }.must_change('@roster.items.length', :by => 1)
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'allows a jid to be pushed' do
|
31
31
|
jid = 'a@b/c'
|
32
|
-
proc { @roster.push(jid) }.must_change('@roster.items', :
|
32
|
+
proc { @roster.push(jid) }.must_change('@roster.items.length', :by => 1)
|
33
33
|
@roster[jid].wont_be_nil
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'allows an item to be pushed' do
|
37
37
|
jid = 'a@b/c'
|
38
38
|
item = RosterItem.new(JID.new(jid))
|
39
|
-
proc { @roster.push(item) }.must_change('@roster.items', :
|
39
|
+
proc { @roster.push(item) }.must_change('@roster.items.length', :by => 1)
|
40
40
|
@roster[jid].wont_be_nil
|
41
41
|
end
|
42
42
|
|
43
|
+
it 'aliases #<< to #push and returns self to allow for chaining' do
|
44
|
+
jid = 'a@b/c'
|
45
|
+
item = RosterItem.new(JID.new(jid))
|
46
|
+
jid2 = 'd@e/f'
|
47
|
+
item2 = RosterItem.new(JID.new(jid2))
|
48
|
+
proc { @roster << item << item2 }.must_change('@roster.items.length', :by => 2)
|
49
|
+
@roster[jid].wont_be_nil
|
50
|
+
@roster[jid2].wont_be_nil
|
51
|
+
end
|
52
|
+
|
43
53
|
it 'sends a @roster addition over the wire' do
|
44
54
|
stream = mock()
|
45
55
|
stream.expects(:send_data)
|
@@ -48,7 +58,7 @@ describe 'Blather::Roster' do
|
|
48
58
|
end
|
49
59
|
|
50
60
|
it 'removes a JID' do
|
51
|
-
proc { @roster.delete 'n@d' }.must_change('@roster.items', :
|
61
|
+
proc { @roster.delete 'n@d' }.must_change('@roster.items.length', :by => -1)
|
52
62
|
end
|
53
63
|
|
54
64
|
it 'sends a @roster removal over the wire' do
|
@@ -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, 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, 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, {: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, 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, 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, [], 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, [], 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, [], '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, [], 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, [], 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
|