ยปCore Development>Code coverage>Lib/test/test_pulldom.py

Python code coverage for Lib/test/test_pulldom.py

#countcontent
1n/aimport io
2n/aimport unittest
3n/aimport xml.sax
4n/a
5n/afrom xml.sax.xmlreader import AttributesImpl
6n/afrom xml.dom import pulldom
7n/a
8n/afrom test.support import findfile
9n/a
10n/a
11n/atstfile = findfile("test.xml", subdir="xmltestdata")
12n/a
13n/a# A handy XML snippet, containing attributes, a namespace prefix, and a
14n/a# self-closing tag:
15n/aSMALL_SAMPLE = """<?xml version="1.0"?>
16n/a<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xdc="http://www.xml.com/books">
17n/a<!-- A comment -->
18n/a<title>Introduction to XSL</title>
19n/a<hr/>
20n/a<p><xdc:author xdc:attrib="prefixed attribute" attrib="other attrib">A. Namespace</xdc:author></p>
21n/a</html>"""
22n/a
23n/a
24n/aclass PullDOMTestCase(unittest.TestCase):
25n/a
26n/a def test_parse(self):
27n/a """Minimal test of DOMEventStream.parse()"""
28n/a
29n/a # This just tests that parsing from a stream works. Actual parser
30n/a # semantics are tested using parseString with a more focused XML
31n/a # fragment.
32n/a
33n/a # Test with a filename:
34n/a handler = pulldom.parse(tstfile)
35n/a self.addCleanup(handler.stream.close)
36n/a list(handler)
37n/a
38n/a # Test with a file object:
39n/a with open(tstfile, "rb") as fin:
40n/a list(pulldom.parse(fin))
41n/a
42n/a def test_parse_semantics(self):
43n/a """Test DOMEventStream parsing semantics."""
44n/a
45n/a items = pulldom.parseString(SMALL_SAMPLE)
46n/a evt, node = next(items)
47n/a # Just check the node is a Document:
48n/a self.assertTrue(hasattr(node, "createElement"))
49n/a self.assertEqual(pulldom.START_DOCUMENT, evt)
50n/a evt, node = next(items)
51n/a self.assertEqual(pulldom.START_ELEMENT, evt)
52n/a self.assertEqual("html", node.tagName)
53n/a self.assertEqual(2, len(node.attributes))
54n/a self.assertEqual(node.attributes.getNamedItem("xmlns:xdc").value,
55n/a "http://www.xml.com/books")
56n/a evt, node = next(items)
57n/a self.assertEqual(pulldom.CHARACTERS, evt) # Line break
58n/a evt, node = next(items)
59n/a # XXX - A comment should be reported here!
60n/a # self.assertEqual(pulldom.COMMENT, evt)
61n/a # Line break after swallowed comment:
62n/a self.assertEqual(pulldom.CHARACTERS, evt)
63n/a evt, node = next(items)
64n/a self.assertEqual("title", node.tagName)
65n/a title_node = node
66n/a evt, node = next(items)
67n/a self.assertEqual(pulldom.CHARACTERS, evt)
68n/a self.assertEqual("Introduction to XSL", node.data)
69n/a evt, node = next(items)
70n/a self.assertEqual(pulldom.END_ELEMENT, evt)
71n/a self.assertEqual("title", node.tagName)
72n/a self.assertTrue(title_node is node)
73n/a evt, node = next(items)
74n/a self.assertEqual(pulldom.CHARACTERS, evt)
75n/a evt, node = next(items)
76n/a self.assertEqual(pulldom.START_ELEMENT, evt)
77n/a self.assertEqual("hr", node.tagName)
78n/a evt, node = next(items)
79n/a self.assertEqual(pulldom.END_ELEMENT, evt)
80n/a self.assertEqual("hr", node.tagName)
81n/a evt, node = next(items)
82n/a self.assertEqual(pulldom.CHARACTERS, evt)
83n/a evt, node = next(items)
84n/a self.assertEqual(pulldom.START_ELEMENT, evt)
85n/a self.assertEqual("p", node.tagName)
86n/a evt, node = next(items)
87n/a self.assertEqual(pulldom.START_ELEMENT, evt)
88n/a self.assertEqual("xdc:author", node.tagName)
89n/a evt, node = next(items)
90n/a self.assertEqual(pulldom.CHARACTERS, evt)
91n/a evt, node = next(items)
92n/a self.assertEqual(pulldom.END_ELEMENT, evt)
93n/a self.assertEqual("xdc:author", node.tagName)
94n/a evt, node = next(items)
95n/a self.assertEqual(pulldom.END_ELEMENT, evt)
96n/a evt, node = next(items)
97n/a self.assertEqual(pulldom.CHARACTERS, evt)
98n/a evt, node = next(items)
99n/a self.assertEqual(pulldom.END_ELEMENT, evt)
100n/a # XXX No END_DOCUMENT item is ever obtained:
101n/a #evt, node = next(items)
102n/a #self.assertEqual(pulldom.END_DOCUMENT, evt)
103n/a
104n/a def test_expandItem(self):
105n/a """Ensure expandItem works as expected."""
106n/a items = pulldom.parseString(SMALL_SAMPLE)
107n/a # Loop through the nodes until we get to a "title" start tag:
108n/a for evt, item in items:
109n/a if evt == pulldom.START_ELEMENT and item.tagName == "title":
110n/a items.expandNode(item)
111n/a self.assertEqual(1, len(item.childNodes))
112n/a break
113n/a else:
114n/a self.fail("No \"title\" element detected in SMALL_SAMPLE!")
115n/a # Loop until we get to the next start-element:
116n/a for evt, node in items:
117n/a if evt == pulldom.START_ELEMENT:
118n/a break
119n/a self.assertEqual("hr", node.tagName,
120n/a "expandNode did not leave DOMEventStream in the correct state.")
121n/a # Attempt to expand a standalone element:
122n/a items.expandNode(node)
123n/a self.assertEqual(next(items)[0], pulldom.CHARACTERS)
124n/a evt, node = next(items)
125n/a self.assertEqual(node.tagName, "p")
126n/a items.expandNode(node)
127n/a next(items) # Skip character data
128n/a evt, node = next(items)
129n/a self.assertEqual(node.tagName, "html")
130n/a with self.assertRaises(StopIteration):
131n/a next(items)
132n/a items.clear()
133n/a self.assertIsNone(items.parser)
134n/a self.assertIsNone(items.stream)
135n/a
136n/a @unittest.expectedFailure
137n/a def test_comment(self):
138n/a """PullDOM does not receive "comment" events."""
139n/a items = pulldom.parseString(SMALL_SAMPLE)
140n/a for evt, _ in items:
141n/a if evt == pulldom.COMMENT:
142n/a break
143n/a else:
144n/a self.fail("No comment was encountered")
145n/a
146n/a @unittest.expectedFailure
147n/a def test_end_document(self):
148n/a """PullDOM does not receive "end-document" events."""
149n/a items = pulldom.parseString(SMALL_SAMPLE)
150n/a # Read all of the nodes up to and including </html>:
151n/a for evt, node in items:
152n/a if evt == pulldom.END_ELEMENT and node.tagName == "html":
153n/a break
154n/a try:
155n/a # Assert that the next node is END_DOCUMENT:
156n/a evt, node = next(items)
157n/a self.assertEqual(pulldom.END_DOCUMENT, evt)
158n/a except StopIteration:
159n/a self.fail(
160n/a "Ran out of events, but should have received END_DOCUMENT")
161n/a
162n/a
163n/aclass ThoroughTestCase(unittest.TestCase):
164n/a """Test the hard-to-reach parts of pulldom."""
165n/a
166n/a def test_thorough_parse(self):
167n/a """Test some of the hard-to-reach parts of PullDOM."""
168n/a self._test_thorough(pulldom.parse(None, parser=SAXExerciser()))
169n/a
170n/a @unittest.expectedFailure
171n/a def test_sax2dom_fail(self):
172n/a """SAX2DOM can"t handle a PI before the root element."""
173n/a pd = SAX2DOMTestHelper(None, SAXExerciser(), 12)
174n/a self._test_thorough(pd)
175n/a
176n/a def test_thorough_sax2dom(self):
177n/a """Test some of the hard-to-reach parts of SAX2DOM."""
178n/a pd = SAX2DOMTestHelper(None, SAX2DOMExerciser(), 12)
179n/a self._test_thorough(pd, False)
180n/a
181n/a def _test_thorough(self, pd, before_root=True):
182n/a """Test some of the hard-to-reach parts of the parser, using a mock
183n/a parser."""
184n/a
185n/a evt, node = next(pd)
186n/a self.assertEqual(pulldom.START_DOCUMENT, evt)
187n/a # Just check the node is a Document:
188n/a self.assertTrue(hasattr(node, "createElement"))
189n/a
190n/a if before_root:
191n/a evt, node = next(pd)
192n/a self.assertEqual(pulldom.COMMENT, evt)
193n/a self.assertEqual("a comment", node.data)
194n/a evt, node = next(pd)
195n/a self.assertEqual(pulldom.PROCESSING_INSTRUCTION, evt)
196n/a self.assertEqual("target", node.target)
197n/a self.assertEqual("data", node.data)
198n/a
199n/a evt, node = next(pd)
200n/a self.assertEqual(pulldom.START_ELEMENT, evt)
201n/a self.assertEqual("html", node.tagName)
202n/a
203n/a evt, node = next(pd)
204n/a self.assertEqual(pulldom.COMMENT, evt)
205n/a self.assertEqual("a comment", node.data)
206n/a evt, node = next(pd)
207n/a self.assertEqual(pulldom.PROCESSING_INSTRUCTION, evt)
208n/a self.assertEqual("target", node.target)
209n/a self.assertEqual("data", node.data)
210n/a
211n/a evt, node = next(pd)
212n/a self.assertEqual(pulldom.START_ELEMENT, evt)
213n/a self.assertEqual("p", node.tagName)
214n/a
215n/a evt, node = next(pd)
216n/a self.assertEqual(pulldom.CHARACTERS, evt)
217n/a self.assertEqual("text", node.data)
218n/a evt, node = next(pd)
219n/a self.assertEqual(pulldom.END_ELEMENT, evt)
220n/a self.assertEqual("p", node.tagName)
221n/a evt, node = next(pd)
222n/a self.assertEqual(pulldom.END_ELEMENT, evt)
223n/a self.assertEqual("html", node.tagName)
224n/a evt, node = next(pd)
225n/a self.assertEqual(pulldom.END_DOCUMENT, evt)
226n/a
227n/a
228n/aclass SAXExerciser(object):
229n/a """A fake sax parser that calls some of the harder-to-reach sax methods to
230n/a ensure it emits the correct events"""
231n/a
232n/a def setContentHandler(self, handler):
233n/a self._handler = handler
234n/a
235n/a def parse(self, _):
236n/a h = self._handler
237n/a h.startDocument()
238n/a
239n/a # The next two items ensure that items preceding the first
240n/a # start_element are properly stored and emitted:
241n/a h.comment("a comment")
242n/a h.processingInstruction("target", "data")
243n/a
244n/a h.startElement("html", AttributesImpl({}))
245n/a
246n/a h.comment("a comment")
247n/a h.processingInstruction("target", "data")
248n/a
249n/a h.startElement("p", AttributesImpl({"class": "paraclass"}))
250n/a h.characters("text")
251n/a h.endElement("p")
252n/a h.endElement("html")
253n/a h.endDocument()
254n/a
255n/a def stub(self, *args, **kwargs):
256n/a """Stub method. Does nothing."""
257n/a pass
258n/a setProperty = stub
259n/a setFeature = stub
260n/a
261n/a
262n/aclass SAX2DOMExerciser(SAXExerciser):
263n/a """The same as SAXExerciser, but without the processing instruction and
264n/a comment before the root element, because S2D can"t handle it"""
265n/a
266n/a def parse(self, _):
267n/a h = self._handler
268n/a h.startDocument()
269n/a h.startElement("html", AttributesImpl({}))
270n/a h.comment("a comment")
271n/a h.processingInstruction("target", "data")
272n/a h.startElement("p", AttributesImpl({"class": "paraclass"}))
273n/a h.characters("text")
274n/a h.endElement("p")
275n/a h.endElement("html")
276n/a h.endDocument()
277n/a
278n/a
279n/aclass SAX2DOMTestHelper(pulldom.DOMEventStream):
280n/a """Allows us to drive SAX2DOM from a DOMEventStream."""
281n/a
282n/a def reset(self):
283n/a self.pulldom = pulldom.SAX2DOM()
284n/a # This content handler relies on namespace support
285n/a self.parser.setFeature(xml.sax.handler.feature_namespaces, 1)
286n/a self.parser.setContentHandler(self.pulldom)
287n/a
288n/a
289n/aclass SAX2DOMTestCase(unittest.TestCase):
290n/a
291n/a def confirm(self, test, testname="Test"):
292n/a self.assertTrue(test, testname)
293n/a
294n/a def test_basic(self):
295n/a """Ensure SAX2DOM can parse from a stream."""
296n/a with io.StringIO(SMALL_SAMPLE) as fin:
297n/a sd = SAX2DOMTestHelper(fin, xml.sax.make_parser(),
298n/a len(SMALL_SAMPLE))
299n/a for evt, node in sd:
300n/a if evt == pulldom.START_ELEMENT and node.tagName == "html":
301n/a break
302n/a # Because the buffer is the same length as the XML, all the
303n/a # nodes should have been parsed and added:
304n/a self.assertGreater(len(node.childNodes), 0)
305n/a
306n/a def testSAX2DOM(self):
307n/a """Ensure SAX2DOM expands nodes as expected."""
308n/a sax2dom = pulldom.SAX2DOM()
309n/a sax2dom.startDocument()
310n/a sax2dom.startElement("doc", {})
311n/a sax2dom.characters("text")
312n/a sax2dom.startElement("subelm", {})
313n/a sax2dom.characters("text")
314n/a sax2dom.endElement("subelm")
315n/a sax2dom.characters("text")
316n/a sax2dom.endElement("doc")
317n/a sax2dom.endDocument()
318n/a
319n/a doc = sax2dom.document
320n/a root = doc.documentElement
321n/a (text1, elm1, text2) = root.childNodes
322n/a text3 = elm1.childNodes[0]
323n/a
324n/a self.assertIsNone(text1.previousSibling)
325n/a self.assertIs(text1.nextSibling, elm1)
326n/a self.assertIs(elm1.previousSibling, text1)
327n/a self.assertIs(elm1.nextSibling, text2)
328n/a self.assertIs(text2.previousSibling, elm1)
329n/a self.assertIsNone(text2.nextSibling)
330n/a self.assertIsNone(text3.previousSibling)
331n/a self.assertIsNone(text3.nextSibling)
332n/a
333n/a self.assertIs(root.parentNode, doc)
334n/a self.assertIs(text1.parentNode, root)
335n/a self.assertIs(elm1.parentNode, root)
336n/a self.assertIs(text2.parentNode, root)
337n/a self.assertIs(text3.parentNode, elm1)
338n/a doc.unlink()
339n/a
340n/a
341n/aif __name__ == "__main__":
342n/a unittest.main()