mirror of
https://github.com/python/cpython.git
synced 2024-11-28 20:33:54 +08:00
32f3add267
Remove extra noise from the output when there are no errors, and say more in the exception when there are errors.
661 lines
18 KiB
Python
661 lines
18 KiB
Python
# regression test for SAX 2.0 -*- coding: iso-8859-1 -*-
|
|
# $Id$
|
|
|
|
from xml.sax import make_parser, ContentHandler, \
|
|
SAXException, SAXReaderNotAvailable, SAXParseException
|
|
try:
|
|
make_parser()
|
|
except SAXReaderNotAvailable:
|
|
# don't try to test this module if we cannot create a parser
|
|
raise ImportError("no XML parsers available")
|
|
from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
|
|
XMLFilterBase
|
|
from xml.sax.expatreader import create_parser
|
|
from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
|
|
from cStringIO import StringIO
|
|
from test.test_support import verify, verbose, TestFailed, findfile
|
|
import os
|
|
|
|
# ===== Utilities
|
|
|
|
tests = 0
|
|
failures = []
|
|
|
|
def confirm(outcome, name):
|
|
global tests
|
|
|
|
tests = tests + 1
|
|
if outcome:
|
|
if verbose:
|
|
print "Failed", name
|
|
else:
|
|
failures.append(name)
|
|
|
|
def test_make_parser2():
|
|
try:
|
|
# Creating parsers several times in a row should succeed.
|
|
# Testing this because there have been failures of this kind
|
|
# before.
|
|
from xml.sax import make_parser
|
|
p = make_parser()
|
|
from xml.sax import make_parser
|
|
p = make_parser()
|
|
from xml.sax import make_parser
|
|
p = make_parser()
|
|
from xml.sax import make_parser
|
|
p = make_parser()
|
|
from xml.sax import make_parser
|
|
p = make_parser()
|
|
from xml.sax import make_parser
|
|
p = make_parser()
|
|
except:
|
|
return 0
|
|
else:
|
|
return p
|
|
|
|
|
|
# ===========================================================================
|
|
#
|
|
# saxutils tests
|
|
#
|
|
# ===========================================================================
|
|
|
|
# ===== escape
|
|
|
|
def test_escape_basic():
|
|
return escape("Donald Duck & Co") == "Donald Duck & Co"
|
|
|
|
def test_escape_all():
|
|
return escape("<Donald Duck & Co>") == "<Donald Duck & Co>"
|
|
|
|
def test_escape_extra():
|
|
return escape("Hei på deg", {"å" : "å"}) == "Hei på deg"
|
|
|
|
# ===== unescape
|
|
|
|
def test_unescape_basic():
|
|
return unescape("Donald Duck & Co") == "Donald Duck & Co"
|
|
|
|
def test_unescape_all():
|
|
return unescape("<Donald Duck & Co>") == "<Donald Duck & Co>"
|
|
|
|
def test_unescape_extra():
|
|
return unescape("Hei på deg", {"å" : "å"}) == "Hei på deg"
|
|
|
|
def test_unescape_amp_extra():
|
|
return unescape("&foo;", {"&foo;": "splat"}) == "&foo;"
|
|
|
|
# ===== quoteattr
|
|
|
|
def test_quoteattr_basic():
|
|
return quoteattr("Donald Duck & Co") == '"Donald Duck & Co"'
|
|
|
|
def test_single_quoteattr():
|
|
return (quoteattr('Includes "double" quotes')
|
|
== '\'Includes "double" quotes\'')
|
|
|
|
def test_double_quoteattr():
|
|
return (quoteattr("Includes 'single' quotes")
|
|
== "\"Includes 'single' quotes\"")
|
|
|
|
def test_single_double_quoteattr():
|
|
return (quoteattr("Includes 'single' and \"double\" quotes")
|
|
== "\"Includes 'single' and "double" quotes\"")
|
|
|
|
# ===== make_parser
|
|
|
|
def test_make_parser():
|
|
try:
|
|
# Creating a parser should succeed - it should fall back
|
|
# to the expatreader
|
|
p = make_parser(['xml.parsers.no_such_parser'])
|
|
except:
|
|
return 0
|
|
else:
|
|
return p
|
|
|
|
|
|
# ===== XMLGenerator
|
|
|
|
start = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
|
|
|
|
def test_xmlgen_basic():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
gen.startDocument()
|
|
gen.startElement("doc", {})
|
|
gen.endElement("doc")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start + "<doc></doc>"
|
|
|
|
def test_xmlgen_content():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
|
|
gen.startDocument()
|
|
gen.startElement("doc", {})
|
|
gen.characters("huhei")
|
|
gen.endElement("doc")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start + "<doc>huhei</doc>"
|
|
|
|
def test_xmlgen_pi():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
|
|
gen.startDocument()
|
|
gen.processingInstruction("test", "data")
|
|
gen.startElement("doc", {})
|
|
gen.endElement("doc")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start + "<?test data?><doc></doc>"
|
|
|
|
def test_xmlgen_content_escape():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
|
|
gen.startDocument()
|
|
gen.startElement("doc", {})
|
|
gen.characters("<huhei&")
|
|
gen.endElement("doc")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start + "<doc><huhei&</doc>"
|
|
|
|
def test_xmlgen_attr_escape():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
|
|
gen.startDocument()
|
|
gen.startElement("doc", {"a": '"'})
|
|
gen.startElement("e", {"a": "'"})
|
|
gen.endElement("e")
|
|
gen.startElement("e", {"a": "'\""})
|
|
gen.endElement("e")
|
|
gen.endElement("doc")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start \
|
|
+ "<doc a='\"'><e a=\"'\"></e><e a=\"'"\"></e></doc>"
|
|
|
|
def test_xmlgen_ignorable():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
|
|
gen.startDocument()
|
|
gen.startElement("doc", {})
|
|
gen.ignorableWhitespace(" ")
|
|
gen.endElement("doc")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start + "<doc> </doc>"
|
|
|
|
ns_uri = "http://www.python.org/xml-ns/saxtest/"
|
|
|
|
def test_xmlgen_ns():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
|
|
gen.startDocument()
|
|
gen.startPrefixMapping("ns1", ns_uri)
|
|
gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
|
|
# add an unqualified name
|
|
gen.startElementNS((None, "udoc"), None, {})
|
|
gen.endElementNS((None, "udoc"), None)
|
|
gen.endElementNS((ns_uri, "doc"), "ns1:doc")
|
|
gen.endPrefixMapping("ns1")
|
|
gen.endDocument()
|
|
|
|
return result.getvalue() == start + \
|
|
('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
|
|
ns_uri)
|
|
|
|
# ===== XMLFilterBase
|
|
|
|
def test_filter_basic():
|
|
result = StringIO()
|
|
gen = XMLGenerator(result)
|
|
filter = XMLFilterBase()
|
|
filter.setContentHandler(gen)
|
|
|
|
filter.startDocument()
|
|
filter.startElement("doc", {})
|
|
filter.characters("content")
|
|
filter.ignorableWhitespace(" ")
|
|
filter.endElement("doc")
|
|
filter.endDocument()
|
|
|
|
return result.getvalue() == start + "<doc>content </doc>"
|
|
|
|
# ===========================================================================
|
|
#
|
|
# expatreader tests
|
|
#
|
|
# ===========================================================================
|
|
|
|
# ===== XMLReader support
|
|
|
|
def test_expat_file():
|
|
parser = create_parser()
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
|
|
parser.setContentHandler(xmlgen)
|
|
parser.parse(open(findfile("test"+os.extsep+"xml")))
|
|
|
|
return result.getvalue() == xml_test_out
|
|
|
|
# ===== DTDHandler support
|
|
|
|
class TestDTDHandler:
|
|
|
|
def __init__(self):
|
|
self._notations = []
|
|
self._entities = []
|
|
|
|
def notationDecl(self, name, publicId, systemId):
|
|
self._notations.append((name, publicId, systemId))
|
|
|
|
def unparsedEntityDecl(self, name, publicId, systemId, ndata):
|
|
self._entities.append((name, publicId, systemId, ndata))
|
|
|
|
def test_expat_dtdhandler():
|
|
parser = create_parser()
|
|
handler = TestDTDHandler()
|
|
parser.setDTDHandler(handler)
|
|
|
|
parser.feed('<!DOCTYPE doc [\n')
|
|
parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
|
|
parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
|
|
parser.feed(']>\n')
|
|
parser.feed('<doc></doc>')
|
|
parser.close()
|
|
|
|
return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \
|
|
handler._entities == [("img", None, "expat.gif", "GIF")]
|
|
|
|
# ===== EntityResolver support
|
|
|
|
class TestEntityResolver:
|
|
|
|
def resolveEntity(self, publicId, systemId):
|
|
inpsrc = InputSource()
|
|
inpsrc.setByteStream(StringIO("<entity/>"))
|
|
return inpsrc
|
|
|
|
def test_expat_entityresolver():
|
|
parser = create_parser()
|
|
parser.setEntityResolver(TestEntityResolver())
|
|
result = StringIO()
|
|
parser.setContentHandler(XMLGenerator(result))
|
|
|
|
parser.feed('<!DOCTYPE doc [\n')
|
|
parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
|
|
parser.feed(']>\n')
|
|
parser.feed('<doc>&test;</doc>')
|
|
parser.close()
|
|
|
|
return result.getvalue() == start + "<doc><entity></entity></doc>"
|
|
|
|
# ===== Attributes support
|
|
|
|
class AttrGatherer(ContentHandler):
|
|
|
|
def startElement(self, name, attrs):
|
|
self._attrs = attrs
|
|
|
|
def startElementNS(self, name, qname, attrs):
|
|
self._attrs = attrs
|
|
|
|
def test_expat_attrs_empty():
|
|
parser = create_parser()
|
|
gather = AttrGatherer()
|
|
parser.setContentHandler(gather)
|
|
|
|
parser.feed("<doc/>")
|
|
parser.close()
|
|
|
|
return verify_empty_attrs(gather._attrs)
|
|
|
|
def test_expat_attrs_wattr():
|
|
parser = create_parser()
|
|
gather = AttrGatherer()
|
|
parser.setContentHandler(gather)
|
|
|
|
parser.feed("<doc attr='val'/>")
|
|
parser.close()
|
|
|
|
return verify_attrs_wattr(gather._attrs)
|
|
|
|
def test_expat_nsattrs_empty():
|
|
parser = create_parser(1)
|
|
gather = AttrGatherer()
|
|
parser.setContentHandler(gather)
|
|
|
|
parser.feed("<doc/>")
|
|
parser.close()
|
|
|
|
return verify_empty_nsattrs(gather._attrs)
|
|
|
|
def test_expat_nsattrs_wattr():
|
|
parser = create_parser(1)
|
|
gather = AttrGatherer()
|
|
parser.setContentHandler(gather)
|
|
|
|
parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
|
|
parser.close()
|
|
|
|
attrs = gather._attrs
|
|
|
|
return attrs.getLength() == 1 and \
|
|
attrs.getNames() == [(ns_uri, "attr")] and \
|
|
(attrs.getQNames() == [] or attrs.getQNames() == ["ns:attr"]) and \
|
|
len(attrs) == 1 and \
|
|
attrs.has_key((ns_uri, "attr")) and \
|
|
attrs.keys() == [(ns_uri, "attr")] and \
|
|
attrs.get((ns_uri, "attr")) == "val" and \
|
|
attrs.get((ns_uri, "attr"), 25) == "val" and \
|
|
attrs.items() == [((ns_uri, "attr"), "val")] and \
|
|
attrs.values() == ["val"] and \
|
|
attrs.getValue((ns_uri, "attr")) == "val" and \
|
|
attrs[(ns_uri, "attr")] == "val"
|
|
|
|
# ===== InputSource support
|
|
|
|
xml_test_out = open(findfile("test"+os.extsep+"xml"+os.extsep+"out")).read()
|
|
|
|
def test_expat_inpsource_filename():
|
|
parser = create_parser()
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
|
|
parser.setContentHandler(xmlgen)
|
|
parser.parse(findfile("test"+os.extsep+"xml"))
|
|
|
|
return result.getvalue() == xml_test_out
|
|
|
|
def test_expat_inpsource_sysid():
|
|
parser = create_parser()
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
|
|
parser.setContentHandler(xmlgen)
|
|
parser.parse(InputSource(findfile("test"+os.extsep+"xml")))
|
|
|
|
return result.getvalue() == xml_test_out
|
|
|
|
def test_expat_inpsource_stream():
|
|
parser = create_parser()
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
|
|
parser.setContentHandler(xmlgen)
|
|
inpsrc = InputSource()
|
|
inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml")))
|
|
parser.parse(inpsrc)
|
|
|
|
return result.getvalue() == xml_test_out
|
|
|
|
# ===== IncrementalParser support
|
|
|
|
def test_expat_incremental():
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
parser = create_parser()
|
|
parser.setContentHandler(xmlgen)
|
|
|
|
parser.feed("<doc>")
|
|
parser.feed("</doc>")
|
|
parser.close()
|
|
|
|
return result.getvalue() == start + "<doc></doc>"
|
|
|
|
def test_expat_incremental_reset():
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
parser = create_parser()
|
|
parser.setContentHandler(xmlgen)
|
|
|
|
parser.feed("<doc>")
|
|
parser.feed("text")
|
|
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
parser.setContentHandler(xmlgen)
|
|
parser.reset()
|
|
|
|
parser.feed("<doc>")
|
|
parser.feed("text")
|
|
parser.feed("</doc>")
|
|
parser.close()
|
|
|
|
return result.getvalue() == start + "<doc>text</doc>"
|
|
|
|
# ===== Locator support
|
|
|
|
def test_expat_locator_noinfo():
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
parser = create_parser()
|
|
parser.setContentHandler(xmlgen)
|
|
|
|
parser.feed("<doc>")
|
|
parser.feed("</doc>")
|
|
parser.close()
|
|
|
|
return parser.getSystemId() is None and \
|
|
parser.getPublicId() is None and \
|
|
parser.getLineNumber() == 1
|
|
|
|
def test_expat_locator_withinfo():
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
parser = create_parser()
|
|
parser.setContentHandler(xmlgen)
|
|
parser.parse(findfile("test.xml"))
|
|
|
|
return parser.getSystemId() == findfile("test.xml") and \
|
|
parser.getPublicId() is None
|
|
|
|
|
|
# ===========================================================================
|
|
#
|
|
# error reporting
|
|
#
|
|
# ===========================================================================
|
|
|
|
def test_expat_inpsource_location():
|
|
parser = create_parser()
|
|
parser.setContentHandler(ContentHandler()) # do nothing
|
|
source = InputSource()
|
|
source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed
|
|
name = "a file name"
|
|
source.setSystemId(name)
|
|
try:
|
|
parser.parse(source)
|
|
except SAXException, e:
|
|
return e.getSystemId() == name
|
|
|
|
def test_expat_incomplete():
|
|
parser = create_parser()
|
|
parser.setContentHandler(ContentHandler()) # do nothing
|
|
try:
|
|
parser.parse(StringIO("<foo>"))
|
|
except SAXParseException:
|
|
return 1 # ok, error found
|
|
else:
|
|
return 0
|
|
|
|
|
|
# ===========================================================================
|
|
#
|
|
# xmlreader tests
|
|
#
|
|
# ===========================================================================
|
|
|
|
# ===== AttributesImpl
|
|
|
|
def verify_empty_attrs(attrs):
|
|
try:
|
|
attrs.getValue("attr")
|
|
gvk = 0
|
|
except KeyError:
|
|
gvk = 1
|
|
|
|
try:
|
|
attrs.getValueByQName("attr")
|
|
gvqk = 0
|
|
except KeyError:
|
|
gvqk = 1
|
|
|
|
try:
|
|
attrs.getNameByQName("attr")
|
|
gnqk = 0
|
|
except KeyError:
|
|
gnqk = 1
|
|
|
|
try:
|
|
attrs.getQNameByName("attr")
|
|
gqnk = 0
|
|
except KeyError:
|
|
gqnk = 1
|
|
|
|
try:
|
|
attrs["attr"]
|
|
gik = 0
|
|
except KeyError:
|
|
gik = 1
|
|
|
|
return attrs.getLength() == 0 and \
|
|
attrs.getNames() == [] and \
|
|
attrs.getQNames() == [] and \
|
|
len(attrs) == 0 and \
|
|
not attrs.has_key("attr") and \
|
|
attrs.keys() == [] and \
|
|
attrs.get("attrs") is None and \
|
|
attrs.get("attrs", 25) == 25 and \
|
|
attrs.items() == [] and \
|
|
attrs.values() == [] and \
|
|
gvk and gvqk and gnqk and gik and gqnk
|
|
|
|
def verify_attrs_wattr(attrs):
|
|
return attrs.getLength() == 1 and \
|
|
attrs.getNames() == ["attr"] and \
|
|
attrs.getQNames() == ["attr"] and \
|
|
len(attrs) == 1 and \
|
|
attrs.has_key("attr") and \
|
|
attrs.keys() == ["attr"] and \
|
|
attrs.get("attr") == "val" and \
|
|
attrs.get("attr", 25) == "val" and \
|
|
attrs.items() == [("attr", "val")] and \
|
|
attrs.values() == ["val"] and \
|
|
attrs.getValue("attr") == "val" and \
|
|
attrs.getValueByQName("attr") == "val" and \
|
|
attrs.getNameByQName("attr") == "attr" and \
|
|
attrs["attr"] == "val" and \
|
|
attrs.getQNameByName("attr") == "attr"
|
|
|
|
def test_attrs_empty():
|
|
return verify_empty_attrs(AttributesImpl({}))
|
|
|
|
def test_attrs_wattr():
|
|
return verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
|
|
|
|
# ===== AttributesImpl
|
|
|
|
def verify_empty_nsattrs(attrs):
|
|
try:
|
|
attrs.getValue((ns_uri, "attr"))
|
|
gvk = 0
|
|
except KeyError:
|
|
gvk = 1
|
|
|
|
try:
|
|
attrs.getValueByQName("ns:attr")
|
|
gvqk = 0
|
|
except KeyError:
|
|
gvqk = 1
|
|
|
|
try:
|
|
attrs.getNameByQName("ns:attr")
|
|
gnqk = 0
|
|
except KeyError:
|
|
gnqk = 1
|
|
|
|
try:
|
|
attrs.getQNameByName((ns_uri, "attr"))
|
|
gqnk = 0
|
|
except KeyError:
|
|
gqnk = 1
|
|
|
|
try:
|
|
attrs[(ns_uri, "attr")]
|
|
gik = 0
|
|
except KeyError:
|
|
gik = 1
|
|
|
|
return attrs.getLength() == 0 and \
|
|
attrs.getNames() == [] and \
|
|
attrs.getQNames() == [] and \
|
|
len(attrs) == 0 and \
|
|
not attrs.has_key((ns_uri, "attr")) and \
|
|
attrs.keys() == [] and \
|
|
attrs.get((ns_uri, "attr")) is None and \
|
|
attrs.get((ns_uri, "attr"), 25) == 25 and \
|
|
attrs.items() == [] and \
|
|
attrs.values() == [] and \
|
|
gvk and gvqk and gnqk and gik and gqnk
|
|
|
|
def test_nsattrs_empty():
|
|
return verify_empty_nsattrs(AttributesNSImpl({}, {}))
|
|
|
|
def test_nsattrs_wattr():
|
|
attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
|
|
{(ns_uri, "attr") : "ns:attr"})
|
|
|
|
return attrs.getLength() == 1 and \
|
|
attrs.getNames() == [(ns_uri, "attr")] and \
|
|
attrs.getQNames() == ["ns:attr"] and \
|
|
len(attrs) == 1 and \
|
|
attrs.has_key((ns_uri, "attr")) and \
|
|
attrs.keys() == [(ns_uri, "attr")] and \
|
|
attrs.get((ns_uri, "attr")) == "val" and \
|
|
attrs.get((ns_uri, "attr"), 25) == "val" and \
|
|
attrs.items() == [((ns_uri, "attr"), "val")] and \
|
|
attrs.values() == ["val"] and \
|
|
attrs.getValue((ns_uri, "attr")) == "val" and \
|
|
attrs.getValueByQName("ns:attr") == "val" and \
|
|
attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \
|
|
attrs[(ns_uri, "attr")] == "val" and \
|
|
attrs.getQNameByName((ns_uri, "attr")) == "ns:attr"
|
|
|
|
|
|
# ===== Main program
|
|
|
|
def make_test_output():
|
|
parser = create_parser()
|
|
result = StringIO()
|
|
xmlgen = XMLGenerator(result)
|
|
|
|
parser.setContentHandler(xmlgen)
|
|
parser.parse(findfile("test"+os.extsep+"xml"))
|
|
|
|
outf = open(findfile("test"+os.extsep+"xml"+os.extsep+"out"), "w")
|
|
outf.write(result.getvalue())
|
|
outf.close()
|
|
|
|
items = locals().items()
|
|
items.sort()
|
|
for (name, value) in items:
|
|
if name[ : 5] == "test_":
|
|
confirm(value(), name)
|
|
|
|
if verbose:
|
|
print "%d tests, %d failures" % (tests, len(failures))
|
|
if failures:
|
|
raise TestFailed("%d of %d tests failed: %s"
|
|
% (len(failures), tests, ", ".join(failures)))
|