blather 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +2 -0
- data/README.rdoc +54 -29
- data/Rakefile +94 -13
- data/VERSION.yml +4 -0
- data/examples/drb_client.rb +2 -4
- data/examples/echo.rb +13 -8
- data/examples/pubsub/cli.rb +64 -0
- data/examples/pubsub/ping_pong.rb +18 -0
- data/examples/pubsub/pubsub_dsl.rb +52 -0
- data/examples/pubsub_client.rb +39 -0
- data/examples/rosterprint.rb +14 -0
- data/examples/xmpp4r/echo.rb +35 -0
- data/ext/extconf.rb +65 -0
- data/lib/blather.rb +18 -121
- data/lib/blather/client.rb +13 -0
- data/lib/blather/client/client.rb +165 -0
- data/lib/blather/client/dsl.rb +99 -0
- data/lib/blather/client/pubsub.rb +53 -0
- data/lib/blather/client/pubsub/node.rb +27 -0
- data/lib/blather/core_ext/active_support.rb +1 -0
- data/lib/blather/core_ext/libxml.rb +7 -1
- data/lib/blather/errors.rb +39 -18
- 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/jid.rb +9 -16
- data/lib/blather/roster.rb +9 -0
- data/lib/blather/roster_item.rb +7 -4
- data/lib/blather/stanza.rb +19 -25
- data/lib/blather/stanza/disco.rb +9 -0
- data/lib/blather/stanza/disco/disco_info.rb +84 -0
- data/lib/blather/stanza/disco/disco_items.rb +59 -0
- data/lib/blather/stanza/iq.rb +16 -4
- data/lib/blather/stanza/iq/query.rb +6 -4
- data/lib/blather/stanza/iq/roster.rb +38 -38
- data/lib/blather/stanza/pubsub.rb +33 -0
- data/lib/blather/stanza/pubsub/affiliations.rb +52 -0
- data/lib/blather/stanza/pubsub/errors.rb +9 -0
- data/lib/blather/stanza/pubsub/event.rb +21 -0
- data/lib/blather/stanza/pubsub/items.rb +59 -0
- data/lib/blather/stanza/pubsub/owner.rb +9 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +57 -0
- data/lib/blather/stream.rb +125 -57
- data/lib/blather/stream/client.rb +26 -0
- data/lib/blather/stream/component.rb +34 -0
- data/lib/blather/stream/parser.rb +17 -27
- data/lib/blather/stream/resource.rb +21 -24
- data/lib/blather/stream/sasl.rb +60 -37
- data/lib/blather/stream/session.rb +12 -19
- data/lib/blather/stream/stream_handler.rb +39 -0
- data/lib/blather/stream/tls.rb +22 -18
- data/lib/blather/xmpp_node.rb +91 -17
- 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/jid_spec.rb +0 -7
- data/spec/blather/roster_item_spec.rb +5 -0
- data/spec/blather/roster_spec.rb +6 -6
- data/spec/blather/stanza/discos/disco_info_spec.rb +207 -0
- data/spec/blather/stanza/discos/disco_items_spec.rb +136 -0
- data/spec/blather/stanza/iq/query_spec.rb +9 -2
- data/spec/blather/stanza/iq/roster_spec.rb +117 -1
- data/spec/blather/stanza/iq_spec.rb +29 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +12 -1
- data/spec/blather/stanza/presence_spec.rb +29 -0
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +46 -0
- data/spec/blather/stanza/pubsub/items_spec.rb +59 -0
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +63 -0
- data/spec/blather/stanza/pubsub_spec.rb +26 -0
- data/spec/blather/stanza_spec.rb +13 -1
- data/spec/blather/stream/client_spec.rb +787 -0
- data/spec/blather/stream/component_spec.rb +86 -0
- data/spec/blather/xmpp_node_spec.rb +75 -22
- data/spec/fixtures/pubsub.rb +157 -0
- data/spec/spec_helper.rb +6 -14
- metadata +86 -74
- data/CHANGELOG +0 -5
- data/Manifest +0 -47
- data/blather.gemspec +0 -41
- data/lib/blather/stanza/error.rb +0 -31
- data/spec/blather/stream_spec.rb +0 -462
- data/spec/build_safe.rb +0 -20
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
|
3
|
+
describe 'Blather::Stream::Component' do
|
4
|
+
class MockServer; end
|
5
|
+
module ServerMock
|
6
|
+
def receive_data(data)
|
7
|
+
@server ||= MockServer.new
|
8
|
+
@server.receive_data data, self
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def mocked_server(times = nil, &block)
|
13
|
+
@client ||= mock()
|
14
|
+
@client.stubs(:stopped) unless @client.respond_to?(:stopped)
|
15
|
+
@client.stubs(:jid=) unless @client.respond_to?(:jid=)
|
16
|
+
|
17
|
+
MockServer.any_instance.expects(:receive_data).send(*(times ? [:times, times] : [:at_least, 1])).with &block
|
18
|
+
EventMachine::run {
|
19
|
+
# Mocked server
|
20
|
+
EventMachine::start_server '127.0.0.1', 12345, ServerMock
|
21
|
+
|
22
|
+
# Stream connection
|
23
|
+
EM.connect('127.0.0.1', 12345, Stream::Component, @client, @jid || 'comp.id', 'secret') { |c| @stream = c }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can be started' do
|
28
|
+
client = mock()
|
29
|
+
params = [client, 'comp.id', 'secret', 'host', 1234]
|
30
|
+
EM.expects(:connect).with do |*parms|
|
31
|
+
parms[0] == 'host' &&
|
32
|
+
parms[1] == 1234 &&
|
33
|
+
parms[3] == client &&
|
34
|
+
parms[4] == 'comp.id'
|
35
|
+
end
|
36
|
+
|
37
|
+
Stream::Component.start *params
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'shakes hands with the server' do
|
41
|
+
state = nil
|
42
|
+
mocked_server(2) do |val, server|
|
43
|
+
case state
|
44
|
+
when nil
|
45
|
+
state = :started
|
46
|
+
server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' id='12345'>"
|
47
|
+
val.must_match(/stream:stream/)
|
48
|
+
|
49
|
+
when :started
|
50
|
+
server.send_data '<handshake/>'
|
51
|
+
EM.stop
|
52
|
+
val.must_equal "<handshake>#{Digest::SHA1.hexdigest('12345'+"secret")}</handshake>"
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'starts the stream once the connection is complete' do
|
59
|
+
mocked_server(1) { |val, _| EM.stop; val.must_match(/stream:stream/) }
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'sends stanzas to the client when the stream is ready' do
|
63
|
+
@client = mock(:stream_started)
|
64
|
+
@client.expects(:call).with do |n|
|
65
|
+
EM.stop
|
66
|
+
n.kind_of?(Stanza::Message) && @stream.ready?.must_equal(true)
|
67
|
+
end
|
68
|
+
|
69
|
+
state = nil
|
70
|
+
mocked_server(2) do |val, server|
|
71
|
+
case state
|
72
|
+
when nil
|
73
|
+
state = :started
|
74
|
+
server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' id='12345'>"
|
75
|
+
val.must_match(/stream:stream/)
|
76
|
+
|
77
|
+
when :started
|
78
|
+
server.send_data '<handshake/>'
|
79
|
+
server.send_data "<message to='comp.id' from='d@e/f' type='chat' xml:lang='en'><body>Message!</body></message>"
|
80
|
+
val.must_equal "<handshake>#{Digest::SHA1.hexdigest('12345'+"secret")}</handshake>"
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -14,38 +14,85 @@ describe 'Blather::XMPPNode' do
|
|
14
14
|
|
15
15
|
it 'sets the namespace on creation' do
|
16
16
|
class Foo < XMPPNode; end
|
17
|
-
Foo.
|
18
|
-
Foo.new('foo').
|
17
|
+
Foo.ns = 'foo'
|
18
|
+
Foo.new('foo').namespace.must_equal 'foo'
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'registers sub classes' do
|
22
22
|
class Foo < XMPPNode; register 'foo', 'foo:bar'; end
|
23
23
|
Foo.name.must_equal 'foo'
|
24
|
-
Foo.
|
24
|
+
Foo.ns.must_equal 'foo:bar'
|
25
25
|
XMPPNode.class_from_registration('foo', 'foo:bar').must_equal Foo
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'imports another node' do
|
29
29
|
class Foo < XMPPNode; register 'foo', 'foo:bar'; end
|
30
30
|
n = XMPPNode.new('foo')
|
31
|
-
n.
|
31
|
+
n.namespace = 'foo:bar'
|
32
32
|
XMPPNode.import(n).must_be_kind_of Foo
|
33
33
|
end
|
34
34
|
|
35
|
+
it 'provides an attribute_reader' do
|
36
|
+
class Foo < XMPPNode
|
37
|
+
attribute_reader :foo
|
38
|
+
end
|
39
|
+
f = Foo.new
|
40
|
+
f.must_respond_to :foo
|
41
|
+
f.foo.must_be_nil
|
42
|
+
f.attributes[:foo] = 'bar'
|
43
|
+
f.foo.must_equal :bar
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'provides an attribute_reader and not convert to syms' do
|
47
|
+
class Foo < XMPPNode
|
48
|
+
attribute_reader :foo, :to_sym => false
|
49
|
+
end
|
50
|
+
f = Foo.new
|
51
|
+
f.must_respond_to :foo
|
52
|
+
f.foo.must_be_nil
|
53
|
+
f.attributes[:foo] = 'bar'
|
54
|
+
f.foo.must_equal 'bar'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'provides an attribute_writer' do
|
58
|
+
class Foo < XMPPNode
|
59
|
+
attribute_writer :foo
|
60
|
+
end
|
61
|
+
f = Foo.new
|
62
|
+
f.attributes[:foo].must_be_nil
|
63
|
+
f.foo = 'bar'
|
64
|
+
f.attributes[:foo].must_equal 'bar'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'provides an attribute_accessor' do
|
68
|
+
class Foo < XMPPNode
|
69
|
+
attribute_accessor :foo
|
70
|
+
attribute_accessor :bar, :to_sym => false
|
71
|
+
end
|
72
|
+
f = Foo.new
|
73
|
+
f.must_respond_to :foo
|
74
|
+
f.foo.must_be_nil
|
75
|
+
f.foo = 'bar'
|
76
|
+
f.foo.must_equal :bar
|
77
|
+
|
78
|
+
f.must_respond_to :bar
|
79
|
+
f.bar.must_be_nil
|
80
|
+
f.bar = 'baz'
|
81
|
+
f.bar.must_equal 'baz'
|
82
|
+
end
|
83
|
+
|
35
84
|
it 'can convert itself into a stanza' do
|
36
85
|
class Foo < XMPPNode; register 'foo'; end
|
37
86
|
n = XMPPNode.new('foo')
|
38
87
|
n.to_stanza.must_be_kind_of Foo
|
39
88
|
end
|
40
89
|
|
41
|
-
it 'provides "attr_accessor" for
|
90
|
+
it 'provides "attr_accessor" for namespace' do
|
42
91
|
n = XMPPNode.new('foo')
|
43
|
-
n.
|
44
|
-
n['xmlns'].must_be_nil
|
92
|
+
n.namespace.must_be_nil
|
45
93
|
|
46
|
-
n.
|
47
|
-
n.
|
48
|
-
n['xmlns'].must_equal 'foo:bar'
|
94
|
+
n.namespace = 'foo:bar'
|
95
|
+
n.namespace.must_equal 'foo:bar'
|
49
96
|
end
|
50
97
|
|
51
98
|
it 'will remove a child element' do
|
@@ -53,22 +100,22 @@ describe 'Blather::XMPPNode' do
|
|
53
100
|
n << XMPPNode.new('bar')
|
54
101
|
n << XMPPNode.new('bar')
|
55
102
|
|
56
|
-
n.find(
|
103
|
+
n.find(:bar).size.must_equal 2
|
57
104
|
n.remove_child 'bar'
|
58
|
-
n.find(
|
105
|
+
n.find(:bar).size.must_equal 1
|
59
106
|
end
|
60
107
|
|
61
108
|
it 'will remove a child with a specific xmlns' do
|
62
109
|
n = XMPPNode.new 'foo'
|
63
110
|
n << XMPPNode.new('bar')
|
64
111
|
c = XMPPNode.new('bar')
|
65
|
-
c.
|
112
|
+
c.namespace = 'foo:bar'
|
66
113
|
n << c
|
67
114
|
|
68
|
-
n.find(
|
115
|
+
n.find(:bar).size.must_equal 2
|
69
116
|
n.remove_child 'bar', 'foo:bar'
|
70
|
-
n.find(
|
71
|
-
n.find(
|
117
|
+
n.find(:bar).size.must_equal 1
|
118
|
+
n.find(:bar).first.namespace.must_be_nil
|
72
119
|
end
|
73
120
|
|
74
121
|
it 'will remove all child elements' do
|
@@ -76,9 +123,9 @@ describe 'Blather::XMPPNode' do
|
|
76
123
|
n << XMPPNode.new('bar')
|
77
124
|
n << XMPPNode.new('bar')
|
78
125
|
|
79
|
-
n.find(
|
126
|
+
n.find(:bar).size.must_equal 2
|
80
127
|
n.remove_children 'bar'
|
81
|
-
n.find(
|
128
|
+
n.find(:bar).size.must_equal 0
|
82
129
|
end
|
83
130
|
|
84
131
|
it 'provides a helper to grab content from a child' do
|
@@ -113,18 +160,24 @@ describe 'Blather::XMPPNode' do
|
|
113
160
|
n['foo'].must_equal 'bar'
|
114
161
|
end
|
115
162
|
|
116
|
-
it 'cuts line breaks out of #
|
163
|
+
it 'cuts line breaks out of #to_xml' do
|
117
164
|
n = XMPPNode.new 'foo'
|
118
165
|
n << XMPPNode.new('bar', 'baz')
|
119
|
-
n.
|
166
|
+
n.to_xml.scan(">\n<").size.must_equal 0
|
120
167
|
end
|
121
168
|
|
122
169
|
it 'overrides #find to find without xpath' do
|
123
170
|
n = XMPPNode.new 'foo'
|
124
171
|
n << XMPPNode.new('bar', 'baz')
|
125
|
-
n.find(
|
172
|
+
n.find(:bar).must_be_kind_of Array
|
126
173
|
|
127
174
|
XML::Document.new.root = n
|
128
|
-
n.find(
|
175
|
+
n.find(:bar).must_be_kind_of XML::XPath::Object
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'can find using a symbol' do
|
179
|
+
n = XMPPNode.new 'foo'
|
180
|
+
n << XMPPNode.new('bar', 'baz')
|
181
|
+
n.find(:bar).first.to_s.must_equal "<bar>baz</bar>"
|
129
182
|
end
|
130
183
|
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
def items_all_nodes_xml
|
2
|
+
<<-ITEMS
|
3
|
+
<iq type='result'
|
4
|
+
from='pubsub.shakespeare.lit'
|
5
|
+
to='francisco@denmark.lit/barracks'
|
6
|
+
id='items1'>
|
7
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
8
|
+
<items node='princely_musings'>
|
9
|
+
<item id='368866411b877c30064a5f62b917cffe'>
|
10
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
11
|
+
<title>The Uses of This World</title>
|
12
|
+
<summary>
|
13
|
+
O, that this too too solid flesh would melt
|
14
|
+
Thaw and resolve itself into a dew!
|
15
|
+
</summary>
|
16
|
+
<link rel='alternate' type='text/html'
|
17
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
18
|
+
<id>tag:denmark.lit,2003:entry-32396</id>
|
19
|
+
<published>2003-12-12T17:47:23Z</published>
|
20
|
+
<updated>2003-12-12T17:47:23Z</updated>
|
21
|
+
</entry>
|
22
|
+
</item>
|
23
|
+
<item id='3300659945416e274474e469a1f0154c'>
|
24
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
25
|
+
<title>Ghostly Encounters</title>
|
26
|
+
<summary>
|
27
|
+
O all you host of heaven! O earth! what else?
|
28
|
+
And shall I couple hell? O, fie! Hold, hold, my heart;
|
29
|
+
And you, my sinews, grow not instant old,
|
30
|
+
But bear me stiffly up. Remember thee!
|
31
|
+
</summary>
|
32
|
+
<link rel='alternate' type='text/html'
|
33
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
34
|
+
<id>tag:denmark.lit,2003:entry-32396</id>
|
35
|
+
<published>2003-12-12T23:21:34Z</published>
|
36
|
+
<updated>2003-12-12T23:21:34Z</updated>
|
37
|
+
</entry>
|
38
|
+
</item>
|
39
|
+
<item id='4e30f35051b7b8b42abe083742187228'>
|
40
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
41
|
+
<title>Alone</title>
|
42
|
+
<summary>
|
43
|
+
Now I am alone.
|
44
|
+
O, what a rogue and peasant slave am I!
|
45
|
+
</summary>
|
46
|
+
<link rel='alternate' type='text/html'
|
47
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
48
|
+
<id>tag:denmark.lit,2003:entry-32396</id>
|
49
|
+
<published>2003-12-13T11:09:53Z</published>
|
50
|
+
<updated>2003-12-13T11:09:53Z</updated>
|
51
|
+
</entry>
|
52
|
+
</item>
|
53
|
+
<item id='ae890ac52d0df67ed7cfdf51b644e901'>
|
54
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
55
|
+
<title>Soliloquy</title>
|
56
|
+
<summary>
|
57
|
+
To be, or not to be: that is the question:
|
58
|
+
Whether 'tis nobler in the mind to suffer
|
59
|
+
The slings and arrows of outrageous fortune,
|
60
|
+
Or to take arms against a sea of troubles,
|
61
|
+
And by opposing end them?
|
62
|
+
</summary>
|
63
|
+
<link rel='alternate' type='text/html'
|
64
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
65
|
+
<id>tag:denmark.lit,2003:entry-32397</id>
|
66
|
+
<published>2003-12-13T18:30:02Z</published>
|
67
|
+
<updated>2003-12-13T18:30:02Z</updated>
|
68
|
+
</entry>
|
69
|
+
</item>
|
70
|
+
</items>
|
71
|
+
</pubsub>
|
72
|
+
</iq>
|
73
|
+
ITEMS
|
74
|
+
end
|
75
|
+
|
76
|
+
def pubsub_items_some_xml
|
77
|
+
<<-ITEMS
|
78
|
+
<iq type='result'
|
79
|
+
from='pubsub.shakespeare.lit'
|
80
|
+
to='francisco@denmark.lit/barracks'
|
81
|
+
id='items1'>
|
82
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
83
|
+
<items node='princely_musings'>
|
84
|
+
<item id='368866411b877c30064a5f62b917cffe'>
|
85
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
86
|
+
<title>The Uses of This World</title>
|
87
|
+
<summary>
|
88
|
+
O, that this too too solid flesh would melt
|
89
|
+
Thaw and resolve itself into a dew!
|
90
|
+
</summary>
|
91
|
+
<link rel='alternate' type='text/html'
|
92
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
93
|
+
<id>tag:denmark.lit,2003:entry-32396</id>
|
94
|
+
<published>2003-12-12T17:47:23Z</published>
|
95
|
+
<updated>2003-12-12T17:47:23Z</updated>
|
96
|
+
</entry>
|
97
|
+
</item>
|
98
|
+
<item id='3300659945416e274474e469a1f0154c'>
|
99
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
100
|
+
<title>Ghostly Encounters</title>
|
101
|
+
<summary>
|
102
|
+
O all you host of heaven! O earth! what else?
|
103
|
+
And shall I couple hell? O, fie! Hold, hold, my heart;
|
104
|
+
And you, my sinews, grow not instant old,
|
105
|
+
But bear me stiffly up. Remember thee!
|
106
|
+
</summary>
|
107
|
+
<link rel='alternate' type='text/html'
|
108
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
109
|
+
<id>tag:denmark.lit,2003:entry-32396</id>
|
110
|
+
<published>2003-12-12T23:21:34Z</published>
|
111
|
+
<updated>2003-12-12T23:21:34Z</updated>
|
112
|
+
</entry>
|
113
|
+
</item>
|
114
|
+
<item id='4e30f35051b7b8b42abe083742187228'>
|
115
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
116
|
+
<title>Alone</title>
|
117
|
+
<summary>
|
118
|
+
Now I am alone.
|
119
|
+
O, what a rogue and peasant slave am I!
|
120
|
+
</summary>
|
121
|
+
<link rel='alternate' type='text/html'
|
122
|
+
href='http://denmark.lit/2003/12/13/atom03'/>
|
123
|
+
<id>tag:denmark.lit,2003:entry-32396</id>
|
124
|
+
<published>2003-12-13T11:09:53Z</published>
|
125
|
+
<updated>2003-12-13T11:09:53Z</updated>
|
126
|
+
</entry>
|
127
|
+
</item>
|
128
|
+
</items>
|
129
|
+
<set xmlns='http://jabber.org/protocol/rsm'>
|
130
|
+
<first index='0'>368866411b877c30064a5f62b917cffe</first>
|
131
|
+
<last>4e30f35051b7b8b42abe083742187228</last>
|
132
|
+
<count>19</count>
|
133
|
+
</set>
|
134
|
+
</pubsub>
|
135
|
+
</iq>
|
136
|
+
ITEMS
|
137
|
+
end
|
138
|
+
|
139
|
+
def affiliations_xml
|
140
|
+
<<-NODE
|
141
|
+
<iq type='result'
|
142
|
+
from='pubsub.shakespeare.lit'
|
143
|
+
to='francisco@denmark.lit'
|
144
|
+
id='affil1'>
|
145
|
+
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
146
|
+
<affiliations>
|
147
|
+
<affiliation node='node1' affiliation='owner'/>
|
148
|
+
<affiliation node='node2' affiliation='owner'/>
|
149
|
+
<affiliation node='node3' affiliation='publisher'/>
|
150
|
+
<affiliation node='node4' affiliation='outcast'/>
|
151
|
+
<affiliation node='node5' affiliation='member'/>
|
152
|
+
<affiliation node='node6' affiliation='none'/>
|
153
|
+
</affiliations>
|
154
|
+
</pubsub>
|
155
|
+
</iq>
|
156
|
+
NODE
|
157
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,27 +2,23 @@ require File.join(File.dirname(__FILE__), *%w[.. lib blather])
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'minitest/spec'
|
4
4
|
require 'mocha'
|
5
|
+
require 'mocha/expectation_error'
|
5
6
|
|
6
7
|
module MiniTest
|
7
|
-
if MINI_DIR =~ %r{^./}
|
8
|
-
require 'pathname'
|
9
|
-
path = Pathname.new(MINI_DIR).realpath
|
10
|
-
# remove_const 'MINI_DIR'
|
11
|
-
# const_set 'MINI_DIR', path.to_s
|
12
|
-
end
|
8
|
+
require 'pathname' if MINI_DIR =~ %r{^./}
|
13
9
|
|
14
10
|
module Assertions
|
15
|
-
def assert_change(
|
11
|
+
def assert_change(stmt, args = {}, msg = nil)
|
16
12
|
msg ||= proc {
|
17
|
-
m = "Expected #{
|
13
|
+
m = "Expected #{stmt} to change"
|
18
14
|
m << " by #{mu_pp args[:by]}" if args[:by]
|
19
15
|
m << (args[:from] ? " from #{mu_pp args[:from]}" : '') + " to #{mu_pp args[:to]}" if args[:to]
|
20
16
|
m
|
21
17
|
}.call
|
22
18
|
|
23
|
-
init_val = eval(
|
19
|
+
init_val = eval(stmt)
|
24
20
|
yield
|
25
|
-
new_val = eval(
|
21
|
+
new_val = eval(stmt)
|
26
22
|
|
27
23
|
assert_equal(args[:by], (new_val - init_val), msg) if args[:by]
|
28
24
|
assert_equal([args[:from], args[:to]], [(init_val if args[:from]), new_val], msg) if args[:to]
|
@@ -37,11 +33,7 @@ class Object
|
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
|
-
require 'mocha/expectation_error'
|
41
|
-
|
42
36
|
include Blather
|
43
37
|
include MiniTest
|
44
38
|
|
45
|
-
LOG.level = Logger::INFO
|
46
|
-
|
47
39
|
Unit.autorun
|