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.
- 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
|