|
1 # regression test for SAX 2.0 -*- coding: iso-8859-1 -*- |
|
2 # $Id: test_sax.py 54954 2007-04-25 06:42:41Z neal.norwitz $ |
|
3 |
|
4 from xml.sax import make_parser, ContentHandler, \ |
|
5 SAXException, SAXReaderNotAvailable, SAXParseException |
|
6 try: |
|
7 make_parser() |
|
8 except SAXReaderNotAvailable: |
|
9 # don't try to test this module if we cannot create a parser |
|
10 raise ImportError("no XML parsers available") |
|
11 from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \ |
|
12 XMLFilterBase |
|
13 from xml.sax.expatreader import create_parser |
|
14 from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl |
|
15 from cStringIO import StringIO |
|
16 from test.test_support import verify, verbose, TestFailed, findfile |
|
17 import os |
|
18 |
|
19 # ===== Utilities |
|
20 |
|
21 tests = 0 |
|
22 failures = [] |
|
23 |
|
24 def confirm(outcome, name): |
|
25 global tests |
|
26 |
|
27 tests = tests + 1 |
|
28 if outcome: |
|
29 if verbose: |
|
30 print "Passed", name |
|
31 else: |
|
32 failures.append(name) |
|
33 |
|
34 def test_make_parser2(): |
|
35 try: |
|
36 # Creating parsers several times in a row should succeed. |
|
37 # Testing this because there have been failures of this kind |
|
38 # before. |
|
39 from xml.sax import make_parser |
|
40 p = make_parser() |
|
41 from xml.sax import make_parser |
|
42 p = make_parser() |
|
43 from xml.sax import make_parser |
|
44 p = make_parser() |
|
45 from xml.sax import make_parser |
|
46 p = make_parser() |
|
47 from xml.sax import make_parser |
|
48 p = make_parser() |
|
49 from xml.sax import make_parser |
|
50 p = make_parser() |
|
51 except: |
|
52 return 0 |
|
53 else: |
|
54 return p |
|
55 |
|
56 |
|
57 # =========================================================================== |
|
58 # |
|
59 # saxutils tests |
|
60 # |
|
61 # =========================================================================== |
|
62 |
|
63 # ===== escape |
|
64 |
|
65 def test_escape_basic(): |
|
66 return escape("Donald Duck & Co") == "Donald Duck & Co" |
|
67 |
|
68 def test_escape_all(): |
|
69 return escape("<Donald Duck & Co>") == "<Donald Duck & Co>" |
|
70 |
|
71 def test_escape_extra(): |
|
72 return escape("Hei på deg", {"å" : "å"}) == "Hei på deg" |
|
73 |
|
74 # ===== unescape |
|
75 |
|
76 def test_unescape_basic(): |
|
77 return unescape("Donald Duck & Co") == "Donald Duck & Co" |
|
78 |
|
79 def test_unescape_all(): |
|
80 return unescape("<Donald Duck & Co>") == "<Donald Duck & Co>" |
|
81 |
|
82 def test_unescape_extra(): |
|
83 return unescape("Hei på deg", {"å" : "å"}) == "Hei på deg" |
|
84 |
|
85 def test_unescape_amp_extra(): |
|
86 return unescape("&foo;", {"&foo;": "splat"}) == "&foo;" |
|
87 |
|
88 # ===== quoteattr |
|
89 |
|
90 def test_quoteattr_basic(): |
|
91 return quoteattr("Donald Duck & Co") == '"Donald Duck & Co"' |
|
92 |
|
93 def test_single_quoteattr(): |
|
94 return (quoteattr('Includes "double" quotes') |
|
95 == '\'Includes "double" quotes\'') |
|
96 |
|
97 def test_double_quoteattr(): |
|
98 return (quoteattr("Includes 'single' quotes") |
|
99 == "\"Includes 'single' quotes\"") |
|
100 |
|
101 def test_single_double_quoteattr(): |
|
102 return (quoteattr("Includes 'single' and \"double\" quotes") |
|
103 == "\"Includes 'single' and "double" quotes\"") |
|
104 |
|
105 # ===== make_parser |
|
106 |
|
107 def test_make_parser(): |
|
108 try: |
|
109 # Creating a parser should succeed - it should fall back |
|
110 # to the expatreader |
|
111 p = make_parser(['xml.parsers.no_such_parser']) |
|
112 except: |
|
113 return 0 |
|
114 else: |
|
115 return p |
|
116 |
|
117 |
|
118 # ===== XMLGenerator |
|
119 |
|
120 start = '<?xml version="1.0" encoding="iso-8859-1"?>\n' |
|
121 |
|
122 def test_xmlgen_basic(): |
|
123 result = StringIO() |
|
124 gen = XMLGenerator(result) |
|
125 gen.startDocument() |
|
126 gen.startElement("doc", {}) |
|
127 gen.endElement("doc") |
|
128 gen.endDocument() |
|
129 |
|
130 return result.getvalue() == start + "<doc></doc>" |
|
131 |
|
132 def test_xmlgen_content(): |
|
133 result = StringIO() |
|
134 gen = XMLGenerator(result) |
|
135 |
|
136 gen.startDocument() |
|
137 gen.startElement("doc", {}) |
|
138 gen.characters("huhei") |
|
139 gen.endElement("doc") |
|
140 gen.endDocument() |
|
141 |
|
142 return result.getvalue() == start + "<doc>huhei</doc>" |
|
143 |
|
144 def test_xmlgen_pi(): |
|
145 result = StringIO() |
|
146 gen = XMLGenerator(result) |
|
147 |
|
148 gen.startDocument() |
|
149 gen.processingInstruction("test", "data") |
|
150 gen.startElement("doc", {}) |
|
151 gen.endElement("doc") |
|
152 gen.endDocument() |
|
153 |
|
154 return result.getvalue() == start + "<?test data?><doc></doc>" |
|
155 |
|
156 def test_xmlgen_content_escape(): |
|
157 result = StringIO() |
|
158 gen = XMLGenerator(result) |
|
159 |
|
160 gen.startDocument() |
|
161 gen.startElement("doc", {}) |
|
162 gen.characters("<huhei&") |
|
163 gen.endElement("doc") |
|
164 gen.endDocument() |
|
165 |
|
166 return result.getvalue() == start + "<doc><huhei&</doc>" |
|
167 |
|
168 def test_xmlgen_attr_escape(): |
|
169 result = StringIO() |
|
170 gen = XMLGenerator(result) |
|
171 |
|
172 gen.startDocument() |
|
173 gen.startElement("doc", {"a": '"'}) |
|
174 gen.startElement("e", {"a": "'"}) |
|
175 gen.endElement("e") |
|
176 gen.startElement("e", {"a": "'\""}) |
|
177 gen.endElement("e") |
|
178 gen.startElement("e", {"a": "\n\r\t"}) |
|
179 gen.endElement("e") |
|
180 gen.endElement("doc") |
|
181 gen.endDocument() |
|
182 |
|
183 return result.getvalue() == start + ("<doc a='\"'><e a=\"'\"></e>" |
|
184 "<e a=\"'"\"></e>" |
|
185 "<e a=\" 	\"></e></doc>") |
|
186 |
|
187 def test_xmlgen_ignorable(): |
|
188 result = StringIO() |
|
189 gen = XMLGenerator(result) |
|
190 |
|
191 gen.startDocument() |
|
192 gen.startElement("doc", {}) |
|
193 gen.ignorableWhitespace(" ") |
|
194 gen.endElement("doc") |
|
195 gen.endDocument() |
|
196 |
|
197 return result.getvalue() == start + "<doc> </doc>" |
|
198 |
|
199 ns_uri = "http://www.python.org/xml-ns/saxtest/" |
|
200 |
|
201 def test_xmlgen_ns(): |
|
202 result = StringIO() |
|
203 gen = XMLGenerator(result) |
|
204 |
|
205 gen.startDocument() |
|
206 gen.startPrefixMapping("ns1", ns_uri) |
|
207 gen.startElementNS((ns_uri, "doc"), "ns1:doc", {}) |
|
208 # add an unqualified name |
|
209 gen.startElementNS((None, "udoc"), None, {}) |
|
210 gen.endElementNS((None, "udoc"), None) |
|
211 gen.endElementNS((ns_uri, "doc"), "ns1:doc") |
|
212 gen.endPrefixMapping("ns1") |
|
213 gen.endDocument() |
|
214 |
|
215 return result.getvalue() == start + \ |
|
216 ('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' % |
|
217 ns_uri) |
|
218 |
|
219 def test_1463026_1(): |
|
220 result = StringIO() |
|
221 gen = XMLGenerator(result) |
|
222 |
|
223 gen.startDocument() |
|
224 gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'}) |
|
225 gen.endElementNS((None, 'a'), 'a') |
|
226 gen.endDocument() |
|
227 |
|
228 return result.getvalue() == start+'<a b="c"></a>' |
|
229 |
|
230 def test_1463026_2(): |
|
231 result = StringIO() |
|
232 gen = XMLGenerator(result) |
|
233 |
|
234 gen.startDocument() |
|
235 gen.startPrefixMapping(None, 'qux') |
|
236 gen.startElementNS(('qux', 'a'), 'a', {}) |
|
237 gen.endElementNS(('qux', 'a'), 'a') |
|
238 gen.endPrefixMapping(None) |
|
239 gen.endDocument() |
|
240 |
|
241 return result.getvalue() == start+'<a xmlns="qux"></a>' |
|
242 |
|
243 def test_1463026_3(): |
|
244 result = StringIO() |
|
245 gen = XMLGenerator(result) |
|
246 |
|
247 gen.startDocument() |
|
248 gen.startPrefixMapping('my', 'qux') |
|
249 gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'}) |
|
250 gen.endElementNS(('qux', 'a'), 'a') |
|
251 gen.endPrefixMapping('my') |
|
252 gen.endDocument() |
|
253 |
|
254 return result.getvalue() == start+'<my:a xmlns:my="qux" b="c"></my:a>' |
|
255 |
|
256 # ===== Xmlfilterbase |
|
257 |
|
258 def test_filter_basic(): |
|
259 result = StringIO() |
|
260 gen = XMLGenerator(result) |
|
261 filter = XMLFilterBase() |
|
262 filter.setContentHandler(gen) |
|
263 |
|
264 filter.startDocument() |
|
265 filter.startElement("doc", {}) |
|
266 filter.characters("content") |
|
267 filter.ignorableWhitespace(" ") |
|
268 filter.endElement("doc") |
|
269 filter.endDocument() |
|
270 |
|
271 return result.getvalue() == start + "<doc>content </doc>" |
|
272 |
|
273 # =========================================================================== |
|
274 # |
|
275 # expatreader tests |
|
276 # |
|
277 # =========================================================================== |
|
278 |
|
279 # ===== XMLReader support |
|
280 |
|
281 def test_expat_file(): |
|
282 parser = create_parser() |
|
283 result = StringIO() |
|
284 xmlgen = XMLGenerator(result) |
|
285 |
|
286 parser.setContentHandler(xmlgen) |
|
287 parser.parse(open(findfile("test"+os.extsep+"xml"))) |
|
288 |
|
289 return result.getvalue() == xml_test_out |
|
290 |
|
291 # ===== DTDHandler support |
|
292 |
|
293 class TestDTDHandler: |
|
294 |
|
295 def __init__(self): |
|
296 self._notations = [] |
|
297 self._entities = [] |
|
298 |
|
299 def notationDecl(self, name, publicId, systemId): |
|
300 self._notations.append((name, publicId, systemId)) |
|
301 |
|
302 def unparsedEntityDecl(self, name, publicId, systemId, ndata): |
|
303 self._entities.append((name, publicId, systemId, ndata)) |
|
304 |
|
305 def test_expat_dtdhandler(): |
|
306 parser = create_parser() |
|
307 handler = TestDTDHandler() |
|
308 parser.setDTDHandler(handler) |
|
309 |
|
310 parser.feed('<!DOCTYPE doc [\n') |
|
311 parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n') |
|
312 parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n') |
|
313 parser.feed(']>\n') |
|
314 parser.feed('<doc></doc>') |
|
315 parser.close() |
|
316 |
|
317 return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \ |
|
318 handler._entities == [("img", None, "expat.gif", "GIF")] |
|
319 |
|
320 # ===== EntityResolver support |
|
321 |
|
322 class TestEntityResolver: |
|
323 |
|
324 def resolveEntity(self, publicId, systemId): |
|
325 inpsrc = InputSource() |
|
326 inpsrc.setByteStream(StringIO("<entity/>")) |
|
327 return inpsrc |
|
328 |
|
329 def test_expat_entityresolver(): |
|
330 parser = create_parser() |
|
331 parser.setEntityResolver(TestEntityResolver()) |
|
332 result = StringIO() |
|
333 parser.setContentHandler(XMLGenerator(result)) |
|
334 |
|
335 parser.feed('<!DOCTYPE doc [\n') |
|
336 parser.feed(' <!ENTITY test SYSTEM "whatever">\n') |
|
337 parser.feed(']>\n') |
|
338 parser.feed('<doc>&test;</doc>') |
|
339 parser.close() |
|
340 |
|
341 return result.getvalue() == start + "<doc><entity></entity></doc>" |
|
342 |
|
343 # ===== Attributes support |
|
344 |
|
345 class AttrGatherer(ContentHandler): |
|
346 |
|
347 def startElement(self, name, attrs): |
|
348 self._attrs = attrs |
|
349 |
|
350 def startElementNS(self, name, qname, attrs): |
|
351 self._attrs = attrs |
|
352 |
|
353 def test_expat_attrs_empty(): |
|
354 parser = create_parser() |
|
355 gather = AttrGatherer() |
|
356 parser.setContentHandler(gather) |
|
357 |
|
358 parser.feed("<doc/>") |
|
359 parser.close() |
|
360 |
|
361 return verify_empty_attrs(gather._attrs) |
|
362 |
|
363 def test_expat_attrs_wattr(): |
|
364 parser = create_parser() |
|
365 gather = AttrGatherer() |
|
366 parser.setContentHandler(gather) |
|
367 |
|
368 parser.feed("<doc attr='val'/>") |
|
369 parser.close() |
|
370 |
|
371 return verify_attrs_wattr(gather._attrs) |
|
372 |
|
373 def test_expat_nsattrs_empty(): |
|
374 parser = create_parser(1) |
|
375 gather = AttrGatherer() |
|
376 parser.setContentHandler(gather) |
|
377 |
|
378 parser.feed("<doc/>") |
|
379 parser.close() |
|
380 |
|
381 return verify_empty_nsattrs(gather._attrs) |
|
382 |
|
383 def test_expat_nsattrs_wattr(): |
|
384 parser = create_parser(1) |
|
385 gather = AttrGatherer() |
|
386 parser.setContentHandler(gather) |
|
387 |
|
388 parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri) |
|
389 parser.close() |
|
390 |
|
391 attrs = gather._attrs |
|
392 |
|
393 return attrs.getLength() == 1 and \ |
|
394 attrs.getNames() == [(ns_uri, "attr")] and \ |
|
395 (attrs.getQNames() == [] or attrs.getQNames() == ["ns:attr"]) and \ |
|
396 len(attrs) == 1 and \ |
|
397 attrs.has_key((ns_uri, "attr")) and \ |
|
398 attrs.keys() == [(ns_uri, "attr")] and \ |
|
399 attrs.get((ns_uri, "attr")) == "val" and \ |
|
400 attrs.get((ns_uri, "attr"), 25) == "val" and \ |
|
401 attrs.items() == [((ns_uri, "attr"), "val")] and \ |
|
402 attrs.values() == ["val"] and \ |
|
403 attrs.getValue((ns_uri, "attr")) == "val" and \ |
|
404 attrs[(ns_uri, "attr")] == "val" |
|
405 |
|
406 # ===== InputSource support |
|
407 |
|
408 xml_test_out = open(findfile("test"+os.extsep+"xml"+os.extsep+"out")).read() |
|
409 |
|
410 def test_expat_inpsource_filename(): |
|
411 parser = create_parser() |
|
412 result = StringIO() |
|
413 xmlgen = XMLGenerator(result) |
|
414 |
|
415 parser.setContentHandler(xmlgen) |
|
416 parser.parse(findfile("test"+os.extsep+"xml")) |
|
417 |
|
418 return result.getvalue() == xml_test_out |
|
419 |
|
420 def test_expat_inpsource_sysid(): |
|
421 parser = create_parser() |
|
422 result = StringIO() |
|
423 xmlgen = XMLGenerator(result) |
|
424 |
|
425 parser.setContentHandler(xmlgen) |
|
426 parser.parse(InputSource(findfile("test"+os.extsep+"xml"))) |
|
427 |
|
428 return result.getvalue() == xml_test_out |
|
429 |
|
430 def test_expat_inpsource_stream(): |
|
431 parser = create_parser() |
|
432 result = StringIO() |
|
433 xmlgen = XMLGenerator(result) |
|
434 |
|
435 parser.setContentHandler(xmlgen) |
|
436 inpsrc = InputSource() |
|
437 inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml"))) |
|
438 parser.parse(inpsrc) |
|
439 |
|
440 return result.getvalue() == xml_test_out |
|
441 |
|
442 # ===== IncrementalParser support |
|
443 |
|
444 def test_expat_incremental(): |
|
445 result = StringIO() |
|
446 xmlgen = XMLGenerator(result) |
|
447 parser = create_parser() |
|
448 parser.setContentHandler(xmlgen) |
|
449 |
|
450 parser.feed("<doc>") |
|
451 parser.feed("</doc>") |
|
452 parser.close() |
|
453 |
|
454 return result.getvalue() == start + "<doc></doc>" |
|
455 |
|
456 def test_expat_incremental_reset(): |
|
457 result = StringIO() |
|
458 xmlgen = XMLGenerator(result) |
|
459 parser = create_parser() |
|
460 parser.setContentHandler(xmlgen) |
|
461 |
|
462 parser.feed("<doc>") |
|
463 parser.feed("text") |
|
464 |
|
465 result = StringIO() |
|
466 xmlgen = XMLGenerator(result) |
|
467 parser.setContentHandler(xmlgen) |
|
468 parser.reset() |
|
469 |
|
470 parser.feed("<doc>") |
|
471 parser.feed("text") |
|
472 parser.feed("</doc>") |
|
473 parser.close() |
|
474 |
|
475 return result.getvalue() == start + "<doc>text</doc>" |
|
476 |
|
477 # ===== Locator support |
|
478 |
|
479 def test_expat_locator_noinfo(): |
|
480 result = StringIO() |
|
481 xmlgen = XMLGenerator(result) |
|
482 parser = create_parser() |
|
483 parser.setContentHandler(xmlgen) |
|
484 |
|
485 parser.feed("<doc>") |
|
486 parser.feed("</doc>") |
|
487 parser.close() |
|
488 |
|
489 return parser.getSystemId() is None and \ |
|
490 parser.getPublicId() is None and \ |
|
491 parser.getLineNumber() == 1 |
|
492 |
|
493 def test_expat_locator_withinfo(): |
|
494 result = StringIO() |
|
495 xmlgen = XMLGenerator(result) |
|
496 parser = create_parser() |
|
497 parser.setContentHandler(xmlgen) |
|
498 parser.parse(findfile("test.xml")) |
|
499 |
|
500 return parser.getSystemId() == findfile("test.xml") and \ |
|
501 parser.getPublicId() is None |
|
502 |
|
503 |
|
504 # =========================================================================== |
|
505 # |
|
506 # error reporting |
|
507 # |
|
508 # =========================================================================== |
|
509 |
|
510 def test_expat_inpsource_location(): |
|
511 parser = create_parser() |
|
512 parser.setContentHandler(ContentHandler()) # do nothing |
|
513 source = InputSource() |
|
514 source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed |
|
515 name = "a file name" |
|
516 source.setSystemId(name) |
|
517 try: |
|
518 parser.parse(source) |
|
519 except SAXException, e: |
|
520 return e.getSystemId() == name |
|
521 |
|
522 def test_expat_incomplete(): |
|
523 parser = create_parser() |
|
524 parser.setContentHandler(ContentHandler()) # do nothing |
|
525 try: |
|
526 parser.parse(StringIO("<foo>")) |
|
527 except SAXParseException: |
|
528 return 1 # ok, error found |
|
529 else: |
|
530 return 0 |
|
531 |
|
532 def test_sax_parse_exception_str(): |
|
533 # pass various values from a locator to the SAXParseException to |
|
534 # make sure that the __str__() doesn't fall apart when None is |
|
535 # passed instead of an integer line and column number |
|
536 # |
|
537 # use "normal" values for the locator: |
|
538 str(SAXParseException("message", None, |
|
539 DummyLocator(1, 1))) |
|
540 # use None for the line number: |
|
541 str(SAXParseException("message", None, |
|
542 DummyLocator(None, 1))) |
|
543 # use None for the column number: |
|
544 str(SAXParseException("message", None, |
|
545 DummyLocator(1, None))) |
|
546 # use None for both: |
|
547 str(SAXParseException("message", None, |
|
548 DummyLocator(None, None))) |
|
549 return 1 |
|
550 |
|
551 class DummyLocator: |
|
552 def __init__(self, lineno, colno): |
|
553 self._lineno = lineno |
|
554 self._colno = colno |
|
555 |
|
556 def getPublicId(self): |
|
557 return "pubid" |
|
558 |
|
559 def getSystemId(self): |
|
560 return "sysid" |
|
561 |
|
562 def getLineNumber(self): |
|
563 return self._lineno |
|
564 |
|
565 def getColumnNumber(self): |
|
566 return self._colno |
|
567 |
|
568 # =========================================================================== |
|
569 # |
|
570 # xmlreader tests |
|
571 # |
|
572 # =========================================================================== |
|
573 |
|
574 # ===== AttributesImpl |
|
575 |
|
576 def verify_empty_attrs(attrs): |
|
577 try: |
|
578 attrs.getValue("attr") |
|
579 gvk = 0 |
|
580 except KeyError: |
|
581 gvk = 1 |
|
582 |
|
583 try: |
|
584 attrs.getValueByQName("attr") |
|
585 gvqk = 0 |
|
586 except KeyError: |
|
587 gvqk = 1 |
|
588 |
|
589 try: |
|
590 attrs.getNameByQName("attr") |
|
591 gnqk = 0 |
|
592 except KeyError: |
|
593 gnqk = 1 |
|
594 |
|
595 try: |
|
596 attrs.getQNameByName("attr") |
|
597 gqnk = 0 |
|
598 except KeyError: |
|
599 gqnk = 1 |
|
600 |
|
601 try: |
|
602 attrs["attr"] |
|
603 gik = 0 |
|
604 except KeyError: |
|
605 gik = 1 |
|
606 |
|
607 return attrs.getLength() == 0 and \ |
|
608 attrs.getNames() == [] and \ |
|
609 attrs.getQNames() == [] and \ |
|
610 len(attrs) == 0 and \ |
|
611 not attrs.has_key("attr") and \ |
|
612 attrs.keys() == [] and \ |
|
613 attrs.get("attrs") is None and \ |
|
614 attrs.get("attrs", 25) == 25 and \ |
|
615 attrs.items() == [] and \ |
|
616 attrs.values() == [] and \ |
|
617 gvk and gvqk and gnqk and gik and gqnk |
|
618 |
|
619 def verify_attrs_wattr(attrs): |
|
620 return attrs.getLength() == 1 and \ |
|
621 attrs.getNames() == ["attr"] and \ |
|
622 attrs.getQNames() == ["attr"] and \ |
|
623 len(attrs) == 1 and \ |
|
624 attrs.has_key("attr") and \ |
|
625 attrs.keys() == ["attr"] and \ |
|
626 attrs.get("attr") == "val" and \ |
|
627 attrs.get("attr", 25) == "val" and \ |
|
628 attrs.items() == [("attr", "val")] and \ |
|
629 attrs.values() == ["val"] and \ |
|
630 attrs.getValue("attr") == "val" and \ |
|
631 attrs.getValueByQName("attr") == "val" and \ |
|
632 attrs.getNameByQName("attr") == "attr" and \ |
|
633 attrs["attr"] == "val" and \ |
|
634 attrs.getQNameByName("attr") == "attr" |
|
635 |
|
636 def test_attrs_empty(): |
|
637 return verify_empty_attrs(AttributesImpl({})) |
|
638 |
|
639 def test_attrs_wattr(): |
|
640 return verify_attrs_wattr(AttributesImpl({"attr" : "val"})) |
|
641 |
|
642 # ===== AttributesImpl |
|
643 |
|
644 def verify_empty_nsattrs(attrs): |
|
645 try: |
|
646 attrs.getValue((ns_uri, "attr")) |
|
647 gvk = 0 |
|
648 except KeyError: |
|
649 gvk = 1 |
|
650 |
|
651 try: |
|
652 attrs.getValueByQName("ns:attr") |
|
653 gvqk = 0 |
|
654 except KeyError: |
|
655 gvqk = 1 |
|
656 |
|
657 try: |
|
658 attrs.getNameByQName("ns:attr") |
|
659 gnqk = 0 |
|
660 except KeyError: |
|
661 gnqk = 1 |
|
662 |
|
663 try: |
|
664 attrs.getQNameByName((ns_uri, "attr")) |
|
665 gqnk = 0 |
|
666 except KeyError: |
|
667 gqnk = 1 |
|
668 |
|
669 try: |
|
670 attrs[(ns_uri, "attr")] |
|
671 gik = 0 |
|
672 except KeyError: |
|
673 gik = 1 |
|
674 |
|
675 return attrs.getLength() == 0 and \ |
|
676 attrs.getNames() == [] and \ |
|
677 attrs.getQNames() == [] and \ |
|
678 len(attrs) == 0 and \ |
|
679 not attrs.has_key((ns_uri, "attr")) and \ |
|
680 attrs.keys() == [] and \ |
|
681 attrs.get((ns_uri, "attr")) is None and \ |
|
682 attrs.get((ns_uri, "attr"), 25) == 25 and \ |
|
683 attrs.items() == [] and \ |
|
684 attrs.values() == [] and \ |
|
685 gvk and gvqk and gnqk and gik and gqnk |
|
686 |
|
687 def test_nsattrs_empty(): |
|
688 return verify_empty_nsattrs(AttributesNSImpl({}, {})) |
|
689 |
|
690 def test_nsattrs_wattr(): |
|
691 attrs = AttributesNSImpl({(ns_uri, "attr") : "val"}, |
|
692 {(ns_uri, "attr") : "ns:attr"}) |
|
693 |
|
694 return attrs.getLength() == 1 and \ |
|
695 attrs.getNames() == [(ns_uri, "attr")] and \ |
|
696 attrs.getQNames() == ["ns:attr"] and \ |
|
697 len(attrs) == 1 and \ |
|
698 attrs.has_key((ns_uri, "attr")) and \ |
|
699 attrs.keys() == [(ns_uri, "attr")] and \ |
|
700 attrs.get((ns_uri, "attr")) == "val" and \ |
|
701 attrs.get((ns_uri, "attr"), 25) == "val" and \ |
|
702 attrs.items() == [((ns_uri, "attr"), "val")] and \ |
|
703 attrs.values() == ["val"] and \ |
|
704 attrs.getValue((ns_uri, "attr")) == "val" and \ |
|
705 attrs.getValueByQName("ns:attr") == "val" and \ |
|
706 attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \ |
|
707 attrs[(ns_uri, "attr")] == "val" and \ |
|
708 attrs.getQNameByName((ns_uri, "attr")) == "ns:attr" |
|
709 |
|
710 |
|
711 # During the development of Python 2.5, an attempt to move the "xml" |
|
712 # package implementation to a new package ("xmlcore") proved painful. |
|
713 # The goal of this change was to allow applications to be able to |
|
714 # obtain and rely on behavior in the standard library implementation |
|
715 # of the XML support without needing to be concerned about the |
|
716 # availability of the PyXML implementation. |
|
717 # |
|
718 # While the existing import hackery in Lib/xml/__init__.py can cause |
|
719 # PyXML's _xmlpus package to supplant the "xml" package, that only |
|
720 # works because either implementation uses the "xml" package name for |
|
721 # imports. |
|
722 # |
|
723 # The move resulted in a number of problems related to the fact that |
|
724 # the import machinery's "package context" is based on the name that's |
|
725 # being imported rather than the __name__ of the actual package |
|
726 # containment; it wasn't possible for the "xml" package to be replaced |
|
727 # by a simple module that indirected imports to the "xmlcore" package. |
|
728 # |
|
729 # The following two tests exercised bugs that were introduced in that |
|
730 # attempt. Keeping these tests around will help detect problems with |
|
731 # other attempts to provide reliable access to the standard library's |
|
732 # implementation of the XML support. |
|
733 |
|
734 def test_sf_1511497(): |
|
735 # Bug report: http://www.python.org/sf/1511497 |
|
736 import sys |
|
737 old_modules = sys.modules.copy() |
|
738 for modname in sys.modules.keys(): |
|
739 if modname.startswith("xml."): |
|
740 del sys.modules[modname] |
|
741 try: |
|
742 import xml.sax.expatreader |
|
743 module = xml.sax.expatreader |
|
744 return module.__name__ == "xml.sax.expatreader" |
|
745 finally: |
|
746 sys.modules.update(old_modules) |
|
747 |
|
748 def test_sf_1513611(): |
|
749 # Bug report: http://www.python.org/sf/1513611 |
|
750 sio = StringIO("invalid") |
|
751 parser = make_parser() |
|
752 from xml.sax import SAXParseException |
|
753 try: |
|
754 parser.parse(sio) |
|
755 except SAXParseException: |
|
756 return True |
|
757 else: |
|
758 return False |
|
759 |
|
760 # ===== Main program |
|
761 |
|
762 def make_test_output(): |
|
763 parser = create_parser() |
|
764 result = StringIO() |
|
765 xmlgen = XMLGenerator(result) |
|
766 |
|
767 parser.setContentHandler(xmlgen) |
|
768 parser.parse(findfile("test"+os.extsep+"xml")) |
|
769 |
|
770 outf = open(findfile("test"+os.extsep+"xml"+os.extsep+"out"), "w") |
|
771 outf.write(result.getvalue()) |
|
772 outf.close() |
|
773 |
|
774 items = locals().items() |
|
775 items.sort() |
|
776 for (name, value) in items: |
|
777 if name[ : 5] == "test_": |
|
778 confirm(value(), name) |
|
779 # We delete the items variable so that the assignment to items above |
|
780 # doesn't pick up the old value of items (which messes with attempts |
|
781 # to find reference leaks). |
|
782 del items |
|
783 |
|
784 if verbose: |
|
785 print "%d tests, %d failures" % (tests, len(failures)) |
|
786 if failures: |
|
787 raise TestFailed("%d of %d tests failed: %s" |
|
788 % (len(failures), tests, ", ".join(failures))) |