python-2.5.2/win32/Lib/test/test_sax.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     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>") == "&lt;Donald Duck &amp; Co&gt;"
       
    70 
       
    71 def test_escape_extra():
       
    72     return escape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
       
    73 
       
    74 # ===== unescape
       
    75 
       
    76 def test_unescape_basic():
       
    77     return unescape("Donald Duck &amp; Co") == "Donald Duck & Co"
       
    78 
       
    79 def test_unescape_all():
       
    80     return unescape("&lt;Donald Duck &amp; Co&gt;") == "<Donald Duck & Co>"
       
    81 
       
    82 def test_unescape_extra():
       
    83     return unescape("Hei på deg", {"å" : "&aring;"}) == "Hei p&aring; deg"
       
    84 
       
    85 def test_unescape_amp_extra():
       
    86     return unescape("&amp;foo;", {"&foo;": "splat"}) == "&foo;"
       
    87 
       
    88 # ===== quoteattr
       
    89 
       
    90 def test_quoteattr_basic():
       
    91     return quoteattr("Donald Duck & Co") == '"Donald Duck &amp; 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 &quot;double&quot; 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>&lt;huhei&amp;</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=\"'&quot;\"></e>"
       
   185                                          "<e a=\"&#10;&#13;&#9;\"></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)))