»Core Development>Code coverage>Lib/test/test_sax.py

Python code coverage for Lib/test/test_sax.py

#countcontent
1n/a# regression test for SAX 2.0
2n/a# $Id$
3n/a
4n/afrom xml.sax import make_parser, ContentHandler, \
5n/a SAXException, SAXReaderNotAvailable, SAXParseException
6n/aimport unittest
7n/atry:
8n/a make_parser()
9n/aexcept SAXReaderNotAvailable:
10n/a # don't try to test this module if we cannot create a parser
11n/a raise unittest.SkipTest("no XML parsers available")
12n/afrom xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \
13n/a XMLFilterBase, prepare_input_source
14n/afrom xml.sax.expatreader import create_parser
15n/afrom xml.sax.handler import feature_namespaces
16n/afrom xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl
17n/afrom io import BytesIO, StringIO
18n/aimport codecs
19n/aimport gc
20n/aimport os.path
21n/aimport shutil
22n/afrom test import support
23n/afrom test.support import findfile, run_unittest, TESTFN
24n/a
25n/aTEST_XMLFILE = findfile("test.xml", subdir="xmltestdata")
26n/aTEST_XMLFILE_OUT = findfile("test.xml.out", subdir="xmltestdata")
27n/atry:
28n/a TEST_XMLFILE.encode("utf-8")
29n/a TEST_XMLFILE_OUT.encode("utf-8")
30n/aexcept UnicodeEncodeError:
31n/a raise unittest.SkipTest("filename is not encodable to utf8")
32n/a
33n/asupports_nonascii_filenames = True
34n/aif not os.path.supports_unicode_filenames:
35n/a try:
36n/a support.TESTFN_UNICODE.encode(support.TESTFN_ENCODING)
37n/a except (UnicodeError, TypeError):
38n/a # Either the file system encoding is None, or the file name
39n/a # cannot be encoded in the file system encoding.
40n/a supports_nonascii_filenames = False
41n/arequires_nonascii_filenames = unittest.skipUnless(
42n/a supports_nonascii_filenames,
43n/a 'Requires non-ascii filenames support')
44n/a
45n/ans_uri = "http://www.python.org/xml-ns/saxtest/"
46n/a
47n/aclass XmlTestBase(unittest.TestCase):
48n/a def verify_empty_attrs(self, attrs):
49n/a self.assertRaises(KeyError, attrs.getValue, "attr")
50n/a self.assertRaises(KeyError, attrs.getValueByQName, "attr")
51n/a self.assertRaises(KeyError, attrs.getNameByQName, "attr")
52n/a self.assertRaises(KeyError, attrs.getQNameByName, "attr")
53n/a self.assertRaises(KeyError, attrs.__getitem__, "attr")
54n/a self.assertEqual(attrs.getLength(), 0)
55n/a self.assertEqual(attrs.getNames(), [])
56n/a self.assertEqual(attrs.getQNames(), [])
57n/a self.assertEqual(len(attrs), 0)
58n/a self.assertNotIn("attr", attrs)
59n/a self.assertEqual(list(attrs.keys()), [])
60n/a self.assertEqual(attrs.get("attrs"), None)
61n/a self.assertEqual(attrs.get("attrs", 25), 25)
62n/a self.assertEqual(list(attrs.items()), [])
63n/a self.assertEqual(list(attrs.values()), [])
64n/a
65n/a def verify_empty_nsattrs(self, attrs):
66n/a self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr"))
67n/a self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr")
68n/a self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr")
69n/a self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr"))
70n/a self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr"))
71n/a self.assertEqual(attrs.getLength(), 0)
72n/a self.assertEqual(attrs.getNames(), [])
73n/a self.assertEqual(attrs.getQNames(), [])
74n/a self.assertEqual(len(attrs), 0)
75n/a self.assertNotIn((ns_uri, "attr"), attrs)
76n/a self.assertEqual(list(attrs.keys()), [])
77n/a self.assertEqual(attrs.get((ns_uri, "attr")), None)
78n/a self.assertEqual(attrs.get((ns_uri, "attr"), 25), 25)
79n/a self.assertEqual(list(attrs.items()), [])
80n/a self.assertEqual(list(attrs.values()), [])
81n/a
82n/a def verify_attrs_wattr(self, attrs):
83n/a self.assertEqual(attrs.getLength(), 1)
84n/a self.assertEqual(attrs.getNames(), ["attr"])
85n/a self.assertEqual(attrs.getQNames(), ["attr"])
86n/a self.assertEqual(len(attrs), 1)
87n/a self.assertIn("attr", attrs)
88n/a self.assertEqual(list(attrs.keys()), ["attr"])
89n/a self.assertEqual(attrs.get("attr"), "val")
90n/a self.assertEqual(attrs.get("attr", 25), "val")
91n/a self.assertEqual(list(attrs.items()), [("attr", "val")])
92n/a self.assertEqual(list(attrs.values()), ["val"])
93n/a self.assertEqual(attrs.getValue("attr"), "val")
94n/a self.assertEqual(attrs.getValueByQName("attr"), "val")
95n/a self.assertEqual(attrs.getNameByQName("attr"), "attr")
96n/a self.assertEqual(attrs["attr"], "val")
97n/a self.assertEqual(attrs.getQNameByName("attr"), "attr")
98n/a
99n/a
100n/adef xml_str(doc, encoding=None):
101n/a if encoding is None:
102n/a return doc
103n/a return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
104n/a
105n/adef xml_bytes(doc, encoding, decl_encoding=...):
106n/a if decl_encoding is ...:
107n/a decl_encoding = encoding
108n/a return xml_str(doc, decl_encoding).encode(encoding, 'xmlcharrefreplace')
109n/a
110n/adef make_xml_file(doc, encoding, decl_encoding=...):
111n/a if decl_encoding is ...:
112n/a decl_encoding = encoding
113n/a with open(TESTFN, 'w', encoding=encoding, errors='xmlcharrefreplace') as f:
114n/a f.write(xml_str(doc, decl_encoding))
115n/a
116n/a
117n/aclass ParseTest(unittest.TestCase):
118n/a data = '<money value="$\xa3\u20ac\U0001017b">$\xa3\u20ac\U0001017b</money>'
119n/a
120n/a def tearDown(self):
121n/a support.unlink(TESTFN)
122n/a
123n/a def check_parse(self, f):
124n/a from xml.sax import parse
125n/a result = StringIO()
126n/a parse(f, XMLGenerator(result, 'utf-8'))
127n/a self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
128n/a
129n/a def test_parse_text(self):
130n/a encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
131n/a 'utf-16', 'utf-16le', 'utf-16be')
132n/a for encoding in encodings:
133n/a self.check_parse(StringIO(xml_str(self.data, encoding)))
134n/a make_xml_file(self.data, encoding)
135n/a with open(TESTFN, 'r', encoding=encoding) as f:
136n/a self.check_parse(f)
137n/a self.check_parse(StringIO(self.data))
138n/a make_xml_file(self.data, encoding, None)
139n/a with open(TESTFN, 'r', encoding=encoding) as f:
140n/a self.check_parse(f)
141n/a
142n/a def test_parse_bytes(self):
143n/a # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
144n/a # UTF-16 is autodetected
145n/a encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
146n/a for encoding in encodings:
147n/a self.check_parse(BytesIO(xml_bytes(self.data, encoding)))
148n/a make_xml_file(self.data, encoding)
149n/a self.check_parse(TESTFN)
150n/a with open(TESTFN, 'rb') as f:
151n/a self.check_parse(f)
152n/a self.check_parse(BytesIO(xml_bytes(self.data, encoding, None)))
153n/a make_xml_file(self.data, encoding, None)
154n/a self.check_parse(TESTFN)
155n/a with open(TESTFN, 'rb') as f:
156n/a self.check_parse(f)
157n/a # accept UTF-8 with BOM
158n/a self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', 'utf-8')))
159n/a make_xml_file(self.data, 'utf-8-sig', 'utf-8')
160n/a self.check_parse(TESTFN)
161n/a with open(TESTFN, 'rb') as f:
162n/a self.check_parse(f)
163n/a self.check_parse(BytesIO(xml_bytes(self.data, 'utf-8-sig', None)))
164n/a make_xml_file(self.data, 'utf-8-sig', None)
165n/a self.check_parse(TESTFN)
166n/a with open(TESTFN, 'rb') as f:
167n/a self.check_parse(f)
168n/a # accept data with declared encoding
169n/a self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1')))
170n/a make_xml_file(self.data, 'iso-8859-1')
171n/a self.check_parse(TESTFN)
172n/a with open(TESTFN, 'rb') as f:
173n/a self.check_parse(f)
174n/a # fail on non-UTF-8 incompatible data without declared encoding
175n/a with self.assertRaises(SAXException):
176n/a self.check_parse(BytesIO(xml_bytes(self.data, 'iso-8859-1', None)))
177n/a make_xml_file(self.data, 'iso-8859-1', None)
178n/a with support.check_warnings(('unclosed file', ResourceWarning)):
179n/a # XXX Failed parser leaks an opened file.
180n/a with self.assertRaises(SAXException):
181n/a self.check_parse(TESTFN)
182n/a # Collect leaked file.
183n/a gc.collect()
184n/a with open(TESTFN, 'rb') as f:
185n/a with self.assertRaises(SAXException):
186n/a self.check_parse(f)
187n/a
188n/a def test_parse_InputSource(self):
189n/a # accept data without declared but with explicitly specified encoding
190n/a make_xml_file(self.data, 'iso-8859-1', None)
191n/a with open(TESTFN, 'rb') as f:
192n/a input = InputSource()
193n/a input.setByteStream(f)
194n/a input.setEncoding('iso-8859-1')
195n/a self.check_parse(input)
196n/a
197n/a def check_parseString(self, s):
198n/a from xml.sax import parseString
199n/a result = StringIO()
200n/a parseString(s, XMLGenerator(result, 'utf-8'))
201n/a self.assertEqual(result.getvalue(), xml_str(self.data, 'utf-8'))
202n/a
203n/a def test_parseString_text(self):
204n/a encodings = ('us-ascii', 'iso-8859-1', 'utf-8',
205n/a 'utf-16', 'utf-16le', 'utf-16be')
206n/a for encoding in encodings:
207n/a self.check_parseString(xml_str(self.data, encoding))
208n/a self.check_parseString(self.data)
209n/a
210n/a def test_parseString_bytes(self):
211n/a # UTF-8 is default encoding, US-ASCII is compatible with UTF-8,
212n/a # UTF-16 is autodetected
213n/a encodings = ('us-ascii', 'utf-8', 'utf-16', 'utf-16le', 'utf-16be')
214n/a for encoding in encodings:
215n/a self.check_parseString(xml_bytes(self.data, encoding))
216n/a self.check_parseString(xml_bytes(self.data, encoding, None))
217n/a # accept UTF-8 with BOM
218n/a self.check_parseString(xml_bytes(self.data, 'utf-8-sig', 'utf-8'))
219n/a self.check_parseString(xml_bytes(self.data, 'utf-8-sig', None))
220n/a # accept data with declared encoding
221n/a self.check_parseString(xml_bytes(self.data, 'iso-8859-1'))
222n/a # fail on non-UTF-8 incompatible data without declared encoding
223n/a with self.assertRaises(SAXException):
224n/a self.check_parseString(xml_bytes(self.data, 'iso-8859-1', None))
225n/a
226n/aclass MakeParserTest(unittest.TestCase):
227n/a def test_make_parser2(self):
228n/a # Creating parsers several times in a row should succeed.
229n/a # Testing this because there have been failures of this kind
230n/a # before.
231n/a from xml.sax import make_parser
232n/a p = make_parser()
233n/a from xml.sax import make_parser
234n/a p = make_parser()
235n/a from xml.sax import make_parser
236n/a p = make_parser()
237n/a from xml.sax import make_parser
238n/a p = make_parser()
239n/a from xml.sax import make_parser
240n/a p = make_parser()
241n/a from xml.sax import make_parser
242n/a p = make_parser()
243n/a
244n/a
245n/a# ===========================================================================
246n/a#
247n/a# saxutils tests
248n/a#
249n/a# ===========================================================================
250n/a
251n/aclass SaxutilsTest(unittest.TestCase):
252n/a # ===== escape
253n/a def test_escape_basic(self):
254n/a self.assertEqual(escape("Donald Duck & Co"), "Donald Duck &amp; Co")
255n/a
256n/a def test_escape_all(self):
257n/a self.assertEqual(escape("<Donald Duck & Co>"),
258n/a "&lt;Donald Duck &amp; Co&gt;")
259n/a
260n/a def test_escape_extra(self):
261n/a self.assertEqual(escape("Hei på deg", {"å" : "&aring;"}),
262n/a "Hei p&aring; deg")
263n/a
264n/a # ===== unescape
265n/a def test_unescape_basic(self):
266n/a self.assertEqual(unescape("Donald Duck &amp; Co"), "Donald Duck & Co")
267n/a
268n/a def test_unescape_all(self):
269n/a self.assertEqual(unescape("&lt;Donald Duck &amp; Co&gt;"),
270n/a "<Donald Duck & Co>")
271n/a
272n/a def test_unescape_extra(self):
273n/a self.assertEqual(unescape("Hei på deg", {"å" : "&aring;"}),
274n/a "Hei p&aring; deg")
275n/a
276n/a def test_unescape_amp_extra(self):
277n/a self.assertEqual(unescape("&amp;foo;", {"&foo;": "splat"}), "&foo;")
278n/a
279n/a # ===== quoteattr
280n/a def test_quoteattr_basic(self):
281n/a self.assertEqual(quoteattr("Donald Duck & Co"),
282n/a '"Donald Duck &amp; Co"')
283n/a
284n/a def test_single_quoteattr(self):
285n/a self.assertEqual(quoteattr('Includes "double" quotes'),
286n/a '\'Includes "double" quotes\'')
287n/a
288n/a def test_double_quoteattr(self):
289n/a self.assertEqual(quoteattr("Includes 'single' quotes"),
290n/a "\"Includes 'single' quotes\"")
291n/a
292n/a def test_single_double_quoteattr(self):
293n/a self.assertEqual(quoteattr("Includes 'single' and \"double\" quotes"),
294n/a "\"Includes 'single' and &quot;double&quot; quotes\"")
295n/a
296n/a # ===== make_parser
297n/a def test_make_parser(self):
298n/a # Creating a parser should succeed - it should fall back
299n/a # to the expatreader
300n/a p = make_parser(['xml.parsers.no_such_parser'])
301n/a
302n/a
303n/aclass PrepareInputSourceTest(unittest.TestCase):
304n/a
305n/a def setUp(self):
306n/a self.file = support.TESTFN
307n/a with open(self.file, "w") as tmp:
308n/a tmp.write("This was read from a file.")
309n/a
310n/a def tearDown(self):
311n/a support.unlink(self.file)
312n/a
313n/a def make_byte_stream(self):
314n/a return BytesIO(b"This is a byte stream.")
315n/a
316n/a def make_character_stream(self):
317n/a return StringIO("This is a character stream.")
318n/a
319n/a def checkContent(self, stream, content):
320n/a self.assertIsNotNone(stream)
321n/a self.assertEqual(stream.read(), content)
322n/a stream.close()
323n/a
324n/a
325n/a def test_character_stream(self):
326n/a # If the source is an InputSource with a character stream, use it.
327n/a src = InputSource(self.file)
328n/a src.setCharacterStream(self.make_character_stream())
329n/a prep = prepare_input_source(src)
330n/a self.assertIsNone(prep.getByteStream())
331n/a self.checkContent(prep.getCharacterStream(),
332n/a "This is a character stream.")
333n/a
334n/a def test_byte_stream(self):
335n/a # If the source is an InputSource that does not have a character
336n/a # stream but does have a byte stream, use the byte stream.
337n/a src = InputSource(self.file)
338n/a src.setByteStream(self.make_byte_stream())
339n/a prep = prepare_input_source(src)
340n/a self.assertIsNone(prep.getCharacterStream())
341n/a self.checkContent(prep.getByteStream(),
342n/a b"This is a byte stream.")
343n/a
344n/a def test_system_id(self):
345n/a # If the source is an InputSource that has neither a character
346n/a # stream nor a byte stream, open the system ID.
347n/a src = InputSource(self.file)
348n/a prep = prepare_input_source(src)
349n/a self.assertIsNone(prep.getCharacterStream())
350n/a self.checkContent(prep.getByteStream(),
351n/a b"This was read from a file.")
352n/a
353n/a def test_string(self):
354n/a # If the source is a string, use it as a system ID and open it.
355n/a prep = prepare_input_source(self.file)
356n/a self.assertIsNone(prep.getCharacterStream())
357n/a self.checkContent(prep.getByteStream(),
358n/a b"This was read from a file.")
359n/a
360n/a def test_binary_file(self):
361n/a # If the source is a binary file-like object, use it as a byte
362n/a # stream.
363n/a prep = prepare_input_source(self.make_byte_stream())
364n/a self.assertIsNone(prep.getCharacterStream())
365n/a self.checkContent(prep.getByteStream(),
366n/a b"This is a byte stream.")
367n/a
368n/a def test_text_file(self):
369n/a # If the source is a text file-like object, use it as a character
370n/a # stream.
371n/a prep = prepare_input_source(self.make_character_stream())
372n/a self.assertIsNone(prep.getByteStream())
373n/a self.checkContent(prep.getCharacterStream(),
374n/a "This is a character stream.")
375n/a
376n/a
377n/a# ===== XMLGenerator
378n/a
379n/aclass XmlgenTest:
380n/a def test_xmlgen_basic(self):
381n/a result = self.ioclass()
382n/a gen = XMLGenerator(result)
383n/a gen.startDocument()
384n/a gen.startElement("doc", {})
385n/a gen.endElement("doc")
386n/a gen.endDocument()
387n/a
388n/a self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))
389n/a
390n/a def test_xmlgen_basic_empty(self):
391n/a result = self.ioclass()
392n/a gen = XMLGenerator(result, short_empty_elements=True)
393n/a gen.startDocument()
394n/a gen.startElement("doc", {})
395n/a gen.endElement("doc")
396n/a gen.endDocument()
397n/a
398n/a self.assertEqual(result.getvalue(), self.xml("<doc/>"))
399n/a
400n/a def test_xmlgen_content(self):
401n/a result = self.ioclass()
402n/a gen = XMLGenerator(result)
403n/a
404n/a gen.startDocument()
405n/a gen.startElement("doc", {})
406n/a gen.characters("huhei")
407n/a gen.endElement("doc")
408n/a gen.endDocument()
409n/a
410n/a self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
411n/a
412n/a def test_xmlgen_content_empty(self):
413n/a result = self.ioclass()
414n/a gen = XMLGenerator(result, short_empty_elements=True)
415n/a
416n/a gen.startDocument()
417n/a gen.startElement("doc", {})
418n/a gen.characters("huhei")
419n/a gen.endElement("doc")
420n/a gen.endDocument()
421n/a
422n/a self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))
423n/a
424n/a def test_xmlgen_pi(self):
425n/a result = self.ioclass()
426n/a gen = XMLGenerator(result)
427n/a
428n/a gen.startDocument()
429n/a gen.processingInstruction("test", "data")
430n/a gen.startElement("doc", {})
431n/a gen.endElement("doc")
432n/a gen.endDocument()
433n/a
434n/a self.assertEqual(result.getvalue(),
435n/a self.xml("<?test data?><doc></doc>"))
436n/a
437n/a def test_xmlgen_content_escape(self):
438n/a result = self.ioclass()
439n/a gen = XMLGenerator(result)
440n/a
441n/a gen.startDocument()
442n/a gen.startElement("doc", {})
443n/a gen.characters("<huhei&")
444n/a gen.endElement("doc")
445n/a gen.endDocument()
446n/a
447n/a self.assertEqual(result.getvalue(),
448n/a self.xml("<doc>&lt;huhei&amp;</doc>"))
449n/a
450n/a def test_xmlgen_attr_escape(self):
451n/a result = self.ioclass()
452n/a gen = XMLGenerator(result)
453n/a
454n/a gen.startDocument()
455n/a gen.startElement("doc", {"a": '"'})
456n/a gen.startElement("e", {"a": "'"})
457n/a gen.endElement("e")
458n/a gen.startElement("e", {"a": "'\""})
459n/a gen.endElement("e")
460n/a gen.startElement("e", {"a": "\n\r\t"})
461n/a gen.endElement("e")
462n/a gen.endElement("doc")
463n/a gen.endDocument()
464n/a
465n/a self.assertEqual(result.getvalue(), self.xml(
466n/a "<doc a='\"'><e a=\"'\"></e>"
467n/a "<e a=\"'&quot;\"></e>"
468n/a "<e a=\"&#10;&#13;&#9;\"></e></doc>"))
469n/a
470n/a def test_xmlgen_encoding(self):
471n/a encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
472n/a 'utf-16', 'utf-16be', 'utf-16le',
473n/a 'utf-32', 'utf-32be', 'utf-32le')
474n/a for encoding in encodings:
475n/a result = self.ioclass()
476n/a gen = XMLGenerator(result, encoding=encoding)
477n/a
478n/a gen.startDocument()
479n/a gen.startElement("doc", {"a": '\u20ac'})
480n/a gen.characters("\u20ac")
481n/a gen.endElement("doc")
482n/a gen.endDocument()
483n/a
484n/a self.assertEqual(result.getvalue(),
485n/a self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))
486n/a
487n/a def test_xmlgen_unencodable(self):
488n/a result = self.ioclass()
489n/a gen = XMLGenerator(result, encoding='ascii')
490n/a
491n/a gen.startDocument()
492n/a gen.startElement("doc", {"a": '\u20ac'})
493n/a gen.characters("\u20ac")
494n/a gen.endElement("doc")
495n/a gen.endDocument()
496n/a
497n/a self.assertEqual(result.getvalue(),
498n/a self.xml('<doc a="&#8364;">&#8364;</doc>', encoding='ascii'))
499n/a
500n/a def test_xmlgen_ignorable(self):
501n/a result = self.ioclass()
502n/a gen = XMLGenerator(result)
503n/a
504n/a gen.startDocument()
505n/a gen.startElement("doc", {})
506n/a gen.ignorableWhitespace(" ")
507n/a gen.endElement("doc")
508n/a gen.endDocument()
509n/a
510n/a self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
511n/a
512n/a def test_xmlgen_ignorable_empty(self):
513n/a result = self.ioclass()
514n/a gen = XMLGenerator(result, short_empty_elements=True)
515n/a
516n/a gen.startDocument()
517n/a gen.startElement("doc", {})
518n/a gen.ignorableWhitespace(" ")
519n/a gen.endElement("doc")
520n/a gen.endDocument()
521n/a
522n/a self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))
523n/a
524n/a def test_xmlgen_encoding_bytes(self):
525n/a encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',
526n/a 'utf-16', 'utf-16be', 'utf-16le',
527n/a 'utf-32', 'utf-32be', 'utf-32le')
528n/a for encoding in encodings:
529n/a result = self.ioclass()
530n/a gen = XMLGenerator(result, encoding=encoding)
531n/a
532n/a gen.startDocument()
533n/a gen.startElement("doc", {"a": '\u20ac'})
534n/a gen.characters("\u20ac".encode(encoding))
535n/a gen.ignorableWhitespace(" ".encode(encoding))
536n/a gen.endElement("doc")
537n/a gen.endDocument()
538n/a
539n/a self.assertEqual(result.getvalue(),
540n/a self.xml('<doc a="\u20ac">\u20ac </doc>', encoding=encoding))
541n/a
542n/a def test_xmlgen_ns(self):
543n/a result = self.ioclass()
544n/a gen = XMLGenerator(result)
545n/a
546n/a gen.startDocument()
547n/a gen.startPrefixMapping("ns1", ns_uri)
548n/a gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
549n/a # add an unqualified name
550n/a gen.startElementNS((None, "udoc"), None, {})
551n/a gen.endElementNS((None, "udoc"), None)
552n/a gen.endElementNS((ns_uri, "doc"), "ns1:doc")
553n/a gen.endPrefixMapping("ns1")
554n/a gen.endDocument()
555n/a
556n/a self.assertEqual(result.getvalue(), self.xml(
557n/a '<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
558n/a ns_uri))
559n/a
560n/a def test_xmlgen_ns_empty(self):
561n/a result = self.ioclass()
562n/a gen = XMLGenerator(result, short_empty_elements=True)
563n/a
564n/a gen.startDocument()
565n/a gen.startPrefixMapping("ns1", ns_uri)
566n/a gen.startElementNS((ns_uri, "doc"), "ns1:doc", {})
567n/a # add an unqualified name
568n/a gen.startElementNS((None, "udoc"), None, {})
569n/a gen.endElementNS((None, "udoc"), None)
570n/a gen.endElementNS((ns_uri, "doc"), "ns1:doc")
571n/a gen.endPrefixMapping("ns1")
572n/a gen.endDocument()
573n/a
574n/a self.assertEqual(result.getvalue(), self.xml(
575n/a '<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %
576n/a ns_uri))
577n/a
578n/a def test_1463026_1(self):
579n/a result = self.ioclass()
580n/a gen = XMLGenerator(result)
581n/a
582n/a gen.startDocument()
583n/a gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
584n/a gen.endElementNS((None, 'a'), 'a')
585n/a gen.endDocument()
586n/a
587n/a self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))
588n/a
589n/a def test_1463026_1_empty(self):
590n/a result = self.ioclass()
591n/a gen = XMLGenerator(result, short_empty_elements=True)
592n/a
593n/a gen.startDocument()
594n/a gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
595n/a gen.endElementNS((None, 'a'), 'a')
596n/a gen.endDocument()
597n/a
598n/a self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))
599n/a
600n/a def test_1463026_2(self):
601n/a result = self.ioclass()
602n/a gen = XMLGenerator(result)
603n/a
604n/a gen.startDocument()
605n/a gen.startPrefixMapping(None, 'qux')
606n/a gen.startElementNS(('qux', 'a'), 'a', {})
607n/a gen.endElementNS(('qux', 'a'), 'a')
608n/a gen.endPrefixMapping(None)
609n/a gen.endDocument()
610n/a
611n/a self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))
612n/a
613n/a def test_1463026_2_empty(self):
614n/a result = self.ioclass()
615n/a gen = XMLGenerator(result, short_empty_elements=True)
616n/a
617n/a gen.startDocument()
618n/a gen.startPrefixMapping(None, 'qux')
619n/a gen.startElementNS(('qux', 'a'), 'a', {})
620n/a gen.endElementNS(('qux', 'a'), 'a')
621n/a gen.endPrefixMapping(None)
622n/a gen.endDocument()
623n/a
624n/a self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))
625n/a
626n/a def test_1463026_3(self):
627n/a result = self.ioclass()
628n/a gen = XMLGenerator(result)
629n/a
630n/a gen.startDocument()
631n/a gen.startPrefixMapping('my', 'qux')
632n/a gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
633n/a gen.endElementNS(('qux', 'a'), 'a')
634n/a gen.endPrefixMapping('my')
635n/a gen.endDocument()
636n/a
637n/a self.assertEqual(result.getvalue(),
638n/a self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))
639n/a
640n/a def test_1463026_3_empty(self):
641n/a result = self.ioclass()
642n/a gen = XMLGenerator(result, short_empty_elements=True)
643n/a
644n/a gen.startDocument()
645n/a gen.startPrefixMapping('my', 'qux')
646n/a gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
647n/a gen.endElementNS(('qux', 'a'), 'a')
648n/a gen.endPrefixMapping('my')
649n/a gen.endDocument()
650n/a
651n/a self.assertEqual(result.getvalue(),
652n/a self.xml('<my:a xmlns:my="qux" b="c"/>'))
653n/a
654n/a def test_5027_1(self):
655n/a # The xml prefix (as in xml:lang below) is reserved and bound by
656n/a # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
657n/a # a bug whereby a KeyError is raised because this namespace is missing
658n/a # from a dictionary.
659n/a #
660n/a # This test demonstrates the bug by parsing a document.
661n/a test_xml = StringIO(
662n/a '<?xml version="1.0"?>'
663n/a '<a:g1 xmlns:a="http://example.com/ns">'
664n/a '<a:g2 xml:lang="en">Hello</a:g2>'
665n/a '</a:g1>')
666n/a
667n/a parser = make_parser()
668n/a parser.setFeature(feature_namespaces, True)
669n/a result = self.ioclass()
670n/a gen = XMLGenerator(result)
671n/a parser.setContentHandler(gen)
672n/a parser.parse(test_xml)
673n/a
674n/a self.assertEqual(result.getvalue(),
675n/a self.xml(
676n/a '<a:g1 xmlns:a="http://example.com/ns">'
677n/a '<a:g2 xml:lang="en">Hello</a:g2>'
678n/a '</a:g1>'))
679n/a
680n/a def test_5027_2(self):
681n/a # The xml prefix (as in xml:lang below) is reserved and bound by
682n/a # definition to http://www.w3.org/XML/1998/namespace. XMLGenerator had
683n/a # a bug whereby a KeyError is raised because this namespace is missing
684n/a # from a dictionary.
685n/a #
686n/a # This test demonstrates the bug by direct manipulation of the
687n/a # XMLGenerator.
688n/a result = self.ioclass()
689n/a gen = XMLGenerator(result)
690n/a
691n/a gen.startDocument()
692n/a gen.startPrefixMapping('a', 'http://example.com/ns')
693n/a gen.startElementNS(('http://example.com/ns', 'g1'), 'g1', {})
694n/a lang_attr = {('http://www.w3.org/XML/1998/namespace', 'lang'): 'en'}
695n/a gen.startElementNS(('http://example.com/ns', 'g2'), 'g2', lang_attr)
696n/a gen.characters('Hello')
697n/a gen.endElementNS(('http://example.com/ns', 'g2'), 'g2')
698n/a gen.endElementNS(('http://example.com/ns', 'g1'), 'g1')
699n/a gen.endPrefixMapping('a')
700n/a gen.endDocument()
701n/a
702n/a self.assertEqual(result.getvalue(),
703n/a self.xml(
704n/a '<a:g1 xmlns:a="http://example.com/ns">'
705n/a '<a:g2 xml:lang="en">Hello</a:g2>'
706n/a '</a:g1>'))
707n/a
708n/a def test_no_close_file(self):
709n/a result = self.ioclass()
710n/a def func(out):
711n/a gen = XMLGenerator(out)
712n/a gen.startDocument()
713n/a gen.startElement("doc", {})
714n/a func(result)
715n/a self.assertFalse(result.closed)
716n/a
717n/a def test_xmlgen_fragment(self):
718n/a result = self.ioclass()
719n/a gen = XMLGenerator(result)
720n/a
721n/a # Don't call gen.startDocument()
722n/a gen.startElement("foo", {"a": "1.0"})
723n/a gen.characters("Hello")
724n/a gen.endElement("foo")
725n/a gen.startElement("bar", {"b": "2.0"})
726n/a gen.endElement("bar")
727n/a # Don't call gen.endDocument()
728n/a
729n/a self.assertEqual(result.getvalue(),
730n/a self.xml('<foo a="1.0">Hello</foo><bar b="2.0"></bar>')[len(self.xml('')):])
731n/a
732n/aclass StringXmlgenTest(XmlgenTest, unittest.TestCase):
733n/a ioclass = StringIO
734n/a
735n/a def xml(self, doc, encoding='iso-8859-1'):
736n/a return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)
737n/a
738n/a test_xmlgen_unencodable = None
739n/a
740n/aclass BytesXmlgenTest(XmlgenTest, unittest.TestCase):
741n/a ioclass = BytesIO
742n/a
743n/a def xml(self, doc, encoding='iso-8859-1'):
744n/a return ('<?xml version="1.0" encoding="%s"?>\n%s' %
745n/a (encoding, doc)).encode(encoding, 'xmlcharrefreplace')
746n/a
747n/aclass WriterXmlgenTest(BytesXmlgenTest):
748n/a class ioclass(list):
749n/a write = list.append
750n/a closed = False
751n/a
752n/a def seekable(self):
753n/a return True
754n/a
755n/a def tell(self):
756n/a # return 0 at start and not 0 after start
757n/a return len(self)
758n/a
759n/a def getvalue(self):
760n/a return b''.join(self)
761n/a
762n/aclass StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase):
763n/a def ioclass(self):
764n/a raw = BytesIO()
765n/a writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace')
766n/a writer.getvalue = raw.getvalue
767n/a return writer
768n/a
769n/a def xml(self, doc, encoding='iso-8859-1'):
770n/a return ('<?xml version="1.0" encoding="%s"?>\n%s' %
771n/a (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
772n/a
773n/aclass StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase):
774n/a fname = support.TESTFN + '-codecs'
775n/a
776n/a def ioclass(self):
777n/a writer = codecs.open(self.fname, 'w', encoding='ascii',
778n/a errors='xmlcharrefreplace', buffering=0)
779n/a def cleanup():
780n/a writer.close()
781n/a support.unlink(self.fname)
782n/a self.addCleanup(cleanup)
783n/a def getvalue():
784n/a # Windows will not let use reopen without first closing
785n/a writer.close()
786n/a with open(writer.name, 'rb') as f:
787n/a return f.read()
788n/a writer.getvalue = getvalue
789n/a return writer
790n/a
791n/a def xml(self, doc, encoding='iso-8859-1'):
792n/a return ('<?xml version="1.0" encoding="%s"?>\n%s' %
793n/a (encoding, doc)).encode('ascii', 'xmlcharrefreplace')
794n/a
795n/astart = b'<?xml version="1.0" encoding="iso-8859-1"?>\n'
796n/a
797n/a
798n/aclass XMLFilterBaseTest(unittest.TestCase):
799n/a def test_filter_basic(self):
800n/a result = BytesIO()
801n/a gen = XMLGenerator(result)
802n/a filter = XMLFilterBase()
803n/a filter.setContentHandler(gen)
804n/a
805n/a filter.startDocument()
806n/a filter.startElement("doc", {})
807n/a filter.characters("content")
808n/a filter.ignorableWhitespace(" ")
809n/a filter.endElement("doc")
810n/a filter.endDocument()
811n/a
812n/a self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")
813n/a
814n/a# ===========================================================================
815n/a#
816n/a# expatreader tests
817n/a#
818n/a# ===========================================================================
819n/a
820n/awith open(TEST_XMLFILE_OUT, 'rb') as f:
821n/a xml_test_out = f.read()
822n/a
823n/aclass ExpatReaderTest(XmlTestBase):
824n/a
825n/a # ===== XMLReader support
826n/a
827n/a def test_expat_binary_file(self):
828n/a parser = create_parser()
829n/a result = BytesIO()
830n/a xmlgen = XMLGenerator(result)
831n/a
832n/a parser.setContentHandler(xmlgen)
833n/a with open(TEST_XMLFILE, 'rb') as f:
834n/a parser.parse(f)
835n/a
836n/a self.assertEqual(result.getvalue(), xml_test_out)
837n/a
838n/a def test_expat_text_file(self):
839n/a parser = create_parser()
840n/a result = BytesIO()
841n/a xmlgen = XMLGenerator(result)
842n/a
843n/a parser.setContentHandler(xmlgen)
844n/a with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
845n/a parser.parse(f)
846n/a
847n/a self.assertEqual(result.getvalue(), xml_test_out)
848n/a
849n/a @requires_nonascii_filenames
850n/a def test_expat_binary_file_nonascii(self):
851n/a fname = support.TESTFN_UNICODE
852n/a shutil.copyfile(TEST_XMLFILE, fname)
853n/a self.addCleanup(support.unlink, fname)
854n/a
855n/a parser = create_parser()
856n/a result = BytesIO()
857n/a xmlgen = XMLGenerator(result)
858n/a
859n/a parser.setContentHandler(xmlgen)
860n/a parser.parse(open(fname, 'rb'))
861n/a
862n/a self.assertEqual(result.getvalue(), xml_test_out)
863n/a
864n/a def test_expat_binary_file_bytes_name(self):
865n/a fname = os.fsencode(TEST_XMLFILE)
866n/a parser = create_parser()
867n/a result = BytesIO()
868n/a xmlgen = XMLGenerator(result)
869n/a
870n/a parser.setContentHandler(xmlgen)
871n/a with open(fname, 'rb') as f:
872n/a parser.parse(f)
873n/a
874n/a self.assertEqual(result.getvalue(), xml_test_out)
875n/a
876n/a def test_expat_binary_file_int_name(self):
877n/a parser = create_parser()
878n/a result = BytesIO()
879n/a xmlgen = XMLGenerator(result)
880n/a
881n/a parser.setContentHandler(xmlgen)
882n/a with open(TEST_XMLFILE, 'rb') as f:
883n/a with open(f.fileno(), 'rb', closefd=False) as f2:
884n/a parser.parse(f2)
885n/a
886n/a self.assertEqual(result.getvalue(), xml_test_out)
887n/a
888n/a # ===== DTDHandler support
889n/a
890n/a class TestDTDHandler:
891n/a
892n/a def __init__(self):
893n/a self._notations = []
894n/a self._entities = []
895n/a
896n/a def notationDecl(self, name, publicId, systemId):
897n/a self._notations.append((name, publicId, systemId))
898n/a
899n/a def unparsedEntityDecl(self, name, publicId, systemId, ndata):
900n/a self._entities.append((name, publicId, systemId, ndata))
901n/a
902n/a def test_expat_dtdhandler(self):
903n/a parser = create_parser()
904n/a handler = self.TestDTDHandler()
905n/a parser.setDTDHandler(handler)
906n/a
907n/a parser.feed('<!DOCTYPE doc [\n')
908n/a parser.feed(' <!ENTITY img SYSTEM "expat.gif" NDATA GIF>\n')
909n/a parser.feed(' <!NOTATION GIF PUBLIC "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">\n')
910n/a parser.feed(']>\n')
911n/a parser.feed('<doc></doc>')
912n/a parser.close()
913n/a
914n/a self.assertEqual(handler._notations,
915n/a [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)])
916n/a self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")])
917n/a
918n/a # ===== EntityResolver support
919n/a
920n/a class TestEntityResolver:
921n/a
922n/a def resolveEntity(self, publicId, systemId):
923n/a inpsrc = InputSource()
924n/a inpsrc.setByteStream(BytesIO(b"<entity/>"))
925n/a return inpsrc
926n/a
927n/a def test_expat_entityresolver(self):
928n/a parser = create_parser()
929n/a parser.setEntityResolver(self.TestEntityResolver())
930n/a result = BytesIO()
931n/a parser.setContentHandler(XMLGenerator(result))
932n/a
933n/a parser.feed('<!DOCTYPE doc [\n')
934n/a parser.feed(' <!ENTITY test SYSTEM "whatever">\n')
935n/a parser.feed(']>\n')
936n/a parser.feed('<doc>&test;</doc>')
937n/a parser.close()
938n/a
939n/a self.assertEqual(result.getvalue(), start +
940n/a b"<doc><entity></entity></doc>")
941n/a
942n/a # ===== Attributes support
943n/a
944n/a class AttrGatherer(ContentHandler):
945n/a
946n/a def startElement(self, name, attrs):
947n/a self._attrs = attrs
948n/a
949n/a def startElementNS(self, name, qname, attrs):
950n/a self._attrs = attrs
951n/a
952n/a def test_expat_attrs_empty(self):
953n/a parser = create_parser()
954n/a gather = self.AttrGatherer()
955n/a parser.setContentHandler(gather)
956n/a
957n/a parser.feed("<doc/>")
958n/a parser.close()
959n/a
960n/a self.verify_empty_attrs(gather._attrs)
961n/a
962n/a def test_expat_attrs_wattr(self):
963n/a parser = create_parser()
964n/a gather = self.AttrGatherer()
965n/a parser.setContentHandler(gather)
966n/a
967n/a parser.feed("<doc attr='val'/>")
968n/a parser.close()
969n/a
970n/a self.verify_attrs_wattr(gather._attrs)
971n/a
972n/a def test_expat_nsattrs_empty(self):
973n/a parser = create_parser(1)
974n/a gather = self.AttrGatherer()
975n/a parser.setContentHandler(gather)
976n/a
977n/a parser.feed("<doc/>")
978n/a parser.close()
979n/a
980n/a self.verify_empty_nsattrs(gather._attrs)
981n/a
982n/a def test_expat_nsattrs_wattr(self):
983n/a parser = create_parser(1)
984n/a gather = self.AttrGatherer()
985n/a parser.setContentHandler(gather)
986n/a
987n/a parser.feed("<doc xmlns:ns='%s' ns:attr='val'/>" % ns_uri)
988n/a parser.close()
989n/a
990n/a attrs = gather._attrs
991n/a
992n/a self.assertEqual(attrs.getLength(), 1)
993n/a self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
994n/a self.assertTrue((attrs.getQNames() == [] or
995n/a attrs.getQNames() == ["ns:attr"]))
996n/a self.assertEqual(len(attrs), 1)
997n/a self.assertIn((ns_uri, "attr"), attrs)
998n/a self.assertEqual(attrs.get((ns_uri, "attr")), "val")
999n/a self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1000n/a self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1001n/a self.assertEqual(list(attrs.values()), ["val"])
1002n/a self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1003n/a self.assertEqual(attrs[(ns_uri, "attr")], "val")
1004n/a
1005n/a # ===== InputSource support
1006n/a
1007n/a def test_expat_inpsource_filename(self):
1008n/a parser = create_parser()
1009n/a result = BytesIO()
1010n/a xmlgen = XMLGenerator(result)
1011n/a
1012n/a parser.setContentHandler(xmlgen)
1013n/a parser.parse(TEST_XMLFILE)
1014n/a
1015n/a self.assertEqual(result.getvalue(), xml_test_out)
1016n/a
1017n/a def test_expat_inpsource_sysid(self):
1018n/a parser = create_parser()
1019n/a result = BytesIO()
1020n/a xmlgen = XMLGenerator(result)
1021n/a
1022n/a parser.setContentHandler(xmlgen)
1023n/a parser.parse(InputSource(TEST_XMLFILE))
1024n/a
1025n/a self.assertEqual(result.getvalue(), xml_test_out)
1026n/a
1027n/a @requires_nonascii_filenames
1028n/a def test_expat_inpsource_sysid_nonascii(self):
1029n/a fname = support.TESTFN_UNICODE
1030n/a shutil.copyfile(TEST_XMLFILE, fname)
1031n/a self.addCleanup(support.unlink, fname)
1032n/a
1033n/a parser = create_parser()
1034n/a result = BytesIO()
1035n/a xmlgen = XMLGenerator(result)
1036n/a
1037n/a parser.setContentHandler(xmlgen)
1038n/a parser.parse(InputSource(fname))
1039n/a
1040n/a self.assertEqual(result.getvalue(), xml_test_out)
1041n/a
1042n/a def test_expat_inpsource_byte_stream(self):
1043n/a parser = create_parser()
1044n/a result = BytesIO()
1045n/a xmlgen = XMLGenerator(result)
1046n/a
1047n/a parser.setContentHandler(xmlgen)
1048n/a inpsrc = InputSource()
1049n/a with open(TEST_XMLFILE, 'rb') as f:
1050n/a inpsrc.setByteStream(f)
1051n/a parser.parse(inpsrc)
1052n/a
1053n/a self.assertEqual(result.getvalue(), xml_test_out)
1054n/a
1055n/a def test_expat_inpsource_character_stream(self):
1056n/a parser = create_parser()
1057n/a result = BytesIO()
1058n/a xmlgen = XMLGenerator(result)
1059n/a
1060n/a parser.setContentHandler(xmlgen)
1061n/a inpsrc = InputSource()
1062n/a with open(TEST_XMLFILE, 'rt', encoding='iso-8859-1') as f:
1063n/a inpsrc.setCharacterStream(f)
1064n/a parser.parse(inpsrc)
1065n/a
1066n/a self.assertEqual(result.getvalue(), xml_test_out)
1067n/a
1068n/a # ===== IncrementalParser support
1069n/a
1070n/a def test_expat_incremental(self):
1071n/a result = BytesIO()
1072n/a xmlgen = XMLGenerator(result)
1073n/a parser = create_parser()
1074n/a parser.setContentHandler(xmlgen)
1075n/a
1076n/a parser.feed("<doc>")
1077n/a parser.feed("</doc>")
1078n/a parser.close()
1079n/a
1080n/a self.assertEqual(result.getvalue(), start + b"<doc></doc>")
1081n/a
1082n/a def test_expat_incremental_reset(self):
1083n/a result = BytesIO()
1084n/a xmlgen = XMLGenerator(result)
1085n/a parser = create_parser()
1086n/a parser.setContentHandler(xmlgen)
1087n/a
1088n/a parser.feed("<doc>")
1089n/a parser.feed("text")
1090n/a
1091n/a result = BytesIO()
1092n/a xmlgen = XMLGenerator(result)
1093n/a parser.setContentHandler(xmlgen)
1094n/a parser.reset()
1095n/a
1096n/a parser.feed("<doc>")
1097n/a parser.feed("text")
1098n/a parser.feed("</doc>")
1099n/a parser.close()
1100n/a
1101n/a self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
1102n/a
1103n/a # ===== Locator support
1104n/a
1105n/a def test_expat_locator_noinfo(self):
1106n/a result = BytesIO()
1107n/a xmlgen = XMLGenerator(result)
1108n/a parser = create_parser()
1109n/a parser.setContentHandler(xmlgen)
1110n/a
1111n/a parser.feed("<doc>")
1112n/a parser.feed("</doc>")
1113n/a parser.close()
1114n/a
1115n/a self.assertEqual(parser.getSystemId(), None)
1116n/a self.assertEqual(parser.getPublicId(), None)
1117n/a self.assertEqual(parser.getLineNumber(), 1)
1118n/a
1119n/a def test_expat_locator_withinfo(self):
1120n/a result = BytesIO()
1121n/a xmlgen = XMLGenerator(result)
1122n/a parser = create_parser()
1123n/a parser.setContentHandler(xmlgen)
1124n/a parser.parse(TEST_XMLFILE)
1125n/a
1126n/a self.assertEqual(parser.getSystemId(), TEST_XMLFILE)
1127n/a self.assertEqual(parser.getPublicId(), None)
1128n/a
1129n/a @requires_nonascii_filenames
1130n/a def test_expat_locator_withinfo_nonascii(self):
1131n/a fname = support.TESTFN_UNICODE
1132n/a shutil.copyfile(TEST_XMLFILE, fname)
1133n/a self.addCleanup(support.unlink, fname)
1134n/a
1135n/a result = BytesIO()
1136n/a xmlgen = XMLGenerator(result)
1137n/a parser = create_parser()
1138n/a parser.setContentHandler(xmlgen)
1139n/a parser.parse(fname)
1140n/a
1141n/a self.assertEqual(parser.getSystemId(), fname)
1142n/a self.assertEqual(parser.getPublicId(), None)
1143n/a
1144n/a
1145n/a# ===========================================================================
1146n/a#
1147n/a# error reporting
1148n/a#
1149n/a# ===========================================================================
1150n/a
1151n/aclass ErrorReportingTest(unittest.TestCase):
1152n/a def test_expat_inpsource_location(self):
1153n/a parser = create_parser()
1154n/a parser.setContentHandler(ContentHandler()) # do nothing
1155n/a source = InputSource()
1156n/a source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed
1157n/a name = "a file name"
1158n/a source.setSystemId(name)
1159n/a try:
1160n/a parser.parse(source)
1161n/a self.fail()
1162n/a except SAXException as e:
1163n/a self.assertEqual(e.getSystemId(), name)
1164n/a
1165n/a def test_expat_incomplete(self):
1166n/a parser = create_parser()
1167n/a parser.setContentHandler(ContentHandler()) # do nothing
1168n/a self.assertRaises(SAXParseException, parser.parse, StringIO("<foo>"))
1169n/a self.assertEqual(parser.getColumnNumber(), 5)
1170n/a self.assertEqual(parser.getLineNumber(), 1)
1171n/a
1172n/a def test_sax_parse_exception_str(self):
1173n/a # pass various values from a locator to the SAXParseException to
1174n/a # make sure that the __str__() doesn't fall apart when None is
1175n/a # passed instead of an integer line and column number
1176n/a #
1177n/a # use "normal" values for the locator:
1178n/a str(SAXParseException("message", None,
1179n/a self.DummyLocator(1, 1)))
1180n/a # use None for the line number:
1181n/a str(SAXParseException("message", None,
1182n/a self.DummyLocator(None, 1)))
1183n/a # use None for the column number:
1184n/a str(SAXParseException("message", None,
1185n/a self.DummyLocator(1, None)))
1186n/a # use None for both:
1187n/a str(SAXParseException("message", None,
1188n/a self.DummyLocator(None, None)))
1189n/a
1190n/a class DummyLocator:
1191n/a def __init__(self, lineno, colno):
1192n/a self._lineno = lineno
1193n/a self._colno = colno
1194n/a
1195n/a def getPublicId(self):
1196n/a return "pubid"
1197n/a
1198n/a def getSystemId(self):
1199n/a return "sysid"
1200n/a
1201n/a def getLineNumber(self):
1202n/a return self._lineno
1203n/a
1204n/a def getColumnNumber(self):
1205n/a return self._colno
1206n/a
1207n/a# ===========================================================================
1208n/a#
1209n/a# xmlreader tests
1210n/a#
1211n/a# ===========================================================================
1212n/a
1213n/aclass XmlReaderTest(XmlTestBase):
1214n/a
1215n/a # ===== AttributesImpl
1216n/a def test_attrs_empty(self):
1217n/a self.verify_empty_attrs(AttributesImpl({}))
1218n/a
1219n/a def test_attrs_wattr(self):
1220n/a self.verify_attrs_wattr(AttributesImpl({"attr" : "val"}))
1221n/a
1222n/a def test_nsattrs_empty(self):
1223n/a self.verify_empty_nsattrs(AttributesNSImpl({}, {}))
1224n/a
1225n/a def test_nsattrs_wattr(self):
1226n/a attrs = AttributesNSImpl({(ns_uri, "attr") : "val"},
1227n/a {(ns_uri, "attr") : "ns:attr"})
1228n/a
1229n/a self.assertEqual(attrs.getLength(), 1)
1230n/a self.assertEqual(attrs.getNames(), [(ns_uri, "attr")])
1231n/a self.assertEqual(attrs.getQNames(), ["ns:attr"])
1232n/a self.assertEqual(len(attrs), 1)
1233n/a self.assertIn((ns_uri, "attr"), attrs)
1234n/a self.assertEqual(list(attrs.keys()), [(ns_uri, "attr")])
1235n/a self.assertEqual(attrs.get((ns_uri, "attr")), "val")
1236n/a self.assertEqual(attrs.get((ns_uri, "attr"), 25), "val")
1237n/a self.assertEqual(list(attrs.items()), [((ns_uri, "attr"), "val")])
1238n/a self.assertEqual(list(attrs.values()), ["val"])
1239n/a self.assertEqual(attrs.getValue((ns_uri, "attr")), "val")
1240n/a self.assertEqual(attrs.getValueByQName("ns:attr"), "val")
1241n/a self.assertEqual(attrs.getNameByQName("ns:attr"), (ns_uri, "attr"))
1242n/a self.assertEqual(attrs[(ns_uri, "attr")], "val")
1243n/a self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr")
1244n/a
1245n/a
1246n/adef test_main():
1247n/a run_unittest(MakeParserTest,
1248n/a ParseTest,
1249n/a SaxutilsTest,
1250n/a PrepareInputSourceTest,
1251n/a StringXmlgenTest,
1252n/a BytesXmlgenTest,
1253n/a WriterXmlgenTest,
1254n/a StreamWriterXmlgenTest,
1255n/a StreamReaderWriterXmlgenTest,
1256n/a ExpatReaderTest,
1257n/a ErrorReportingTest,
1258n/a XmlReaderTest)
1259n/a
1260n/aif __name__ == "__main__":
1261n/a test_main()