Allow XEP 0092 to send os information
[slixmpp.git] / tests / test_stanza_element.py
blobf7387d36346b7390462cbfbd5e3c6dfb63d8cbf1
1 from sleekxmpp.test import *
2 from sleekxmpp.xmlstream.stanzabase import ElementBase
5 class TestElementBase(SleekTest):
7 def testFixNs(self):
8 """Test fixing namespaces in an XPath expression."""
10 e = ElementBase()
11 ns = "http://jabber.org/protocol/disco#items"
12 result = e._fix_ns("{%s}foo/bar/{abc}baz/{%s}more" % (ns, ns))
14 expected = "/".join(["{%s}foo" % ns,
15 "{%s}bar" % ns,
16 "{abc}baz",
17 "{%s}more" % ns])
18 self.failUnless(expected == result,
19 "Incorrect namespace fixing result: %s" % str(result))
22 def testExtendedName(self):
23 """Test element names of the form tag1/tag2/tag3."""
25 class TestStanza(ElementBase):
26 name = "foo/bar/baz"
27 namespace = "test"
29 stanza = TestStanza()
30 self.check(stanza, """
31 <foo xmlns="test">
32 <bar>
33 <baz />
34 </bar>
35 </foo>
36 """)
38 def testGetStanzaValues(self):
39 """Test getStanzaValues using plugins and substanzas."""
41 class TestStanzaPlugin(ElementBase):
42 name = "foo2"
43 namespace = "foo"
44 interfaces = set(('bar', 'baz'))
45 plugin_attrib = "foo2"
47 class TestSubStanza(ElementBase):
48 name = "subfoo"
49 namespace = "foo"
50 interfaces = set(('bar', 'baz'))
52 class TestStanza(ElementBase):
53 name = "foo"
54 namespace = "foo"
55 interfaces = set(('bar', 'baz'))
56 subitem = set((TestSubStanza,))
58 register_stanza_plugin(TestStanza, TestStanzaPlugin)
60 stanza = TestStanza()
61 stanza['bar'] = 'a'
62 stanza['foo2']['baz'] = 'b'
63 substanza = TestSubStanza()
64 substanza['bar'] = 'c'
65 stanza.append(substanza)
67 values = stanza.getStanzaValues()
68 expected = {'bar': 'a',
69 'baz': '',
70 'foo2': {'bar': '',
71 'baz': 'b'},
72 'substanzas': [{'__childtag__': '{foo}subfoo',
73 'bar': 'c',
74 'baz': ''}]}
75 self.failUnless(values == expected,
76 "Unexpected stanza values:\n%s\n%s" % (str(expected), str(values)))
79 def testSetStanzaValues(self):
80 """Test using setStanzaValues with substanzas and plugins."""
82 class TestStanzaPlugin(ElementBase):
83 name = "pluginfoo"
84 namespace = "foo"
85 interfaces = set(('bar', 'baz'))
86 plugin_attrib = "plugin_foo"
88 class TestStanzaPlugin2(ElementBase):
89 name = "pluginfoo2"
90 namespace = "foo"
91 interfaces = set(('bar', 'baz'))
92 plugin_attrib = "plugin_foo2"
94 class TestSubStanza(ElementBase):
95 name = "subfoo"
96 namespace = "foo"
97 interfaces = set(('bar', 'baz'))
99 class TestStanza(ElementBase):
100 name = "foo"
101 namespace = "foo"
102 interfaces = set(('bar', 'baz'))
103 subitem = set((TestSubStanza,))
105 register_stanza_plugin(TestStanza, TestStanzaPlugin)
106 register_stanza_plugin(TestStanza, TestStanzaPlugin2)
108 stanza = TestStanza()
109 values = {'bar': 'a',
110 'baz': '',
111 'plugin_foo': {'bar': '',
112 'baz': 'b'},
113 'plugin_foo2': {'bar': 'd',
114 'baz': 'e'},
115 'substanzas': [{'__childtag__': '{foo}subfoo',
116 'bar': 'c',
117 'baz': ''}]}
118 stanza.setStanzaValues(values)
120 self.check(stanza, """
121 <foo xmlns="foo" bar="a">
122 <pluginfoo baz="b" />
123 <pluginfoo2 bar="d" baz="e" />
124 <subfoo bar="c" />
125 </foo>
126 """)
128 def testGetItem(self):
129 """Test accessing stanza interfaces."""
131 class TestStanza(ElementBase):
132 name = "foo"
133 namespace = "foo"
134 interfaces = set(('bar', 'baz', 'qux'))
135 sub_interfaces = set(('baz',))
137 def getQux(self):
138 return 'qux'
140 class TestStanzaPlugin(ElementBase):
141 name = "foobar"
142 namespace = "foo"
143 plugin_attrib = "foobar"
144 interfaces = set(('fizz',))
146 TestStanza.subitem = (TestStanza,)
147 register_stanza_plugin(TestStanza, TestStanzaPlugin)
149 stanza = TestStanza()
150 substanza = TestStanza()
151 stanza.append(substanza)
152 stanza.setStanzaValues({'bar': 'a',
153 'baz': 'b',
154 'qux': 42,
155 'foobar': {'fizz': 'c'}})
157 # Test non-plugin interfaces
158 expected = {'substanzas': [substanza],
159 'bar': 'a',
160 'baz': 'b',
161 'qux': 'qux',
162 'meh': ''}
163 for interface, value in expected.items():
164 result = stanza[interface]
165 self.failUnless(result == value,
166 "Incorrect stanza interface access result: %s" % result)
168 # Test plugin interfaces
169 self.failUnless(isinstance(stanza['foobar'], TestStanzaPlugin),
170 "Incorrect plugin object result.")
171 self.failUnless(stanza['foobar']['fizz'] == 'c',
172 "Incorrect plugin subvalue result.")
174 def testSetItem(self):
175 """Test assigning to stanza interfaces."""
177 class TestStanza(ElementBase):
178 name = "foo"
179 namespace = "foo"
180 interfaces = set(('bar', 'baz', 'qux'))
181 sub_interfaces = set(('baz',))
183 def setQux(self, value):
184 pass
186 class TestStanzaPlugin(ElementBase):
187 name = "foobar"
188 namespace = "foo"
189 plugin_attrib = "foobar"
190 interfaces = set(('foobar',))
192 register_stanza_plugin(TestStanza, TestStanzaPlugin)
194 stanza = TestStanza()
196 stanza['bar'] = 'attribute!'
197 stanza['baz'] = 'element!'
198 stanza['qux'] = 'overridden'
199 stanza['foobar'] = 'plugin'
201 self.check(stanza, """
202 <foo xmlns="foo" bar="attribute!">
203 <baz>element!</baz>
204 <foobar foobar="plugin" />
205 </foo>
206 """)
208 def testDelItem(self):
209 """Test deleting stanza interface values."""
211 class TestStanza(ElementBase):
212 name = "foo"
213 namespace = "foo"
214 interfaces = set(('bar', 'baz', 'qux'))
215 sub_interfaces = set(('bar',))
217 def delQux(self):
218 pass
220 class TestStanzaPlugin(ElementBase):
221 name = "foobar"
222 namespace = "foo"
223 plugin_attrib = "foobar"
224 interfaces = set(('foobar',))
226 register_stanza_plugin(TestStanza, TestStanzaPlugin)
228 stanza = TestStanza()
229 stanza['bar'] = 'a'
230 stanza['baz'] = 'b'
231 stanza['qux'] = 'c'
232 stanza['foobar']['foobar'] = 'd'
234 self.check(stanza, """
235 <foo xmlns="foo" baz="b" qux="c">
236 <bar>a</bar>
237 <foobar foobar="d" />
238 </foo>
239 """)
241 del stanza['bar']
242 del stanza['baz']
243 del stanza['qux']
244 del stanza['foobar']
246 self.check(stanza, """
247 <foo xmlns="foo" qux="c" />
248 """)
250 def testModifyingAttributes(self):
251 """Test modifying top level attributes of a stanza's XML object."""
253 class TestStanza(ElementBase):
254 name = "foo"
255 namespace = "foo"
256 interfaces = set(('bar', 'baz'))
258 stanza = TestStanza()
260 self.check(stanza, """
261 <foo xmlns="foo" />
262 """)
264 self.failUnless(stanza._get_attr('bar') == '',
265 "Incorrect value returned for an unset XML attribute.")
267 stanza._set_attr('bar', 'a')
268 stanza._set_attr('baz', 'b')
270 self.check(stanza, """
271 <foo xmlns="foo" bar="a" baz="b" />
272 """)
274 self.failUnless(stanza._get_attr('bar') == 'a',
275 "Retrieved XML attribute value is incorrect.")
277 stanza._set_attr('bar', None)
278 stanza._del_attr('baz')
280 self.check(stanza, """
281 <foo xmlns="foo" />
282 """)
284 self.failUnless(stanza._get_attr('bar', 'c') == 'c',
285 "Incorrect default value returned for an unset XML attribute.")
287 def testGetSubText(self):
288 """Test retrieving the contents of a sub element."""
290 class TestStanza(ElementBase):
291 name = "foo"
292 namespace = "foo"
293 interfaces = set(('bar',))
295 def setBar(self, value):
296 wrapper = ET.Element("{foo}wrapper")
297 bar = ET.Element("{foo}bar")
298 bar.text = value
299 wrapper.append(bar)
300 self.xml.append(wrapper)
302 def getBar(self):
303 return self._get_sub_text("wrapper/bar", default="not found")
305 stanza = TestStanza()
306 self.failUnless(stanza['bar'] == 'not found',
307 "Default _get_sub_text value incorrect.")
309 stanza['bar'] = 'found'
310 self.check(stanza, """
311 <foo xmlns="foo">
312 <wrapper>
313 <bar>found</bar>
314 </wrapper>
315 </foo>
316 """)
317 self.failUnless(stanza['bar'] == 'found',
318 "_get_sub_text value incorrect: %s." % stanza['bar'])
320 def testSubElement(self):
321 """Test setting the contents of a sub element."""
323 class TestStanza(ElementBase):
324 name = "foo"
325 namespace = "foo"
326 interfaces = set(('bar', 'baz'))
328 def setBaz(self, value):
329 self._set_sub_text("wrapper/baz", text=value)
331 def getBaz(self):
332 return self._get_sub_text("wrapper/baz")
334 def setBar(self, value):
335 self._set_sub_text("wrapper/bar", text=value)
337 def getBar(self):
338 return self._get_sub_text("wrapper/bar")
340 stanza = TestStanza()
341 stanza['bar'] = 'a'
342 stanza['baz'] = 'b'
343 self.check(stanza, """
344 <foo xmlns="foo">
345 <wrapper>
346 <bar>a</bar>
347 <baz>b</baz>
348 </wrapper>
349 </foo>
350 """)
351 stanza._set_sub_text('wrapper/bar', text='', keep=True)
352 self.check(stanza, """
353 <foo xmlns="foo">
354 <wrapper>
355 <bar />
356 <baz>b</baz>
357 </wrapper>
358 </foo>
359 """, use_values=False)
361 stanza['bar'] = 'a'
362 stanza._set_sub_text('wrapper/bar', text='')
363 self.check(stanza, """
364 <foo xmlns="foo">
365 <wrapper>
366 <baz>b</baz>
367 </wrapper>
368 </foo>
369 """)
371 def testDelSub(self):
372 """Test removing sub elements."""
374 class TestStanza(ElementBase):
375 name = "foo"
376 namespace = "foo"
377 interfaces = set(('bar', 'baz'))
379 def setBar(self, value):
380 self._set_sub_text("path/to/only/bar", value);
382 def getBar(self):
383 return self._get_sub_text("path/to/only/bar")
385 def delBar(self):
386 self._del_sub("path/to/only/bar")
388 def setBaz(self, value):
389 self._set_sub_text("path/to/just/baz", value);
391 def getBaz(self):
392 return self._get_sub_text("path/to/just/baz")
394 def delBaz(self):
395 self._del_sub("path/to/just/baz")
397 stanza = TestStanza()
398 stanza['bar'] = 'a'
399 stanza['baz'] = 'b'
401 self.check(stanza, """
402 <foo xmlns="foo">
403 <path>
404 <to>
405 <only>
406 <bar>a</bar>
407 </only>
408 <just>
409 <baz>b</baz>
410 </just>
411 </to>
412 </path>
413 </foo>
414 """)
416 del stanza['bar']
417 del stanza['baz']
419 self.check(stanza, """
420 <foo xmlns="foo">
421 <path>
422 <to>
423 <only />
424 <just />
425 </to>
426 </path>
427 </foo>
428 """, use_values=False)
430 stanza['bar'] = 'a'
431 stanza['baz'] = 'b'
433 stanza._del_sub('path/to/only/bar', all=True)
435 self.check(stanza, """
436 <foo xmlns="foo">
437 <path>
438 <to>
439 <just>
440 <baz>b</baz>
441 </just>
442 </to>
443 </path>
444 </foo>
445 """)
447 def testMatch(self):
448 """Test matching a stanza against an XPath expression."""
450 class TestSubStanza(ElementBase):
451 name = "sub"
452 namespace = "baz"
453 interfaces = set(('attrib',))
455 class TestStanza(ElementBase):
456 name = "foo"
457 namespace = "foo"
458 interfaces = set(('bar','baz', 'qux'))
459 sub_interfaces = set(('qux',))
460 subitem = (TestSubStanza,)
462 def setQux(self, value):
463 self._set_sub_text('qux', text=value)
465 def getQux(self):
466 return self._get_sub_text('qux')
468 class TestStanzaPlugin(ElementBase):
469 name = "plugin"
470 namespace = "http://test/slash/bar"
471 interfaces = set(('attrib',))
473 register_stanza_plugin(TestStanza, TestStanzaPlugin)
475 stanza = TestStanza()
476 self.failUnless(stanza.match("foo"),
477 "Stanza did not match its own tag name.")
479 self.failUnless(stanza.match("{foo}foo"),
480 "Stanza did not match its own namespaced name.")
482 stanza['bar'] = 'a'
483 self.failUnless(stanza.match("foo@bar=a"),
484 "Stanza did not match its own name with attribute value check.")
486 stanza['baz'] = 'b'
487 self.failUnless(stanza.match("foo@bar=a@baz=b"),
488 "Stanza did not match its own name with multiple attributes.")
490 stanza['qux'] = 'c'
491 self.failUnless(stanza.match("foo/qux"),
492 "Stanza did not match with subelements.")
494 stanza['qux'] = ''
495 self.failUnless(stanza.match("foo/qux") == False,
496 "Stanza matched missing subinterface element.")
498 self.failUnless(stanza.match("foo/bar") == False,
499 "Stanza matched nonexistent element.")
501 stanza['plugin']['attrib'] = 'c'
502 self.failUnless(stanza.match("foo/plugin@attrib=c"),
503 "Stanza did not match with plugin and attribute.")
505 self.failUnless(stanza.match("foo/{http://test/slash/bar}plugin"),
506 "Stanza did not match with namespaced plugin.")
508 substanza = TestSubStanza()
509 substanza['attrib'] = 'd'
510 stanza.append(substanza)
511 self.failUnless(stanza.match("foo/sub@attrib=d"),
512 "Stanza did not match with substanzas and attribute.")
514 self.failUnless(stanza.match("foo/{baz}sub"),
515 "Stanza did not match with namespaced substanza.")
517 def testComparisons(self):
518 """Test comparing ElementBase objects."""
520 class TestStanza(ElementBase):
521 name = "foo"
522 namespace = "foo"
523 interfaces = set(('bar', 'baz'))
525 stanza1 = TestStanza()
526 stanza1['bar'] = 'a'
528 self.failUnless(stanza1,
529 "Stanza object does not evaluate to True")
531 stanza2 = TestStanza()
532 stanza2['baz'] = 'b'
534 self.failUnless(stanza1 != stanza2,
535 "Different stanza objects incorrectly compared equal.")
537 stanza1['baz'] = 'b'
538 stanza2['bar'] = 'a'
540 self.failUnless(stanza1 == stanza2,
541 "Equal stanzas incorrectly compared inequal.")
543 def testKeys(self):
544 """Test extracting interface names from a stanza object."""
546 class TestStanza(ElementBase):
547 name = "foo"
548 namespace = "foo"
549 interfaces = set(('bar', 'baz'))
550 plugin_attrib = 'qux'
552 register_stanza_plugin(TestStanza, TestStanza)
554 stanza = TestStanza()
556 self.failUnless(set(stanza.keys()) == set(('bar', 'baz')),
557 "Returned set of interface keys does not match expected.")
559 stanza.enable('qux')
561 self.failUnless(set(stanza.keys()) == set(('bar', 'baz', 'qux')),
562 "Incorrect set of interface and plugin keys.")
564 def testGet(self):
565 """Test accessing stanza interfaces using get()."""
567 class TestStanza(ElementBase):
568 name = "foo"
569 namespace = "foo"
570 interfaces = set(('bar', 'baz'))
572 stanza = TestStanza()
573 stanza['bar'] = 'a'
575 self.failUnless(stanza.get('bar') == 'a',
576 "Incorrect value returned by stanza.get")
578 self.failUnless(stanza.get('baz', 'b') == 'b',
579 "Incorrect default value returned by stanza.get")
581 def testSubStanzas(self):
582 """Test manipulating substanzas of a stanza object."""
584 class TestSubStanza(ElementBase):
585 name = "foobar"
586 namespace = "foo"
587 interfaces = set(('qux',))
589 class TestStanza(ElementBase):
590 name = "foo"
591 namespace = "foo"
592 interfaces = set(('bar', 'baz'))
593 subitem = (TestSubStanza,)
595 stanza = TestStanza()
596 substanza1 = TestSubStanza()
597 substanza2 = TestSubStanza()
598 substanza1['qux'] = 'a'
599 substanza2['qux'] = 'b'
601 # Test appending substanzas
602 self.failUnless(len(stanza) == 0,
603 "Incorrect empty stanza size.")
605 stanza.append(substanza1)
606 self.check(stanza, """
607 <foo xmlns="foo">
608 <foobar qux="a" />
609 </foo>
610 """, use_values=False)
611 self.failUnless(len(stanza) == 1,
612 "Incorrect stanza size with 1 substanza.")
614 stanza.append(substanza2)
615 self.check(stanza, """
616 <foo xmlns="foo">
617 <foobar qux="a" />
618 <foobar qux="b" />
619 </foo>
620 """, use_values=False)
621 self.failUnless(len(stanza) == 2,
622 "Incorrect stanza size with 2 substanzas.")
624 # Test popping substanzas
625 stanza.pop(0)
626 self.check(stanza, """
627 <foo xmlns="foo">
628 <foobar qux="b" />
629 </foo>
630 """, use_values=False)
632 # Test iterating over substanzas
633 stanza.append(substanza1)
634 results = []
635 for substanza in stanza:
636 results.append(substanza['qux'])
637 self.failUnless(results == ['b', 'a'],
638 "Iteration over substanzas failed: %s." % str(results))
640 def testCopy(self):
641 """Test copying stanza objects."""
643 class TestStanza(ElementBase):
644 name = "foo"
645 namespace = "foo"
646 interfaces = set(('bar', 'baz'))
648 stanza1 = TestStanza()
649 stanza1['bar'] = 'a'
651 stanza2 = stanza1.__copy__()
653 self.failUnless(stanza1 == stanza2,
654 "Copied stanzas are not equal to each other.")
656 stanza1['baz'] = 'b'
657 self.failUnless(stanza1 != stanza2,
658 "Divergent stanza copies incorrectly compared equal.")
660 suite = unittest.TestLoader().loadTestsFromTestCase(TestElementBase)