| 1 | # regression test for SAX 2.0 -*- coding: iso-8859-1 -*-
|
|---|
| 2 | # $Id: test_sax.py 50941 2006-07-29 16:56:15Z fred.drake $
|
|---|
| 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 | # ===== XMLFilterBase
|
|---|
| 220 |
|
|---|
| 221 | def test_filter_basic():
|
|---|
| 222 | result = StringIO()
|
|---|
| 223 | gen = XMLGenerator(result)
|
|---|
| 224 | filter = XMLFilterBase()
|
|---|
| 225 | filter.setContentHandler(gen)
|
|---|
| 226 |
|
|---|
| 227 | filter.startDocument()
|
|---|
| 228 | filter.startElement("doc", {})
|
|---|
| 229 | filter.characters("content")
|
|---|
| 230 | filter.ignorableWhitespace(" ")
|
|---|
| 231 | filter.endElement("doc")
|
|---|
| 232 | filter.endDocument()
|
|---|
| 233 |
|
|---|
| 234 | return result.getvalue() == start + "<doc>content </doc>"
|
|---|
| 235 |
|
|---|
| 236 | # ===========================================================================
|
|---|
| 237 | #
|
|---|
| 238 | # expatreader tests
|
|---|
| 239 | #
|
|---|
| 240 | # ===========================================================================
|
|---|
| 241 |
|
|---|
| 242 | # ===== XMLReader support
|
|---|
| 243 |
|
|---|
| 244 | def test_expat_file():
|
|---|
| 245 | parser = create_parser()
|
|---|
| 246 | result = StringIO()
|
|---|
| 247 | xmlgen = XMLGenerator(result)
|
|---|
| 248 |
|
|---|
| 249 | parser.setContentHandler(xmlgen)
|
|---|
| 250 | parser.parse(open(findfile("test"+os.extsep+"xml")))
|
|---|
| 251 |
|
|---|
| 252 | return result.getvalue() == xml_test_out
|
|---|
| 253 |
|
|---|
| 254 | # ===== DTDHandler support
|
|---|
| 255 |
|
|---|
| 256 | class TestDTDHandler:
|
|---|
| 257 |
|
|---|
| 258 | def __init__(self):
|
|---|
| 259 | self._notations = []
|
|---|
| 260 | self._entities = []
|
|---|
| 261 |
|
|---|
| 262 | def notationDecl(self, name, publicId, systemId):
|
|---|
| 263 | self._notations.append((name, publicId, systemId))
|
|---|
| 264 |
|
|---|
| 265 | def unparsedEntityDecl(self, name, publicId, systemId, ndata):
|
|---|
| 266 | self._entities.append((name, publicId, systemId, ndata))
|
|---|
| 267 |
|
|---|
| 268 | def test_expat_dtdhandler():
|
|---|
| 269 | parser = create_parser()
|
|---|
| 270 | handler = TestDTDHandler()
|
|---|
| 271 | parser.setDTDHandler(handler)
|
|---|
| 272 |
|
|---|
| 273 | parser.feed('<!DOCTYPE doc [\n')
|
|---|
| 274 | parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
|
|---|
| 275 | parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
|
|---|
| 276 | parser.feed(']>\n')
|
|---|
| 277 | parser.feed('<doc></doc>')
|
|---|
| 278 | parser.close()
|
|---|
| 279 |
|
|---|
| 280 | return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
|
|---|
| 281 | handler._entities == [("img", None, "expat.gif", "GIF")]
|
|---|
| 282 |
|
|---|
| 283 | # ===== EntityResolver support
|
|---|
| 284 |
|
|---|
| 285 | class TestEntityResolver:
|
|---|
| 286 |
|
|---|
| 287 | def resolveEntity(self, publicId, systemId):
|
|---|
| 288 | inpsrc = InputSource()
|
|---|
| 289 | inpsrc.setByteStream(StringIO("<entity/>"))
|
|---|
| 290 | return inpsrc
|
|---|
| 291 |
|
|---|
| 292 | def test_expat_entityresolver():
|
|---|
| 293 | parser = create_parser()
|
|---|
| 294 | parser.setEntityResolver(TestEntityResolver())
|
|---|
| 295 | result = StringIO()
|
|---|
| 296 | parser.setContentHandler(XMLGenerator(result))
|
|---|
| 297 |
|
|---|
| 298 | parser.feed('<!DOCTYPE doc [\n')
|
|---|
| 299 | parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
|
|---|
| 300 | parser.feed(']>\n')
|
|---|
| 301 | parser.feed('<doc>&test;</doc>')
|
|---|
| 302 | parser.close()
|
|---|
| 303 |
|
|---|
| 304 | return result.getvalue() == start + "<doc><entity></entity></doc>"
|
|---|
| 305 |
|
|---|
| 306 | # ===== Attributes support
|
|---|
| 307 |
|
|---|
| 308 | class AttrGatherer(ContentHandler):
|
|---|
| 309 |
|
|---|
| 310 | def startElement(self, name, attrs):
|
|---|
| 311 | self._attrs = attrs
|
|---|
| 312 |
|
|---|
| 313 | def startElementNS(self, name, qname, attrs):
|
|---|
| 314 | self._attrs = attrs
|
|---|
| 315 |
|
|---|
| 316 | def test_expat_attrs_empty():
|
|---|
| 317 | parser = create_parser()
|
|---|
| 318 | gather = AttrGatherer()
|
|---|
| 319 | parser.setContentHandler(gather)
|
|---|
| 320 |
|
|---|
| 321 | parser.feed("<doc/>")
|
|---|
| 322 | parser.close()
|
|---|
| 323 |
|
|---|
| 324 | return verify_empty_attrs(gather._attrs)
|
|---|
| 325 |
|
|---|
| 326 | def test_expat_attrs_wattr():
|
|---|
| 327 | parser = create_parser()
|
|---|
| 328 | gather = AttrGatherer()
|
|---|
| 329 | parser.setContentHandler(gather)
|
|---|
| 330 |
|
|---|
| 331 | parser.feed("<doc attr='val'/>")
|
|---|
| 332 | parser.close()
|
|---|
| 333 |
|
|---|
| 334 | return verify_attrs_wattr(gather._attrs)
|
|---|
| 335 |
|
|---|
| 336 | def test_expat_nsattrs_empty():
|
|---|
| 337 | parser = create_parser(1)
|
|---|
| 338 | gather = AttrGatherer()
|
|---|
| 339 | parser.setContentHandler(gather)
|
|---|
| 340 |
|
|---|
| 341 | parser.feed("<doc/>")
|
|---|
| 342 | parser.close()
|
|---|
| 343 |
|
|---|
| 344 | return verify_empty_nsattrs(gather._attrs)
|
|---|
| 345 |
|
|---|
| 346 | def test_expat_nsattrs_wattr():
|
|---|
| 347 | parser = create_parser(1)
|
|---|
| 348 | gather = AttrGatherer()
|
|---|
| 349 | parser.setContentHandler(gather)
|
|---|
| 350 |
|
|---|
| 351 | parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
|
|---|
| 352 | parser.close()
|
|---|
| 353 |
|
|---|
| 354 | attrs = gather._attrs
|
|---|
| 355 |
|
|---|
| 356 | return attrs.getLength() == 1 and \
|
|---|
| 357 | attrs.getNames() == [(ns_uri, "attr")] and \
|
|---|
| 358 | (attrs.getQNames() == [] or attrs.getQNames() == ["ns:attr"]) and \
|
|---|
| 359 | len(attrs) == 1 and \
|
|---|
| 360 | attrs.has_key((ns_uri, "attr")) and \
|
|---|
| 361 | attrs.keys() == [(ns_uri, "attr")] and \
|
|---|
| 362 | attrs.get((ns_uri, "attr")) == "val" and \
|
|---|
| 363 | attrs.get((ns_uri, "attr"), 25) == "val" and \
|
|---|
| 364 | attrs.items() == [((ns_uri, "attr"), "val")] and \
|
|---|
| 365 | attrs.values() == ["val"] and \
|
|---|
| 366 | attrs.getValue((ns_uri, "attr")) == "val" and \
|
|---|
| 367 | attrs[(ns_uri, "attr")] == "val"
|
|---|
| 368 |
|
|---|
| 369 | # ===== InputSource support
|
|---|
| 370 |
|
|---|
| 371 | xml_test_out = open(findfile("test"+os.extsep+"xml"+os.extsep+"out")).read()
|
|---|
| 372 |
|
|---|
| 373 | def test_expat_inpsource_filename():
|
|---|
| 374 | parser = create_parser()
|
|---|
| 375 | result = StringIO()
|
|---|
| 376 | xmlgen = XMLGenerator(result)
|
|---|
| 377 |
|
|---|
| 378 | parser.setContentHandler(xmlgen)
|
|---|
| 379 | parser.parse(findfile("test"+os.extsep+"xml"))
|
|---|
| 380 |
|
|---|
| 381 | return result.getvalue() == xml_test_out
|
|---|
| 382 |
|
|---|
| 383 | def test_expat_inpsource_sysid():
|
|---|
| 384 | parser = create_parser()
|
|---|
| 385 | result = StringIO()
|
|---|
| 386 | xmlgen = XMLGenerator(result)
|
|---|
| 387 |
|
|---|
| 388 | parser.setContentHandler(xmlgen)
|
|---|
| 389 | parser.parse(InputSource(findfile("test"+os.extsep+"xml")))
|
|---|
| 390 |
|
|---|
| 391 | return result.getvalue() == xml_test_out
|
|---|
| 392 |
|
|---|
| 393 | def test_expat_inpsource_stream():
|
|---|
| 394 | parser = create_parser()
|
|---|
| 395 | result = StringIO()
|
|---|
| 396 | xmlgen = XMLGenerator(result)
|
|---|
| 397 |
|
|---|
| 398 | parser.setContentHandler(xmlgen)
|
|---|
| 399 | inpsrc = InputSource()
|
|---|
| 400 | inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml")))
|
|---|
| 401 | parser.parse(inpsrc)
|
|---|
| 402 |
|
|---|
| 403 | return result.getvalue() == xml_test_out
|
|---|
| 404 |
|
|---|
| 405 | # ===== IncrementalParser support
|
|---|
| 406 |
|
|---|
| 407 | def test_expat_incremental():
|
|---|
| 408 | result = StringIO()
|
|---|
| 409 | xmlgen = XMLGenerator(result)
|
|---|
| 410 | parser = create_parser()
|
|---|
| 411 | parser.setContentHandler(xmlgen)
|
|---|
| 412 |
|
|---|
| 413 | parser.feed("<doc>")
|
|---|
| 414 | parser.feed("</doc>")
|
|---|
| 415 | parser.close()
|
|---|
| 416 |
|
|---|
| 417 | return result.getvalue() == start + "<doc></doc>"
|
|---|
| 418 |
|
|---|
| 419 | def test_expat_incremental_reset():
|
|---|
| 420 | result = StringIO()
|
|---|
| 421 | xmlgen = XMLGenerator(result)
|
|---|
| 422 | parser = create_parser()
|
|---|
| 423 | parser.setContentHandler(xmlgen)
|
|---|
| 424 |
|
|---|
| 425 | parser.feed("<doc>")
|
|---|
| 426 | parser.feed("text")
|
|---|
| 427 |
|
|---|
| 428 | result = StringIO()
|
|---|
| 429 | xmlgen = XMLGenerator(result)
|
|---|
| 430 | parser.setContentHandler(xmlgen)
|
|---|
| 431 | parser.reset()
|
|---|
| 432 |
|
|---|
| 433 | parser.feed("<doc>")
|
|---|
| 434 | parser.feed("text")
|
|---|
| 435 | parser.feed("</doc>")
|
|---|
| 436 | parser.close()
|
|---|
| 437 |
|
|---|
| 438 | return result.getvalue() == start + "<doc>text</doc>"
|
|---|
| 439 |
|
|---|
| 440 | # ===== Locator support
|
|---|
| 441 |
|
|---|
| 442 | def test_expat_locator_noinfo():
|
|---|
| 443 | result = StringIO()
|
|---|
| 444 | xmlgen = XMLGenerator(result)
|
|---|
| 445 | parser = create_parser()
|
|---|
| 446 | parser.setContentHandler(xmlgen)
|
|---|
| 447 |
|
|---|
| 448 | parser.feed("<doc>")
|
|---|
| 449 | parser.feed("</doc>")
|
|---|
| 450 | parser.close()
|
|---|
| 451 |
|
|---|
| 452 | return parser.getSystemId() is None and \
|
|---|
| 453 | parser.getPublicId() is None and \
|
|---|
| 454 | parser.getLineNumber() == 1
|
|---|
| 455 |
|
|---|
| 456 | def test_expat_locator_withinfo():
|
|---|
| 457 | result = StringIO()
|
|---|
| 458 | xmlgen = XMLGenerator(result)
|
|---|
| 459 | parser = create_parser()
|
|---|
| 460 | parser.setContentHandler(xmlgen)
|
|---|
| 461 | parser.parse(findfile("test.xml"))
|
|---|
| 462 |
|
|---|
| 463 | return parser.getSystemId() == findfile("test.xml") and \
|
|---|
| 464 | parser.getPublicId() is None
|
|---|
| 465 |
|
|---|
| 466 |
|
|---|
| 467 | # ===========================================================================
|
|---|
| 468 | #
|
|---|
| 469 | # error reporting
|
|---|
| 470 | #
|
|---|
| 471 | # ===========================================================================
|
|---|
| 472 |
|
|---|
| 473 | def test_expat_inpsource_location():
|
|---|
| 474 | parser = create_parser()
|
|---|
| 475 | parser.setContentHandler(ContentHandler()) # do nothing
|
|---|
| 476 | source = InputSource()
|
|---|
| 477 | source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
|
|---|
| 478 | name = "a file name"
|
|---|
| 479 | source.setSystemId(name)
|
|---|
| 480 | try:
|
|---|
| 481 | parser.parse(source)
|
|---|
| 482 | except SAXException, e:
|
|---|
| 483 | return e.getSystemId() == name
|
|---|
| 484 |
|
|---|
| 485 | def test_expat_incomplete():
|
|---|
| 486 | parser = create_parser()
|
|---|
| 487 | parser.setContentHandler(ContentHandler()) # do nothing
|
|---|
| 488 | try:
|
|---|
| 489 | parser.parse(StringIO("<foo>"))
|
|---|
| 490 | except SAXParseException:
|
|---|
| 491 | return 1 # ok, error found
|
|---|
| 492 | else:
|
|---|
| 493 | return 0
|
|---|
| 494 |
|
|---|
| 495 | def test_sax_parse_exception_str():
|
|---|
| 496 | # pass various values from a locator to the SAXParseException to
|
|---|
| 497 | # make sure that the __str__() doesn't fall apart when None is
|
|---|
| 498 | # passed instead of an integer line and column number
|
|---|
| 499 | #
|
|---|
| 500 | # use "normal" values for the locator:
|
|---|
| 501 | str(SAXParseException("message", None,
|
|---|
| 502 | DummyLocator(1, 1)))
|
|---|
| 503 | # use None for the line number:
|
|---|
| 504 | str(SAXParseException("message", None,
|
|---|
| 505 | DummyLocator(None, 1)))
|
|---|
| 506 | # use None for the column number:
|
|---|
| 507 | str(SAXParseException("message", None,
|
|---|
| 508 | DummyLocator(1, None)))
|
|---|
| 509 | # use None for both:
|
|---|
| 510 | str(SAXParseException("message", None,
|
|---|
| 511 | DummyLocator(None, None)))
|
|---|
| 512 | return 1
|
|---|
| 513 |
|
|---|
| 514 | class DummyLocator:
|
|---|
| 515 | def __init__(self, lineno, colno):
|
|---|
| 516 | self._lineno = lineno
|
|---|
| 517 | self._colno = colno
|
|---|
| 518 |
|
|---|
| 519 | def getPublicId(self):
|
|---|
| 520 | return "pubid"
|
|---|
| 521 |
|
|---|
| 522 | def getSystemId(self):
|
|---|
| 523 | return "sysid"
|
|---|
| 524 |
|
|---|
| 525 | def getLineNumber(self):
|
|---|
| 526 | return self._lineno
|
|---|
| 527 |
|
|---|
| 528 | def getColumnNumber(self):
|
|---|
| 529 | return self._colno
|
|---|
| 530 |
|
|---|
| 531 | # ===========================================================================
|
|---|
| 532 | #
|
|---|
| 533 | # xmlreader tests
|
|---|
| 534 | #
|
|---|
| 535 | # ===========================================================================
|
|---|
| 536 |
|
|---|
| 537 | # ===== AttributesImpl
|
|---|
| 538 |
|
|---|
| 539 | def verify_empty_attrs(attrs):
|
|---|
| 540 | try:
|
|---|
| 541 | attrs.getValue("attr")
|
|---|
| 542 | gvk = 0
|
|---|
| 543 | except KeyError:
|
|---|
| 544 | gvk = 1
|
|---|
| 545 |
|
|---|
| 546 | try:
|
|---|
| 547 | attrs.getValueByQName("attr")
|
|---|
| 548 | gvqk = 0
|
|---|
| 549 | except KeyError:
|
|---|
| 550 | gvqk = 1
|
|---|
| 551 |
|
|---|
| 552 | try:
|
|---|
| 553 | attrs.getNameByQName("attr")
|
|---|
| 554 | gnqk = 0
|
|---|
| 555 | except KeyError:
|
|---|
| 556 | gnqk = 1
|
|---|
| 557 |
|
|---|
| 558 | try:
|
|---|
| 559 | attrs.getQNameByName("attr")
|
|---|
| 560 | gqnk = 0
|
|---|
| 561 | except KeyError:
|
|---|
| 562 | gqnk = 1
|
|---|
| 563 |
|
|---|
| 564 | try:
|
|---|
| 565 | attrs["attr"]
|
|---|
| 566 | gik = 0
|
|---|
| 567 | except KeyError:
|
|---|
| 568 | gik = 1
|
|---|
| 569 |
|
|---|
| 570 | return attrs.getLength() == 0 and \
|
|---|
| 571 | attrs.getNames() == [] and \
|
|---|
| 572 | attrs.getQNames() == [] and \
|
|---|
| 573 | len(attrs) == 0 and \
|
|---|
| 574 | not attrs.has_key("attr") and \
|
|---|
| 575 | attrs.keys() == [] and \
|
|---|
| 576 | attrs.get("attrs") is None and \
|
|---|
| 577 | attrs.get("attrs", 25) == 25 and \
|
|---|
| 578 | attrs.items() == [] and \
|
|---|
| 579 | attrs.values() == [] and \
|
|---|
| 580 | gvk and gvqk and gnqk and gik and gqnk
|
|---|
| 581 |
|
|---|
| 582 | def verify_attrs_wattr(attrs):
|
|---|
| 583 | return attrs.getLength() == 1 and \
|
|---|
| 584 | attrs.getNames() == ["attr"] and \
|
|---|
| 585 | attrs.getQNames() == ["attr"] and \
|
|---|
| 586 | len(attrs) == 1 and \
|
|---|
| 587 | attrs.has_key("attr") and \
|
|---|
| 588 | attrs.keys() == ["attr"] and \
|
|---|
| 589 | attrs.get("attr") == "val" and \
|
|---|
| 590 | attrs.get("attr", 25) == "val" and \
|
|---|
| 591 | attrs.items() == [("attr", "val")] and \
|
|---|
| 592 | attrs.values() == ["val"] and \
|
|---|
| 593 | attrs.getValue("attr") == "val" and \
|
|---|
| 594 | attrs.getValueByQName("attr") == "val" and \
|
|---|
| 595 | attrs.getNameByQName("attr") == "attr" and \
|
|---|
| 596 | attrs["attr"] == "val" and \
|
|---|
| 597 | attrs.getQNameByName("attr") == "attr"
|
|---|
| 598 |
|
|---|
| 599 | def test_attrs_empty():
|
|---|
| 600 | return verify_empty_attrs(AttributesImpl({}))
|
|---|
| 601 |
|
|---|
| 602 | def test_attrs_wattr():
|
|---|
| 603 | return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
|
|---|
| 604 |
|
|---|
| 605 | # ===== AttributesImpl
|
|---|
| 606 |
|
|---|
| 607 | def verify_empty_nsattrs(attrs):
|
|---|
| 608 | try:
|
|---|
| 609 | attrs.getValue((ns_uri, "attr"))
|
|---|
| 610 | gvk = 0
|
|---|
| 611 | except KeyError:
|
|---|
| 612 | gvk = 1
|
|---|
| 613 |
|
|---|
| 614 | try:
|
|---|
| 615 | attrs.getValueByQName("ns:attr")
|
|---|
| 616 | gvqk = 0
|
|---|
| 617 | except KeyError:
|
|---|
| 618 | gvqk = 1
|
|---|
| 619 |
|
|---|
| 620 | try:
|
|---|
| 621 | attrs.getNameByQName("ns:attr")
|
|---|
| 622 | gnqk = 0
|
|---|
| 623 | except KeyError:
|
|---|
| 624 | gnqk = 1
|
|---|
| 625 |
|
|---|
| 626 | try:
|
|---|
| 627 | attrs.getQNameByName((ns_uri, "attr"))
|
|---|
| 628 | gqnk = 0
|
|---|
| 629 | except KeyError:
|
|---|
| 630 | gqnk = 1
|
|---|
| 631 |
|
|---|
| 632 | try:
|
|---|
| 633 | attrs[(ns_uri, "attr")]
|
|---|
| 634 | gik = 0
|
|---|
| 635 | except KeyError:
|
|---|
| 636 | gik = 1
|
|---|
| 637 |
|
|---|
| 638 | return attrs.getLength() == 0 and \
|
|---|
| 639 | attrs.getNames() == [] and \
|
|---|
| 640 | attrs.getQNames() == [] and \
|
|---|
| 641 | len(attrs) == 0 and \
|
|---|
| 642 | not attrs.has_key((ns_uri, "attr")) and \
|
|---|
| 643 | attrs.keys() == [] and \
|
|---|
| 644 | attrs.get((ns_uri, "attr")) is None and \
|
|---|
| 645 | attrs.get((ns_uri, "attr"), 25) == 25 and \
|
|---|
| 646 | attrs.items() == [] and \
|
|---|
| 647 | attrs.values() == [] and \
|
|---|
| 648 | gvk and gvqk and gnqk and gik and gqnk
|
|---|
| 649 |
|
|---|
| 650 | def test_nsattrs_empty():
|
|---|
| 651 | return verify_empty_nsattrs(AttributesNSImpl({}, {}))
|
|---|
| 652 |
|
|---|
| 653 | def test_nsattrs_wattr():
|
|---|
| 654 | attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
|
|---|
| 655 | {(ns_uri, "attr") : "ns:attr"})
|
|---|
| 656 |
|
|---|
| 657 | return attrs.getLength() == 1 and \
|
|---|
| 658 | attrs.getNames() == [(ns_uri, "attr")] and \
|
|---|
| 659 | attrs.getQNames() == ["ns:attr"] and \
|
|---|
| 660 | len(attrs) == 1 and \
|
|---|
| 661 | attrs.has_key((ns_uri, "attr")) and \
|
|---|
| 662 | attrs.keys() == [(ns_uri, "attr")] and \
|
|---|
| 663 | attrs.get((ns_uri, "attr")) == "val" and \
|
|---|
| 664 | attrs.get((ns_uri, "attr"), 25) == "val" and \
|
|---|
| 665 | attrs.items() == [((ns_uri, "attr"), "val")] and \
|
|---|
| 666 | attrs.values() == ["val"] and \
|
|---|
| 667 | attrs.getValue((ns_uri, "attr")) == "val" and \
|
|---|
| 668 | attrs.getValueByQName("ns:attr") == "val" and \
|
|---|
| 669 | attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
|
|---|
| 670 | attrs[(ns_uri, "attr")] == "val" and \
|
|---|
| 671 | attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
|
|---|
| 672 |
|
|---|
| 673 |
|
|---|
| 674 | # During the development of Python 2.5, an attempt to move the "xml"
|
|---|
| 675 | # package implementation to a new package ("xmlcore") proved painful.
|
|---|
| 676 | # The goal of this change was to allow applications to be able to
|
|---|
| 677 | # obtain and rely on behavior in the standard library implementation
|
|---|
| 678 | # of the XML support without needing to be concerned about the
|
|---|
| 679 | # availability of the PyXML implementation.
|
|---|
| 680 | #
|
|---|
| 681 | # While the existing import hackery in Lib/xml/__init__.py can cause
|
|---|
| 682 | # PyXML's _xmlpus package to supplant the "xml" package, that only
|
|---|
| 683 | # works because either implementation uses the "xml" package name for
|
|---|
| 684 | # imports.
|
|---|
| 685 | #
|
|---|
| 686 | # The move resulted in a number of problems related to the fact that
|
|---|
| 687 | # the import machinery's "package context" is based on the name that's
|
|---|
| 688 | # being imported rather than the __name__ of the actual package
|
|---|
| 689 | # containment; it wasn't possible for the "xml" package to be replaced
|
|---|
| 690 | # by a simple module that indirected imports to the "xmlcore" package.
|
|---|
| 691 | #
|
|---|
| 692 | # The following two tests exercised bugs that were introduced in that
|
|---|
| 693 | # attempt. Keeping these tests around will help detect problems with
|
|---|
| 694 | # other attempts to provide reliable access to the standard library's
|
|---|
| 695 | # implementation of the XML support.
|
|---|
| 696 |
|
|---|
| 697 | def test_sf_1511497():
|
|---|
| 698 | # Bug report: http://www.python.org/sf/1511497
|
|---|
| 699 | import sys
|
|---|
| 700 | old_modules = sys.modules.copy()
|
|---|
| 701 | for modname in sys.modules.keys():
|
|---|
| 702 | if modname.startswith("xml."):
|
|---|
| 703 | del sys.modules[modname]
|
|---|
| 704 | try:
|
|---|
| 705 | import xml.sax.expatreader
|
|---|
| 706 | module = xml.sax.expatreader
|
|---|
| 707 | return module.__name__ == "xml.sax.expatreader"
|
|---|
| 708 | finally:
|
|---|
| 709 | sys.modules.update(old_modules)
|
|---|
| 710 |
|
|---|
| 711 | def test_sf_1513611():
|
|---|
| 712 | # Bug report: http://www.python.org/sf/1513611
|
|---|
| 713 | sio = StringIO("invalid")
|
|---|
| 714 | parser = make_parser()
|
|---|
| 715 | from xml.sax import SAXParseException
|
|---|
| 716 | try:
|
|---|
| 717 | parser.parse(sio)
|
|---|
| 718 | except SAXParseException:
|
|---|
| 719 | return True
|
|---|
| 720 | else:
|
|---|
| 721 | return False
|
|---|
| 722 |
|
|---|
| 723 | # ===== Main program
|
|---|
| 724 |
|
|---|
| 725 | def make_test_output():
|
|---|
| 726 | parser = create_parser()
|
|---|
| 727 | result = StringIO()
|
|---|
| 728 | xmlgen = XMLGenerator(result)
|
|---|
| 729 |
|
|---|
| 730 | parser.setContentHandler(xmlgen)
|
|---|
| 731 | parser.parse(findfile("test"+os.extsep+"xml"))
|
|---|
| 732 |
|
|---|
| 733 | outf = open(findfile("test"+os.extsep+"xml"+os.extsep+"out"), "w")
|
|---|
| 734 | outf.write(result.getvalue())
|
|---|
| 735 | outf.close()
|
|---|
| 736 |
|
|---|
| 737 | items = locals().items()
|
|---|
| 738 | items.sort()
|
|---|
| 739 | for (name, value) in items:
|
|---|
| 740 | if name[ : 5] == "test_":
|
|---|
| 741 | confirm(value(), name)
|
|---|
| 742 | # We delete the items variable so that the assignment to items above
|
|---|
| 743 | # doesn't pick up the old value of items (which messes with attempts
|
|---|
| 744 | # to find reference leaks).
|
|---|
| 745 | del items
|
|---|
| 746 |
|
|---|
| 747 | if verbose:
|
|---|
| 748 | print "%d tests, %d failures" % (tests, len(failures))
|
|---|
| 749 | if failures:
|
|---|
| 750 | raise TestFailed("%d of %d tests failed: %s"
|
|---|
| 751 | % (len(failures), tests, ", ".join(failures)))
|
|---|