# IMPORTANT: the same tests are run from "test_xml_etree_c" in order
# to ensure consistency between the C implementation and the Python
# implementation.
#
# For this purpose, the module-level "ET" symbol is temporarily
# monkey-patched when running the "test_xml_etree_c" test suite.
import copy
import functools
import html
import io
import itertools
import locale
import operator
import os
import pickle
import sys
import textwrap
import types
import unittest
import warnings
import weakref
from functools import partial
from itertools import product, islice
from test import support
from test.support import TESTFN, findfile, import_fresh_module, gc_collect, swap_attr
# pyET is the pure-Python implementation.
#
# ET is pyET in test_xml_etree and is the C accelerated version in
# test_xml_etree_c.
pyET = None
ET = None
SIMPLE_XMLFILE = findfile("simple.xml", subdir="xmltestdata")
try:
    SIMPLE_XMLFILE.encode("utf-8")
except UnicodeEncodeError:
    raise unittest.SkipTest("filename is not encodable to utf8")
SIMPLE_NS_XMLFILE = findfile("simple-ns.xml", subdir="xmltestdata")
UTF8_BUG_XMLFILE = findfile("expat224_utf8_bug.xml", subdir="xmltestdata")
SAMPLE_XML = """\
  text 
  text 
  
  
    Apples 
    Bananas 
   
 
  African Coffee Table 
  80 
  120 
 
 
"""
ENTITY_XML = """\
%user-entities;
]>
&entity; 
"""
EXTERNAL_ENTITY_XML = """\
]>
&entity; 
"""
def checkwarnings(*filters, quiet=False):
    def decorator(test):
        def newtest(*args, **kwargs):
            with support.check_warnings(*filters, quiet=quiet):
                test(*args, **kwargs)
        functools.update_wrapper(newtest, test)
        return newtest
    return decorator
class ModuleTest(unittest.TestCase):
    def test_sanity(self):
        # Import sanity.
        from xml.etree import ElementTree
        from xml.etree import ElementInclude
        from xml.etree import ElementPath
    def test_all(self):
        names = ("xml.etree.ElementTree", "_elementtree")
        support.check__all__(self, ET, names, blacklist=("HTML_EMPTY",))
def serialize(elem, to_string=True, encoding='unicode', **options):
    if encoding != 'unicode':
        file = io.BytesIO()
    else:
        file = io.StringIO()
    tree = ET.ElementTree(elem)
    tree.write(file, encoding=encoding, **options)
    if to_string:
        return file.getvalue()
    else:
        file.seek(0)
        return file
def summarize_list(seq):
    return [elem.tag for elem in seq]
class ElementTestCase:
    @classmethod
    def setUpClass(cls):
        cls.modules = {pyET, ET}
    def pickleRoundTrip(self, obj, name, dumper, loader, proto):
        save_m = sys.modules[name]
        try:
            sys.modules[name] = dumper
            temp = pickle.dumps(obj, proto)
            sys.modules[name] = loader
            result = pickle.loads(temp)
        except pickle.PicklingError as pe:
            # pyET must be second, because pyET may be (equal to) ET.
            human = dict([(ET, "cET"), (pyET, "pyET")])
            raise support.TestFailed("Failed to round-trip %r from %r to %r"
                                     % (obj,
                                        human.get(dumper, dumper),
                                        human.get(loader, loader))) from pe
        finally:
            sys.modules[name] = save_m
        return result
    def assertEqualElements(self, alice, bob):
        self.assertIsInstance(alice, (ET.Element, pyET.Element))
        self.assertIsInstance(bob, (ET.Element, pyET.Element))
        self.assertEqual(len(list(alice)), len(list(bob)))
        for x, y in zip(alice, bob):
            self.assertEqualElements(x, y)
        properties = operator.attrgetter('tag', 'tail', 'text', 'attrib')
        self.assertEqual(properties(alice), properties(bob))
# --------------------------------------------------------------------
# element tree tests
class ElementTreeTest(unittest.TestCase):
    def serialize_check(self, elem, expected):
        self.assertEqual(serialize(elem), expected)
    def test_interface(self):
        # Test element tree interface.
        def check_string(string):
            len(string)
            for char in string:
                self.assertEqual(len(char), 1,
                        msg="expected one-character string, got %r" % char)
            new_string = string + ""
            new_string = string + " "
            string[:0]
        def check_mapping(mapping):
            len(mapping)
            keys = mapping.keys()
            items = mapping.items()
            for key in keys:
                item = mapping[key]
            mapping["key"] = "value"
            self.assertEqual(mapping["key"], "value",
                    msg="expected value string, got %r" % mapping["key"])
        def check_element(element):
            self.assertTrue(ET.iselement(element), msg="not an element")
            direlem = dir(element)
            for attr in 'tag', 'attrib', 'text', 'tail':
                self.assertTrue(hasattr(element, attr),
                        msg='no %s member' % attr)
                self.assertIn(attr, direlem,
                        msg='no %s visible by dir' % attr)
            check_string(element.tag)
            check_mapping(element.attrib)
            if element.text is not None:
                check_string(element.text)
            if element.tail is not None:
                check_string(element.tail)
            for elem in element:
                check_element(elem)
        element = ET.Element("tag")
        check_element(element)
        tree = ET.ElementTree(element)
        check_element(tree.getroot())
        element = ET.Element("t\xe4g", key="value")
        tree = ET.ElementTree(element)
        self.assertRegex(repr(element), r"^$")
        element = ET.Element("tag", key="value")
        # Make sure all standard element methods exist.
        def check_method(method):
            self.assertTrue(hasattr(method, '__call__'),
                    msg="%s not callable" % method)
        check_method(element.append)
        check_method(element.extend)
        check_method(element.insert)
        check_method(element.remove)
        check_method(element.getchildren)
        check_method(element.find)
        check_method(element.iterfind)
        check_method(element.findall)
        check_method(element.findtext)
        check_method(element.clear)
        check_method(element.get)
        check_method(element.set)
        check_method(element.keys)
        check_method(element.items)
        check_method(element.iter)
        check_method(element.itertext)
        check_method(element.getiterator)
        # These methods return an iterable. See bug 6472.
        def check_iter(it):
            check_method(it.__next__)
        check_iter(element.iterfind("tag"))
        check_iter(element.iterfind("*"))
        check_iter(tree.iterfind("tag"))
        check_iter(tree.iterfind("*"))
        # These aliases are provided:
        self.assertEqual(ET.XML, ET.fromstring)
        self.assertEqual(ET.PI, ET.ProcessingInstruction)
    def test_set_attribute(self):
        element = ET.Element('tag')
        self.assertEqual(element.tag, 'tag')
        element.tag = 'Tag'
        self.assertEqual(element.tag, 'Tag')
        element.tag = 'TAG'
        self.assertEqual(element.tag, 'TAG')
        self.assertIsNone(element.text)
        element.text = 'Text'
        self.assertEqual(element.text, 'Text')
        element.text = 'TEXT'
        self.assertEqual(element.text, 'TEXT')
        self.assertIsNone(element.tail)
        element.tail = 'Tail'
        self.assertEqual(element.tail, 'Tail')
        element.tail = 'TAIL'
        self.assertEqual(element.tail, 'TAIL')
        self.assertEqual(element.attrib, {})
        element.attrib = {'a': 'b', 'c': 'd'}
        self.assertEqual(element.attrib, {'a': 'b', 'c': 'd'})
        element.attrib = {'A': 'B', 'C': 'D'}
        self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'})
    def test_simpleops(self):
        # Basic method sanity checks.
        elem = ET.XML("hello "),
                'hello ')
        self.serialize_check(ET.XML("hello "),
                'hello ')
        self.serialize_check(ET.XML("hello ')
    def test_file_init(self):
        stringfile = io.BytesIO(SAMPLE_XML.encode("utf-8"))
        tree = ET.ElementTree(file=stringfile)
        self.assertEqual(tree.find("tag").tag, 'tag')
        self.assertEqual(tree.find("section/tag").tag, 'tag')
        tree = ET.ElementTree(file=SIMPLE_XMLFILE)
        self.assertEqual(tree.find("element").tag, 'element')
        self.assertEqual(tree.find("element/../empty-element").tag,
                'empty-element')
    def test_path_cache(self):
        # Check that the path cache behaves sanely.
        from xml.etree import ElementPath
        elem = ET.XML(SAMPLE_XML)
        for i in range(10): ET.ElementTree(elem).find('./'+str(i))
        cache_len_10 = len(ElementPath._cache)
        for i in range(10): ET.ElementTree(elem).find('./'+str(i))
        self.assertEqual(len(ElementPath._cache), cache_len_10)
        for i in range(20): ET.ElementTree(elem).find('./'+str(i))
        self.assertGreater(len(ElementPath._cache), cache_len_10)
        for i in range(600): ET.ElementTree(elem).find('./'+str(i))
        self.assertLess(len(ElementPath._cache), 500)
    def test_copy(self):
        # Test copy handling (etc).
        import copy
        e1 = ET.XML("hello ")
        e2 = copy.copy(e1)
        e3 = copy.deepcopy(e1)
        e1.find("foo").tag = "bar"
        self.serialize_check(e1, 'hello ')
        self.serialize_check(e2, 'hello ')
        self.serialize_check(e3, 'hello ')
    def test_attrib(self):
        # Test attribute handling.
        elem = ET.Element("tag")
        elem.get("key") # 1.1
        self.assertEqual(elem.get("key", "default"), 'default') # 1.2
        elem.set("key", "value")
        self.assertEqual(elem.get("key"), 'value') # 1.3
        elem = ET.Element("tag", key="value")
        self.assertEqual(elem.get("key"), 'value') # 2.1
        self.assertEqual(elem.attrib, {'key': 'value'}) # 2.2
        attrib = {"key": "value"}
        elem = ET.Element("tag", attrib)
        attrib.clear() # check for aliasing issues
        self.assertEqual(elem.get("key"), 'value') # 3.1
        self.assertEqual(elem.attrib, {'key': 'value'}) # 3.2
        attrib = {"key": "value"}
        elem = ET.Element("tag", **attrib)
        attrib.clear() # check for aliasing issues
        self.assertEqual(elem.get("key"), 'value') # 4.1
        self.assertEqual(elem.attrib, {'key': 'value'}) # 4.2
        elem = ET.Element("tag", {"key": "other"}, key="value")
        self.assertEqual(elem.get("key"), 'value') # 5.1
        self.assertEqual(elem.attrib, {'key': 'value'}) # 5.2
        elem = ET.Element('test')
        elem.text = "aa"
        elem.set('testa', 'testval')
        elem.set('testb', 'test2')
        self.assertEqual(ET.tostring(elem),
                b'aa ')
        self.assertEqual(sorted(elem.keys()), ['testa', 'testb'])
        self.assertEqual(sorted(elem.items()),
                [('testa', 'testval'), ('testb', 'test2')])
        self.assertEqual(elem.attrib['testb'], 'test2')
        elem.attrib['testb'] = 'test1'
        elem.attrib['testc'] = 'test2'
        self.assertEqual(ET.tostring(elem),
                b'aa ')
        elem = ET.Element('test')
        elem.set('a', '\r')
        elem.set('b', '\r\n')
        elem.set('c', '\t\n\r ')
        elem.set('d', '\n\n')
        self.assertEqual(ET.tostring(elem),
                b'\n'
                '   text \n'
                '   text tail\n'
                '    ')
        tree = ET.parse(SIMPLE_NS_XMLFILE)
        stream = io.StringIO()
        tree.write(stream, encoding='unicode')
        self.assertEqual(stream.getvalue(),
                '\n'
                '   text \n'
                '   text tail\n'
                '    ')
        with open(SIMPLE_XMLFILE) as f:
            data = f.read()
        parser = ET.XMLParser()
        self.assertRegex(parser.version, r'^Expat ')
        parser.feed(data)
        self.serialize_check(parser.close(),
                '\n'
                '   text \n'
                '   text tail\n'
                '    ')
        target = ET.TreeBuilder()
        parser = ET.XMLParser(target=target)
        parser.feed(data)
        self.serialize_check(parser.close(),
                '\n'
                '   text \n'
                '   text tail\n'
                '    ')
    def test_parseliteral(self):
        element = ET.XML("text")
        self.assertEqual(ET.tostring(element, encoding='unicode'),
                'text')
        element = ET.fromstring("text")
        self.assertEqual(ET.tostring(element, encoding='unicode'),
                'text')
        sequence = ["", "text"]
        element = ET.fromstringlist(sequence)
        self.assertEqual(ET.tostring(element),
                b'text')
        self.assertEqual(b"".join(ET.tostringlist(element)),
                b'text')
        self.assertEqual(ET.tostring(element, "ascii"),
                b"\n"
                b"text")
        _, ids = ET.XMLID("text")
        self.assertEqual(len(ids), 0)
        _, ids = ET.XMLID("text")
        self.assertEqual(len(ids), 1)
        self.assertEqual(ids["body"].tag, 'body')
    def test_iterparse(self):
        # Test iterparse interface.
        iterparse = ET.iterparse
        context = iterparse(SIMPLE_XMLFILE)
        action, elem = next(context)
        self.assertEqual((action, elem.tag), ('end', 'element'))
        self.assertEqual([(action, elem.tag) for action, elem in context], [
                ('end', 'element'),
                ('end', 'empty-element'),
                ('end', 'root'),
            ])
        self.assertEqual(context.root.tag, 'root')
        context = iterparse(SIMPLE_NS_XMLFILE)
        self.assertEqual([(action, elem.tag) for action, elem in context], [
                ('end', '{namespace}element'),
                ('end', '{namespace}element'),
                ('end', '{namespace}empty-element'),
                ('end', '{namespace}root'),
            ])
        events = ()
        context = iterparse(SIMPLE_XMLFILE, events)
        self.assertEqual([(action, elem.tag) for action, elem in context], [])
        events = ()
        context = iterparse(SIMPLE_XMLFILE, events=events)
        self.assertEqual([(action, elem.tag) for action, elem in context], [])
        events = ("start", "end")
        context = iterparse(SIMPLE_XMLFILE, events)
        self.assertEqual([(action, elem.tag) for action, elem in context], [
                ('start', 'root'),
                ('start', 'element'),
                ('end', 'element'),
                ('start', 'element'),
                ('end', 'element'),
                ('start', 'empty-element'),
                ('end', 'empty-element'),
                ('end', 'root'),
            ])
        events = ("start", "end", "start-ns", "end-ns")
        context = iterparse(SIMPLE_NS_XMLFILE, events)
        self.assertEqual([(action, elem.tag) if action in ("start", "end")
                                             else (action, elem)
                          for action, elem in context], [
                ('start-ns', ('', 'namespace')),
                ('start', '{namespace}root'),
                ('start', '{namespace}element'),
                ('end', '{namespace}element'),
                ('start', '{namespace}element'),
                ('end', '{namespace}element'),
                ('start', '{namespace}empty-element'),
                ('end', '{namespace}empty-element'),
                ('end', '{namespace}root'),
                ('end-ns', None),
            ])
        events = ('start-ns', 'end-ns')
        context = iterparse(io.StringIO(r"text ')
        ET.SubElement(elem, "subtag").text = "subtext"
        self.serialize_check(elem, 'textsubtext  ')
        # Test tag suppression
        elem.tag = None
        self.serialize_check(elem, 'textsubtext ')
        elem.insert(0, ET.Comment("comment"))
        self.serialize_check(elem,
                'textsubtext ')     # assumes 1.3
        elem[0] = ET.PI("key", "value")
        self.serialize_check(elem, 'textsubtext ')
    def test_custom_builder(self):
        # Test parser w. custom builder.
        with open(SIMPLE_XMLFILE) as f:
            data = f.read()
        class Builder(list):
            def start(self, tag, attrib):
                self.append(("start", tag))
            def end(self, tag):
                self.append(("end", tag))
            def data(self, text):
                pass
        builder = Builder()
        parser = ET.XMLParser(target=builder)
        parser.feed(data)
        self.assertEqual(builder, [
                ('start', 'root'),
                ('start', 'element'),
                ('end', 'element'),
                ('start', 'element'),
                ('end', 'element'),
                ('start', 'empty-element'),
                ('end', 'empty-element'),
                ('end', 'root'),
            ])
        with open(SIMPLE_NS_XMLFILE) as f:
            data = f.read()
        class Builder(list):
            def start(self, tag, attrib):
                self.append(("start", tag))
            def end(self, tag):
                self.append(("end", tag))
            def data(self, text):
                pass
            def pi(self, target, data):
                self.append(("pi", target, data))
            def comment(self, data):
                self.append(("comment", data))
            def start_ns(self, prefix, uri):
                self.append(("start-ns", prefix, uri))
            def end_ns(self, prefix):
                self.append(("end-ns", prefix))
        builder = Builder()
        parser = ET.XMLParser(target=builder)
        parser.feed(data)
        self.assertEqual(builder, [
                ('pi', 'pi', 'data'),
                ('comment', ' comment '),
                ('start-ns', '', 'namespace'),
                ('start', '{namespace}root'),
                ('start', '{namespace}element'),
                ('end', '{namespace}element'),
                ('start', '{namespace}element'),
                ('end', '{namespace}element'),
                ('start', '{namespace}empty-element'),
                ('end', '{namespace}empty-element'),
                ('end', '{namespace}root'),
                ('end-ns', ''),
            ])
    def test_custom_builder_only_end_ns(self):
        class Builder(list):
            def end_ns(self, prefix):
                self.append(("end-ns", prefix))
        builder = Builder()
        parser = ET.XMLParser(target=builder)
        parser.feed(textwrap.dedent("""\
            
            
            
               text 
               text tail
                
            """))
        self.assertEqual(builder, [
                ('end-ns', 'a'),
                ('end-ns', 'p'),
                ('end-ns', ''),
            ])
    # Element.getchildren() and ElementTree.getiterator() are deprecated.
    @checkwarnings(("This method will be removed in future versions.  "
                    "Use .+ instead.",
                    DeprecationWarning))
    def test_getchildren(self):
        # Test Element.getchildren()
        with open(SIMPLE_XMLFILE, "rb") as f:
            tree = ET.parse(f)
        self.assertEqual([summarize_list(elem.getchildren())
                          for elem in tree.getroot().iter()], [
                ['element', 'element', 'empty-element'],
                [],
                [],
                [],
            ])
        self.assertEqual([summarize_list(elem.getchildren())
                          for elem in tree.getiterator()], [
                ['element', 'element', 'empty-element'],
                [],
                [],
                [],
            ])
        elem = ET.XML(SAMPLE_XML)
        self.assertEqual(len(elem.getchildren()), 3)
        self.assertEqual(len(elem[2].getchildren()), 1)
        self.assertEqual(elem[:], elem.getchildren())
        child1 = elem[0]
        child2 = elem[2]
        del elem[1:2]
        self.assertEqual(len(elem.getchildren()), 2)
        self.assertEqual(child1, elem[0])
        self.assertEqual(child2, elem[1])
        elem[0:2] = [child2, child1]
        self.assertEqual(child2, elem[0])
        self.assertEqual(child1, elem[1])
        self.assertNotEqual(child1, elem[0])
        elem.clear()
        self.assertEqual(elem.getchildren(), [])
    def test_writestring(self):
        elem = ET.XML("text")
        self.assertEqual(ET.tostring(elem), b'text')
        elem = ET.fromstring("text")
        self.assertEqual(ET.tostring(elem), b'text')
    def test_tostring_default_namespace(self):
        elem = ET.XML('ø ')
        preferredencoding = locale.getpreferredencoding()
        TESTCASES = [
        #   (expected_retval,                  encoding, xml_declaration)
            # ... xml_declaration = None
            (b'ø ', None, None),
            (b'\xc3\xb8 ', 'UTF-8', None),
            (b'ø ', 'US-ASCII', None),
            (b"\n"
             b"\xf8 ", 'ISO-8859-1', None),
            ('ø ', 'unicode', None),
            # ... xml_declaration = False
            (b"ø ", None, False),
            (b"\xc3\xb8 ", 'UTF-8', False),
            (b"ø ", 'US-ASCII', False),
            (b"\xf8 ", 'ISO-8859-1', False),
            ("ø ", 'unicode', False),
            # ... xml_declaration = True
            (b"\n"
             b"ø ", None, True),
            (b"\n"
             b"\xc3\xb8 ", 'UTF-8', True),
            (b"\n"
             b"ø ", 'US-ASCII', True),
            (b"\n"
             b"\xf8 ", 'ISO-8859-1', True),
            (f"\n"
             "ø ", 'unicode', True),
        ]
        for expected_retval, encoding, xml_declaration in TESTCASES:
            with self.subTest(f'encoding={encoding} '
                              f'xml_declaration={xml_declaration}'):
                self.assertEqual(
                    ET.tostring(
                        elem,
                        encoding=encoding,
                        xml_declaration=xml_declaration
                    ),
                    expected_retval
                )
    def test_tostringlist_default_namespace(self):
        elem = ET.XML('%s " %
                   (encoding, body))
            self.assertEqual(ET.XML(xml.encode(encoding)).text, body)
            self.assertEqual(ET.XML(xml).text, body)
        check("ascii", 'a')
        check("us-ascii", 'a')
        check("iso-8859-1", '\xbd')
        check("iso-8859-15", '\u20ac')
        check("cp437", '\u221a')
        check("mac-roman", '\u02da')
        def xml(encoding):
            return "text ')
        self.assertEqual(serialize(e),
                'text ')
        self.assertEqual(serialize(e, method="html"),
                'text ')
    def test_entity(self):
        # Test entity handling.
        # 1) good entities
        e = ET.XML("test ")
        self.assertEqual(serialize(e, encoding="us-ascii"),
                b'test ')
        self.serialize_check(e, 'test ')
        # 2) bad entities
        with self.assertRaises(ET.ParseError) as cm:
            ET.XML("&entity; ")
        self.assertEqual(str(cm.exception),
                'undefined entity: line 1, column 10')
        with self.assertRaises(ET.ParseError) as cm:
            ET.XML(ENTITY_XML)
        self.assertEqual(str(cm.exception),
                'undefined entity &entity;: line 5, column 10')
        # 3) custom entity
        parser = ET.XMLParser()
        parser.entity["entity"] = "text"
        parser.feed(ENTITY_XML)
        root = parser.close()
        self.serialize_check(root, 'text ')
        # 4) external (SYSTEM) entity
        with self.assertRaises(ET.ParseError) as cm:
            ET.XML(EXTERNAL_ENTITY_XML)
        self.assertEqual(str(cm.exception),
                'undefined entity &entity;: line 4, column 10')
    def test_namespace(self):
        # Test namespace issues.
        # 1) xml namespace
        elem = ET.XML("\n'
            '  text \n'
            '  \n'
            '    subtext \n'
            '   \n'
            ' ')
    def test_qname(self):
        # Test QName handling.
        # 1) decorated tags
        elem = ET.Element("{uri}tag")
        self.serialize_check(elem, ''
            ' ') # 3.3
        # 4) Direct QName tests
        self.assertEqual(str(ET.QName('ns', 'tag')), '{ns}tag')
        self.assertEqual(str(ET.QName('{ns}tag')), '{ns}tag')
        q1 = ET.QName('ns', 'tag')
        q2 = ET.QName('ns', 'tag')
        self.assertEqual(q1, q2)
        q2 = ET.QName('ns', 'other-tag')
        self.assertNotEqual(q1, q2)
        self.assertNotEqual(q1, 'ns:tag')
        self.assertEqual(q1, '{ns}tag')
    def test_doctype_public(self):
        # Test PUBLIC doctype.
        elem = ET.XML(''
                'text')
    def test_xpath_tokenizer(self):
        # Test the XPath tokenizer.
        from xml.etree import ElementPath
        def check(p, expected, namespaces=None):
            self.assertEqual([op or tag
                              for op, tag in ElementPath.xpath_tokenizer(p, namespaces)],
                             expected)
        # tests from the xml specification
        check("*", ['*'])
        check("text()", ['text', '()'])
        check("@name", ['@', 'name'])
        check("@*", ['@', '*'])
        check("para[1]", ['para', '[', '1', ']'])
        check("para[last()]", ['para', '[', 'last', '()', ']'])
        check("*/para", ['*', '/', 'para'])
        check("/doc/chapter[5]/section[2]",
              ['/', 'doc', '/', 'chapter', '[', '5', ']',
               '/', 'section', '[', '2', ']'])
        check("chapter//para", ['chapter', '//', 'para'])
        check("//para", ['//', 'para'])
        check("//olist/item", ['//', 'olist', '/', 'item'])
        check(".", ['.'])
        check(".//para", ['.', '//', 'para'])
        check("..", ['..'])
        check("../@lang", ['..', '/', '@', 'lang'])
        check("chapter[title]", ['chapter', '[', 'title', ']'])
        check("employee[@secretary and @assistant]", ['employee',
              '[', '@', 'secretary', '', 'and', '', '@', 'assistant', ']'])
        # additional tests
        check("@{ns}attr", ['@', '{ns}attr'])
        check("{http://spam}egg", ['{http://spam}egg'])
        check("./spam.egg", ['.', '/', 'spam.egg'])
        check(".//{http://spam}egg", ['.', '//', '{http://spam}egg'])
        # wildcard tags
        check("{ns}*", ['{ns}*'])
        check("{}*", ['{}*'])
        check("{*}tag", ['{*}tag'])
        check("{*}*", ['{*}*'])
        check(".//{*}tag", ['.', '//', '{*}tag'])
        # namespace prefix resolution
        check("./xsd:type", ['.', '/', '{http://www.w3.org/2001/XMLSchema}type'],
              {'xsd': 'http://www.w3.org/2001/XMLSchema'})
        check("type", ['{http://www.w3.org/2001/XMLSchema}type'],
              {'': 'http://www.w3.org/2001/XMLSchema'})
        check("@xsd:type", ['@', '{http://www.w3.org/2001/XMLSchema}type'],
              {'xsd': 'http://www.w3.org/2001/XMLSchema'})
        check("@type", ['@', 'type'],
              {'': 'http://www.w3.org/2001/XMLSchema'})
        check("@{*}type", ['@', '{*}type'],
              {'': 'http://www.w3.org/2001/XMLSchema'})
        check("@{ns}attr", ['@', '{ns}attr'],
              {'': 'http://www.w3.org/2001/XMLSchema',
               'ns': 'http://www.w3.org/2001/XMLSchema'})
    def test_processinginstruction(self):
        # Test ProcessingInstruction directly
        self.assertEqual(ET.tostring(ET.ProcessingInstruction('test', 'instruction')),
                b'')
        self.assertEqual(ET.tostring(ET.PI('test', 'instruction')),
                b'')
        # Issue #2746
        self.assertEqual(ET.tostring(ET.PI('test', '')),
                b'?>')
        self.assertEqual(ET.tostring(ET.PI('test', '\xe3'), 'latin-1'),
                b"\n"
                b"\xe3?>")
    def test_html_empty_elems_serialization(self):
        # issue 15970
        # from http://www.w3.org/TR/html401/index/elements.html
        for element in ['AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME', 'HR',
                        'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM']:
            for elem in [element, element.lower()]:
                expected = '<%s>' % elem
                serialized = serialize(ET.XML('<%s />' % elem), method='html')
                self.assertEqual(serialized, expected)
                serialized = serialize(ET.XML('<%s>%s>' % (elem,elem)),
                                       method='html')
                self.assertEqual(serialized, expected)
    def test_dump_attribute_order(self):
        # See BPO 34160
        e = ET.Element('cirriculum', status='public', company='example')
        with support.captured_stdout() as stdout:
            ET.dump(e)
        self.assertEqual(stdout.getvalue(),
                         '\n  text \n", chunk_size)
                self.assert_event_tags(parser, [('end', 'element')])
                self._feed(parser, "text tail\n", chunk_size)
                self._feed(parser, " \n", chunk_size)
                self.assert_event_tags(parser, [('end', 'root')])
                self.assertIsNone(parser.close())
    def test_feed_while_iterating(self):
        parser = ET.XMLPullParser()
        it = parser.read_events()
        self._feed(parser, "\n  text \n")
        action, elem = next(it)
        self.assertEqual((action, elem.tag), ('end', 'element'))
        self._feed(parser, " \n")
        action, elem = next(it)
        self.assertEqual((action, elem.tag), ('end', 'root'))
        with self.assertRaises(StopIteration):
            next(it)
    def test_simple_xml_with_ns(self):
        parser = ET.XMLPullParser()
        self.assert_event_tags(parser, [])
        self._feed(parser, "\n")
        self.assert_event_tags(parser, [])
        self._feed(parser, "\n")
        self.assert_event_tags(parser, [])
        self._feed(parser, "text \n")
        self.assert_event_tags(parser, [('end', '{namespace}element')])
        self._feed(parser, "text tail\n")
        self._feed(parser, " \n")
        self.assert_event_tags(parser, [('end', '{namespace}root')])
        self.assertIsNone(parser.close())
    def test_ns_events(self):
        parser = ET.XMLPullParser(events=('start-ns', 'end-ns'))
        self._feed(parser, "\n")
        self._feed(parser, "\n")
        self.assertEqual(
            list(parser.read_events()),
            [('start-ns', ('', 'namespace'))])
        self._feed(parser, "text \n")
        self._feed(parser, "text tail\n")
        self._feed(parser, " \n")
        self.assertEqual(list(parser.read_events()), [('end-ns', None)])
        self.assertIsNone(parser.close())
    def test_ns_events_start(self):
        parser = ET.XMLPullParser(events=('start-ns', 'start', 'end'))
        self._feed(parser, "\n")
        self.assert_event_tuples(parser, [
            ('start-ns', ('', 'abc')),
            ('start-ns', ('p', 'xyz')),
        ], max_events=2)
        self.assert_event_tags(parser, [
            ('start', '{abc}tag'),
        ], max_events=1)
        self._feed(parser, " \n")
        parser.close()
        self.assert_event_tags(parser, [
            ('end', '{abc}tag'),
        ])
    def test_ns_events_start_end(self):
        parser = ET.XMLPullParser(events=('start-ns', 'start', 'end', 'end-ns'))
        self._feed(parser, "\n")
        self.assert_event_tuples(parser, [
            ('start-ns', ('', 'abc')),
            ('start-ns', ('p', 'xyz')),
        ], max_events=2)
        self.assert_event_tags(parser, [
            ('start', '{abc}tag'),
        ], max_events=1)
        self._feed(parser, " \n")
        parser.close()
        self.assert_event_tags(parser, [
            ('end', '{abc}tag'),
        ], max_events=1)
        self.assert_event_tuples(parser, [
            ('end-ns', None),
            ('end-ns', None),
        ])
    def test_events(self):
        parser = ET.XMLPullParser(events=())
        self._feed(parser, "\n")
        self.assert_event_tags(parser, [('start', 'root')])
        self._feed(parser, "text \n")
        self.assert_event_tags(parser, [('end', 'element')])
        self._feed(parser,
                   "text tail\n")
        self.assert_event_tags(parser, [
            ('start', '{foo}element'),
            ('start', '{foo}empty-element'),
            ('end', '{foo}empty-element'),
            ('end', '{foo}element'),
            ])
        self._feed(parser, " ")
        self.assertIsNone(parser.close())
        self.assert_event_tags(parser, [('end', 'root')])
        parser = ET.XMLPullParser(events=('start',))
        self._feed(parser, "\n")
        self.assert_event_tags(parser, [])
        self._feed(parser, "\n")
        self.assert_event_tags(parser, [('start', 'root')])
        self._feed(parser, "text \n")
        self.assert_event_tags(parser, [])
        self._feed(parser,
                   "text tail\n")
        self.assert_event_tags(parser, [
            ('start', '{foo}element'),
            ('start', '{foo}empty-element'),
            ])
        self._feed(parser, " ")
        self.assertIsNone(parser.close())
    def test_events_comment(self):
        parser = ET.XMLPullParser(events=('start', 'comment', 'end'))
        self._feed(parser, "\n")
        self.assert_events(parser, [('comment', (ET.Comment, ' text here '))])
        self._feed(parser, "\n")
        self.assert_events(parser, [('comment', (ET.Comment, ' more text here '))])
        self._feed(parser, "text")
        self.assert_event_tags(parser, [('start', 'root-tag')])
        self._feed(parser, "\n")
        self.assert_events(parser, [('comment', (ET.Comment, ' inner comment'))])
        self._feed(parser, " \n")
        self.assert_event_tags(parser, [('end', 'root-tag')])
        self._feed(parser, "\n")
        self.assert_events(parser, [('comment', (ET.Comment, ' outer comment '))])
        parser = ET.XMLPullParser(events=('comment',))
        self._feed(parser, "\n")
        self.assert_events(parser, [('comment', (ET.Comment, ' text here '))])
    def test_events_pi(self):
        parser = ET.XMLPullParser(events=('start', 'pi', 'end'))
        self._feed(parser, "\n")
        self.assert_events(parser, [('pi', (ET.PI, 'pitarget'))])
        parser = ET.XMLPullParser(events=('pi',))
        self._feed(parser, "\n")
        self.assert_events(parser, [('pi', (ET.PI, 'pitarget some text '))])
    def test_events_sequence(self):
        # Test that events can be some sequence that's not just a tuple or list
        eventset = {'end', 'start'}
        parser = ET.XMLPullParser(events=eventset)
        self._feed(parser, "bar ")
        self.assert_event_tags(parser, [('start', 'foo'), ('end', 'foo')])
        class DummyIter:
            def __init__(self):
                self.events = iter(['start', 'end', 'start-ns'])
            def __iter__(self):
                return self
            def __next__(self):
                return next(self.events)
        parser = ET.XMLPullParser(events=DummyIter())
        self._feed(parser, "bar ")
        self.assert_event_tags(parser, [('start', 'foo'), ('end', 'foo')])
    def test_unknown_event(self):
        with self.assertRaises(ValueError):
            ET.XMLPullParser(events=('start', 'end', 'bogus'))
#
# xinclude tests (samples from appendix C of the xinclude specification)
XINCLUDE = {}
XINCLUDE["C1.xml"] = """\
  120 Mz is adequate for an average home user.
   
"""
XINCLUDE["disclaimer.xml"] = """\
  The opinions represented herein represent those of the individual
  and should not be interpreted as official policy endorsed by this
  organization.
 
"""
XINCLUDE["C2.xml"] = """\
  This document has been accessed
  
 
"""
XINCLUDE["count.txt"] = "324387"
XINCLUDE["C2b.xml"] = """\
  This document has been accessed 
  
 
"""
XINCLUDE["C3.xml"] = """\
  The following is the source of the "data.xml" resource:
   
"""
XINCLUDE["data.xml"] = """\
  
 
"""
XINCLUDE["C5.xml"] = """\
"""
XINCLUDE["default.xml"] = """\
  Example.
   
""".format(html.escape(SIMPLE_XMLFILE, True))
#
# badly formatted xi:include tags
XINCLUDE_BAD = {}
XINCLUDE_BAD["B1.xml"] = """\
  120 Mz is adequate for an average home user.
   
"""
XINCLUDE_BAD["B2.xml"] = """\
    
"""
class XIncludeTest(unittest.TestCase):
    def xinclude_loader(self, href, parse="xml", encoding=None):
        try:
            data = XINCLUDE[href]
        except KeyError:
            raise OSError("resource not found")
        if parse == "xml":
            data = ET.XML(data)
        return data
    def none_loader(self, href, parser, encoding=None):
        return None
    def _my_loader(self, href, parse):
        # Used to avoid a test-dependency problem where the default loader
        # of ElementInclude uses the pyET parser for cET tests.
        if parse == 'xml':
            with open(href, 'rb') as f:
                return ET.parse(f).getroot()
        else:
            return None
    def test_xinclude_default(self):
        from xml.etree import ElementInclude
        doc = self.xinclude_loader('default.xml')
        ElementInclude.include(doc, self._my_loader)
        self.assertEqual(serialize(doc),
            '\n'
            '  Example.
\n'
            '  \n'
            '   text \n'
            '   text tail\n'
            '    \n'
            ' ')
    def test_xinclude(self):
        from xml.etree import ElementInclude
        # Basic inclusion example (XInclude C.1)
        document = self.xinclude_loader("C1.xml")
        ElementInclude.include(document, self.xinclude_loader)
        self.assertEqual(serialize(document),
            '\n'
            '  120 Mz is adequate for an average home user.
\n'
            '  \n'
            '  The opinions represented herein represent those of the individual\n'
            '  and should not be interpreted as official policy endorsed by this\n'
            '  organization.
\n'
            ' \n'
            ' ') # C1
        # Textual inclusion example (XInclude C.2)
        document = self.xinclude_loader("C2.xml")
        ElementInclude.include(document, self.xinclude_loader)
        self.assertEqual(serialize(document),
            '\n'
            '  This document has been accessed\n'
            '  324387 times.
\n'
            ' ') # C2
        # Textual inclusion after sibling element (based on modified XInclude C.2)
        document = self.xinclude_loader("C2b.xml")
        ElementInclude.include(document, self.xinclude_loader)
        self.assertEqual(serialize(document),
            '\n'
            '  This document has been accessed \n'
            '  324387 times.
\n'
            ' ') # C2b
        # Textual inclusion of XML example (XInclude C.3)
        document = self.xinclude_loader("C3.xml")
        ElementInclude.include(document, self.xinclude_loader)
        self.assertEqual(serialize(document),
            '\n'
            '  The following is the source of the "data.xml" resource:
\n'
            "  <?xml version='1.0'?>\n"
            '<data>\n'
            '  <item><![CDATA[Brooks & Shields]]></item>\n'
            '</data>\n'
            ' \n'
            ' ') # C3
        # Fallback example (XInclude C.5)
        # Note! Fallback support is not yet implemented
        document = self.xinclude_loader("C5.xml")
        with self.assertRaises(OSError) as cm:
            ElementInclude.include(document, self.xinclude_loader)
        self.assertEqual(str(cm.exception), 'resource not found')
        self.assertEqual(serialize(document),
            '') # C5
    def test_xinclude_failures(self):
        from xml.etree import ElementInclude
        # Test failure to locate included XML file.
        document = ET.XML(XINCLUDE["C1.xml"])
        with self.assertRaises(ElementInclude.FatalIncludeError) as cm:
            ElementInclude.include(document, loader=self.none_loader)
        self.assertEqual(str(cm.exception),
                "cannot load 'disclaimer.xml' as 'xml'")
        # Test failure to locate included text file.
        document = ET.XML(XINCLUDE["C2.xml"])
        with self.assertRaises(ElementInclude.FatalIncludeError) as cm:
            ElementInclude.include(document, loader=self.none_loader)
        self.assertEqual(str(cm.exception),
                "cannot load 'count.txt' as 'text'")
        # Test bad parse type.
        document = ET.XML(XINCLUDE_BAD["B1.xml"])
        with self.assertRaises(ElementInclude.FatalIncludeError) as cm:
            ElementInclude.include(document, loader=self.none_loader)
        self.assertEqual(str(cm.exception),
                "unknown parse type in xi:include tag ('BAD_TYPE')")
        # Test xi:fallback outside xi:include.
        document = ET.XML(XINCLUDE_BAD["B2.xml"])
        with self.assertRaises(ElementInclude.FatalIncludeError) as cm:
            ElementInclude.include(document, loader=self.none_loader)
        self.assertEqual(str(cm.exception),
                "xi:fallback tag must be child of xi:include "
                "('{http://www.w3.org/2001/XInclude}fallback')")
# --------------------------------------------------------------------
# reported bugs
class BugsTest(unittest.TestCase):
    def test_bug_xmltoolkit21(self):
        # marshaller gives obscure errors for non-string values
        def check(elem):
            with self.assertRaises(TypeError) as cm:
                serialize(elem)
            self.assertEqual(str(cm.exception),
                    'cannot serialize 123 (type int)')
        elem = ET.Element(123)
        check(elem) # tag
        elem = ET.Element("elem")
        elem.text = 123
        check(elem) # text
        elem = ET.Element("elem")
        elem.tail = 123
        check(elem) # tail
        elem = ET.Element("elem")
        elem.set(123, "123")
        check(elem) # attribute key
        elem = ET.Element("elem")
        elem.set("123", 123)
        check(elem) # attribute value
    def test_bug_xmltoolkit25(self):
        # typo in ElementTree.findtext
        elem = ET.XML(SAMPLE_XML)
        tree = ET.ElementTree(elem)
        self.assertEqual(tree.findtext("tag"), 'text')
        self.assertEqual(tree.findtext("section/tag"), 'subtext')
    def test_bug_xmltoolkit28(self):
        # .//tag causes exceptions
        tree = ET.XML("text ')
        self.assertEqual(ET.tostring(tree, "utf-8"),
                b'text ')
        tree = ET.Element("t\u00e4g")
        self.assertEqual(ET.tostring(tree, "utf-8"), b'&ldots; ')
        self.assertEqual(serialize(e, encoding="us-ascii"),
                b'舰 ')
        self.assertEqual(serialize(e), '\u8230 ')
    def test_bug_xmltoolkit55(self):
        # make sure we're reporting the first error, not the last
        with self.assertRaises(ET.ParseError) as cm:
            ET.XML(b""
                   b'&ldots;&ndots;&rdots; ')
        self.assertEqual(str(cm.exception),
                'undefined entity &ldots;: line 1, column 36')
    def test_bug_xmltoolkit60(self):
        # Handle crash in stream source.
        class ExceptionFile:
            def read(self, x):
                raise OSError
        self.assertRaises(OSError, ET.parse, ExceptionFile())
    def test_bug_xmltoolkit62(self):
        # Don't crash when using custom entities.
        ENTITIES = {'rsquo': '\u2019', 'lsquo': '\u2018'}
        parser = ET.XMLParser()
        parser.entity.update(ENTITIES)
        parser.feed("""
A new cultivar of Begonia plant named ‘BCT9801BEG’. 
 
 """)
        t = parser.close()
        self.assertEqual(t.find('.//paragraph').text,
            'A new cultivar of Begonia plant named \u2018BCT9801BEG\u2019.')
    @unittest.skipIf(sys.gettrace(), "Skips under coverage.")
    def test_bug_xmltoolkit63(self):
        # Check reference leak.
        def xmltoolkit63():
            tree = ET.TreeBuilder()
            tree.start("tag", {})
            tree.data("text")
            tree.end("tag")
        xmltoolkit63()
        count = sys.getrefcount(None)
        for i in range(1000):
            xmltoolkit63()
        self.assertEqual(sys.getrefcount(None), count)
    def test_bug_200708_newline(self):
        # Preserve newlines in attributes.
        e = ET.Element('SomeTag', text="def _f():\n  return 3\n")
        self.assertEqual(ET.tostring(e),
                b'some text ")
        self.assertEqual(parser.close().tag, 'element')
        # Test custom builder.
        class EchoTarget:
            def close(self):
                return ET.Element("element") # simulate root
        parser = ET.XMLParser(target=EchoTarget())
        parser.feed("some text ")
        self.assertEqual(parser.close().tag, 'element')
    def test_bug_200709_default_namespace(self):
        e = ET.Element("{default}elem")
        s = ET.SubElement(e, "{default}elem")
        self.assertEqual(serialize(e, default_namespace="default"), # 1
                ''
            ' ')
        e = ET.Element("{default}elem")
        s = ET.SubElement(e, "{default}elem")
        s = ET.SubElement(e, "elem") # unprefixed name
        with self.assertRaises(ValueError) as cm:
            serialize(e, default_namespace="default") # 3
        self.assertEqual(str(cm.exception),
                'cannot use non-qualified names with default_namespace option')
    def test_bug_200709_register_namespace(self):
        e = ET.Element("{http://namespace.invalid/does/not/exist/}title")
        self.assertEqual(ET.tostring(e),
            b'4 
                    
                 ''')
        nsmap = {'xx': 'X'}
        self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
        self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
        nsmap = {'xx': 'Y'}
        self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 1)
        self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 2)
        nsmap = {'xx': 'X', '': 'Y'}
        self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
        self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 1)
    def test_findall_wildcard(self):
        root = ET.XML('''
            
                 ''')
        root.append(ET.Comment('test'))
        self.assertEqual(summarize_list(root.findall("{*}b")),
                         ['{X}b', 'b', '{Y}b'])
        self.assertEqual(summarize_list(root.findall("{*}c")),
                         ['c'])
        self.assertEqual(summarize_list(root.findall("{X}*")),
                         ['{X}b'])
        self.assertEqual(summarize_list(root.findall("{Y}*")),
                         ['{Y}b'])
        self.assertEqual(summarize_list(root.findall("{}*")),
                         ['b', 'c'])
        self.assertEqual(summarize_list(root.findall("{}b")),  # only for consistency
                         ['b'])
        self.assertEqual(summarize_list(root.findall("{}b")),
                         summarize_list(root.findall("b")))
        self.assertEqual(summarize_list(root.findall("{*}*")),
                         ['{X}b', 'b', 'c', '{Y}b'])
        # This is an unfortunate difference, but that's how find('*') works.
        self.assertEqual(summarize_list(root.findall("{*}*") + [root[-1]]),
                         summarize_list(root.findall("*")))
        self.assertEqual(summarize_list(root.findall(".//{*}b")),
                         ['{X}b', 'b', '{X}b', 'b', '{Y}b'])
        self.assertEqual(summarize_list(root.findall(".//{*}c")),
                         ['c', 'c'])
        self.assertEqual(summarize_list(root.findall(".//{X}*")),
                         ['{X}b', '{X}b'])
        self.assertEqual(summarize_list(root.findall(".//{Y}*")),
                         ['{Y}b'])
        self.assertEqual(summarize_list(root.findall(".//{}*")),
                         ['c', 'b', 'c', 'b'])
        self.assertEqual(summarize_list(root.findall(".//{}b")),  # only for consistency
                         ['b', 'b'])
        self.assertEqual(summarize_list(root.findall(".//{}b")),
                         summarize_list(root.findall(".//b")))
    def test_bad_find(self):
        e = ET.XML(SAMPLE_XML)
        with self.assertRaisesRegex(SyntaxError, 'cannot use absolute path'):
            e.findall('/tag')
    def test_find_through_ElementTree(self):
        e = ET.XML(SAMPLE_XML)
        self.assertEqual(ET.ElementTree(e).find('tag').tag, 'tag')
        self.assertEqual(ET.ElementTree(e).findtext('tag'), 'text')
        self.assertEqual(summarize_list(ET.ElementTree(e).findall('tag')),
            ['tag'] * 2)
        # this produces a warning
        msg = ("This search is broken in 1.3 and earlier, and will be fixed "
               "in a future version.  If you rely on the current behaviour, "
               "change it to '.+'")
        with self.assertWarnsRegex(FutureWarning, msg):
            it = ET.ElementTree(e).findall('//tag')
        self.assertEqual(summarize_list(it), ['tag'] * 3)
class ElementIterTest(unittest.TestCase):
    def _ilist(self, elem, tag=None):
        return summarize_list(elem.iter(tag))
    def test_basic(self):
        doc = ET.XML("this is a paragraph ...")
        self.assertEqual(self._ilist(doc), ['html', 'body', 'i'])
        self.assertEqual(self._ilist(doc.find('body')), ['body', 'i'])
        self.assertEqual(next(doc.iter()).tag, 'html')
        self.assertEqual(''.join(doc.itertext()), 'this is a paragraph...')
        self.assertEqual(''.join(doc.find('body').itertext()),
            'this is a paragraph.')
        self.assertEqual(next(doc.itertext()), 'this is a ')
        # iterparse should return an iterator
        sourcefile = serialize(doc, to_string=False)
        self.assertEqual(next(ET.iterparse(sourcefile))[0], 'end')
        # With an explicit parser too (issue #9708)
        sourcefile = serialize(doc, to_string=False)
        parser = ET.XMLParser(target=ET.TreeBuilder())
        self.assertEqual(next(ET.iterparse(sourcefile, parser=parser))[0],
                         'end')
        tree = ET.ElementTree(None)
        self.assertRaises(AttributeError, tree.iter)
        # Issue #16913
        doc = ET.XML("a&b& c& ")
        self.assertEqual(''.join(doc.itertext()), 'a&b&c&')
    def test_corners(self):
        # single root, no subelements
        a = ET.Element('a')
        self.assertEqual(self._ilist(a), ['a'])
        # one child
        b = ET.SubElement(a, 'b')
        self.assertEqual(self._ilist(a), ['a', 'b'])
        # one child and one grandchild
        c = ET.SubElement(b, 'c')
        self.assertEqual(self._ilist(a), ['a', 'b', 'c'])
        # two children, only first with grandchild
        d = ET.SubElement(a, 'd')
        self.assertEqual(self._ilist(a), ['a', 'b', 'c', 'd'])
        # replace first child by second
        a[0] = a[1]
        del a[1]
        self.assertEqual(self._ilist(a), ['a', 'd'])
    def test_iter_by_tag(self):
        doc = ET.XML('''
            
                
                    bedroom1 
                    bedroom2 
                 
                nothing here
                 
                
                    bedroom8 
                 
             ''')
        self.assertEqual(self._ilist(doc, 'room'), ['room'] * 3)
        self.assertEqual(self._ilist(doc, 'house'), ['house'] * 2)
        # test that iter also accepts 'tag' as a keyword arg
        self.assertEqual(
            summarize_list(doc.iter(tag='room')),
            ['room'] * 3)
        # make sure both tag=None and tag='*' return all tags
        all_tags = ['document', 'house', 'room', 'room',
                    'shed', 'house', 'room']
        self.assertEqual(summarize_list(doc.iter()), all_tags)
        self.assertEqual(self._ilist(doc), all_tags)
        self.assertEqual(self._ilist(doc, '*'), all_tags)
    # Element.getiterator() is deprecated.
    @checkwarnings(("This method will be removed in future versions.  "
                    "Use .+ instead.", DeprecationWarning))
    def test_getiterator(self):
        doc = ET.XML('''
            
                
                    bedroom1 
                    bedroom2 
                 
                nothing here
                 
                
                    bedroom8 
                 
             ''')
        self.assertEqual(summarize_list(doc.getiterator('room')),
                         ['room'] * 3)
        self.assertEqual(summarize_list(doc.getiterator('house')),
                         ['house'] * 2)
        # test that getiterator also accepts 'tag' as a keyword arg
        self.assertEqual(
            summarize_list(doc.getiterator(tag='room')),
            ['room'] * 3)
        # make sure both tag=None and tag='*' return all tags
        all_tags = ['document', 'house', 'room', 'room',
                    'shed', 'house', 'room']
        self.assertEqual(summarize_list(doc.getiterator()), all_tags)
        self.assertEqual(summarize_list(doc.getiterator(None)), all_tags)
        self.assertEqual(summarize_list(doc.getiterator('*')), all_tags)
    def test_copy(self):
        a = ET.Element('a')
        it = a.iter()
        with self.assertRaises(TypeError):
            copy.copy(it)
    def test_pickle(self):
        a = ET.Element('a')
        it = a.iter()
        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
            with self.assertRaises((TypeError, pickle.PicklingError)):
                pickle.dumps(it, proto)
class TreeBuilderTest(unittest.TestCase):
    sample1 = (''
        'textsubtext
tail')
    sample2 = '''sometext '''
    def _check_sample1_element(self, e):
        self.assertEqual(e.tag, 'html')
        self.assertEqual(e.text, 'text')
        self.assertEqual(e.tail, None)
        self.assertEqual(e.attrib, {})
        children = list(e)
        self.assertEqual(len(children), 1)
        child = children[0]
        self.assertEqual(child.tag, 'div')
        self.assertEqual(child.text, 'subtext')
        self.assertEqual(child.tail, 'tail')
        self.assertEqual(child.attrib, {})
    def test_dummy_builder(self):
        class BaseDummyBuilder:
            def close(self):
                return 42
        class DummyBuilder(BaseDummyBuilder):
            data = start = end = lambda *a: None
        parser = ET.XMLParser(target=DummyBuilder())
        parser.feed(self.sample1)
        self.assertEqual(parser.close(), 42)
        parser = ET.XMLParser(target=BaseDummyBuilder())
        parser.feed(self.sample1)
        self.assertEqual(parser.close(), 42)
        parser = ET.XMLParser(target=object())
        parser.feed(self.sample1)
        self.assertIsNone(parser.close())
    def test_treebuilder_comment(self):
        b = ET.TreeBuilder()
        self.assertEqual(b.comment('ctext').tag, ET.Comment)
        self.assertEqual(b.comment('ctext').text, 'ctext')
        b = ET.TreeBuilder(comment_factory=ET.Comment)
        self.assertEqual(b.comment('ctext').tag, ET.Comment)
        self.assertEqual(b.comment('ctext').text, 'ctext')
        b = ET.TreeBuilder(comment_factory=len)
        self.assertEqual(b.comment('ctext'), len('ctext'))
    def test_treebuilder_pi(self):
        b = ET.TreeBuilder()
        self.assertEqual(b.pi('target', None).tag, ET.PI)
        self.assertEqual(b.pi('target', None).text, 'target')
        b = ET.TreeBuilder(pi_factory=ET.PI)
        self.assertEqual(b.pi('target').tag, ET.PI)
        self.assertEqual(b.pi('target').text, "target")
        self.assertEqual(b.pi('pitarget', ' text ').tag, ET.PI)
        self.assertEqual(b.pi('pitarget', ' text ').text, "pitarget  text ")
        b = ET.TreeBuilder(pi_factory=lambda target, text: (len(target), text))
        self.assertEqual(b.pi('target'), (len('target'), None))
        self.assertEqual(b.pi('pitarget', ' text '), (len('pitarget'), ' text '))
    def test_treebuilder_elementfactory_none(self):
        parser = ET.XMLParser(target=ET.TreeBuilder(element_factory=None))
        parser.feed(self.sample1)
        e = parser.close()
        self._check_sample1_element(e)
    def test_subclass(self):
        class MyTreeBuilder(ET.TreeBuilder):
            def foobar(self, x):
                return x * 2
        tb = MyTreeBuilder()
        self.assertEqual(tb.foobar(10), 20)
        parser = ET.XMLParser(target=tb)
        parser.feed(self.sample1)
        e = parser.close()
        self._check_sample1_element(e)
    def test_subclass_comment_pi(self):
        class MyTreeBuilder(ET.TreeBuilder):
            def foobar(self, x):
                return x * 2
        tb = MyTreeBuilder(comment_factory=ET.Comment, pi_factory=ET.PI)
        self.assertEqual(tb.foobar(10), 20)
        parser = ET.XMLParser(target=tb)
        parser.feed(self.sample1)
        parser.feed('')
        e = parser.close()
        self._check_sample1_element(e)
    def test_element_factory(self):
        lst = []
        def myfactory(tag, attrib):
            nonlocal lst
            lst.append(tag)
            return ET.Element(tag, attrib)
        tb = ET.TreeBuilder(element_factory=myfactory)
        parser = ET.XMLParser(target=tb)
        parser.feed(self.sample2)
        parser.close()
        self.assertEqual(lst, ['toplevel'])
    def _check_element_factory_class(self, cls):
        tb = ET.TreeBuilder(element_factory=cls)
        parser = ET.XMLParser(target=tb)
        parser.feed(self.sample1)
        e = parser.close()
        self.assertIsInstance(e, cls)
        self._check_sample1_element(e)
    def test_element_factory_subclass(self):
        class MyElement(ET.Element):
            pass
        self._check_element_factory_class(MyElement)
    def test_element_factory_pure_python_subclass(self):
        # Mimick SimpleTAL's behaviour (issue #16089): both versions of
        # TreeBuilder should be able to cope with a subclass of the
        # pure Python Element class.
        base = ET._Element_Py
        # Not from a C extension
        self.assertEqual(base.__module__, 'xml.etree.ElementTree')
        # Force some multiple inheritance with a C class to make things
        # more interesting.
        class MyElement(base, ValueError):
            pass
        self._check_element_factory_class(MyElement)
    def test_doctype(self):
        class DoctypeParser:
            _doctype = None
            def doctype(self, name, pubid, system):
                self._doctype = (name, pubid, system)
            def close(self):
                return self._doctype
        parser = ET.XMLParser(target=DoctypeParser())
        parser.feed(self.sample1)
        self.assertEqual(parser.close(),
            ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
             'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
    def test_builder_lookup_errors(self):
        class RaisingBuilder:
            def __init__(self, raise_in=None, what=ValueError):
                self.raise_in = raise_in
                self.what = what
            def __getattr__(self, name):
                if name == self.raise_in:
                    raise self.what(self.raise_in)
                def handle(*args):
                    pass
                return handle
        ET.XMLParser(target=RaisingBuilder())
        # cET also checks for 'close' and 'doctype', PyET does it only at need
        for event in ('start', 'data', 'end', 'comment', 'pi'):
            with self.assertRaisesRegex(ValueError, event):
                ET.XMLParser(target=RaisingBuilder(event))
        ET.XMLParser(target=RaisingBuilder(what=AttributeError))
        for event in ('start', 'data', 'end', 'comment', 'pi'):
            parser = ET.XMLParser(target=RaisingBuilder(event, what=AttributeError))
            parser.feed(self.sample1)
            self.assertIsNone(parser.close())
class XMLParserTest(unittest.TestCase):
    sample1 = b'22 $\xa3\u20ac\U0001017b ')
    def _check_sample_element(self, e):
        self.assertEqual(e.tag, 'file')
        self.assertEqual(e[0].tag, 'line')
        self.assertEqual(e[0].text, '22')
    def test_constructor_args(self):
        parser2 = ET.XMLParser(encoding='utf-8',
                               target=ET.TreeBuilder())
        parser2.feed(self.sample1)
        self._check_sample_element(parser2.close())
    def test_subclass(self):
        class MyParser(ET.XMLParser):
            pass
        parser = MyParser()
        parser.feed(self.sample1)
        self._check_sample_element(parser.close())
    def test_doctype_warning(self):
        with warnings.catch_warnings():
            warnings.simplefilter('error', DeprecationWarning)
            parser = ET.XMLParser()
            parser.feed(self.sample2)
            parser.close()
    def test_subclass_doctype(self):
        _doctype = None
        class MyParserWithDoctype(ET.XMLParser):
            def doctype(self, *args, **kwargs):
                nonlocal _doctype
                _doctype = (args, kwargs)
        parser = MyParserWithDoctype()
        with self.assertWarnsRegex(RuntimeWarning, 'doctype'):
            parser.feed(self.sample2)
        parser.close()
        self.assertIsNone(_doctype)
        _doctype = _doctype2 = None
        with warnings.catch_warnings():
            warnings.simplefilter('error', DeprecationWarning)
            warnings.simplefilter('error', RuntimeWarning)
            class DoctypeParser:
                def doctype(self, name, pubid, system):
                    nonlocal _doctype2
                    _doctype2 = (name, pubid, system)
            parser = MyParserWithDoctype(target=DoctypeParser())
            parser.feed(self.sample2)
            parser.close()
            self.assertIsNone(_doctype)
            self.assertEqual(_doctype2,
                ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
                 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
    def test_inherited_doctype(self):
        '''Ensure that ordinary usage is not deprecated (Issue 19176)'''
        with warnings.catch_warnings():
            warnings.simplefilter('error', DeprecationWarning)
            warnings.simplefilter('error', RuntimeWarning)
            class MyParserWithoutDoctype(ET.XMLParser):
                pass
            parser = MyParserWithoutDoctype()
            parser.feed(self.sample2)
            parser.close()
    def test_parse_string(self):
        parser = ET.XMLParser(target=ET.TreeBuilder())
        parser.feed(self.sample3)
        e = parser.close()
        self.assertEqual(e.tag, 'money')
        self.assertEqual(e.attrib['value'], '$\xa3\u20ac\U0001017b')
        self.assertEqual(e.text, '$\xa3\u20ac\U0001017b')
class NamespaceParseTest(unittest.TestCase):
    def test_find_with_namespace(self):
        nsmap = {'h': 'hello', 'f': 'foo'}
        doc = ET.fromstring(SAMPLE_XML_NS_ELEMS)
        self.assertEqual(len(doc.findall('{hello}table', nsmap)), 1)
        self.assertEqual(len(doc.findall('.//{hello}td', nsmap)), 2)
        self.assertEqual(len(doc.findall('.//{foo}name', nsmap)), 1)
class ElementSlicingTest(unittest.TestCase):
    def _elem_tags(self, elemlist):
        return [e.tag for e in elemlist]
    def _subelem_tags(self, elem):
        return self._elem_tags(list(elem))
    def _make_elem_with_children(self, numchildren):
        """Create an Element with a tag 'a', with the given amount of children
           named 'a0', 'a1' ... and so on.
        """
        e = ET.Element('a')
        for i in range(numchildren):
            ET.SubElement(e, 'a%s' % i)
        return e
    def test_getslice_single_index(self):
        e = self._make_elem_with_children(10)
        self.assertEqual(e[1].tag, 'a1')
        self.assertEqual(e[-2].tag, 'a8')
        self.assertRaises(IndexError, lambda: e[12])
        self.assertRaises(IndexError, lambda: e[-12])
    def test_getslice_range(self):
        e = self._make_elem_with_children(6)
        self.assertEqual(self._elem_tags(e[3:]), ['a3', 'a4', 'a5'])
        self.assertEqual(self._elem_tags(e[3:6]), ['a3', 'a4', 'a5'])
        self.assertEqual(self._elem_tags(e[3:16]), ['a3', 'a4', 'a5'])
        self.assertEqual(self._elem_tags(e[3:5]), ['a3', 'a4'])
        self.assertEqual(self._elem_tags(e[3:-1]), ['a3', 'a4'])
        self.assertEqual(self._elem_tags(e[:2]), ['a0', 'a1'])
    def test_getslice_steps(self):
        e = self._make_elem_with_children(10)
        self.assertEqual(self._elem_tags(e[8:10:1]), ['a8', 'a9'])
        self.assertEqual(self._elem_tags(e[::3]), ['a0', 'a3', 'a6', 'a9'])
        self.assertEqual(self._elem_tags(e[::8]), ['a0', 'a8'])
        self.assertEqual(self._elem_tags(e[1::8]), ['a1', 'a9'])
        self.assertEqual(self._elem_tags(e[3::sys.maxsize]), ['a3'])
        self.assertEqual(self._elem_tags(e[3::sys.maxsize<<64]), ['a3'])
    def test_getslice_negative_steps(self):
        e = self._make_elem_with_children(4)
        self.assertEqual(self._elem_tags(e[::-1]), ['a3', 'a2', 'a1', 'a0'])
        self.assertEqual(self._elem_tags(e[::-2]), ['a3', 'a1'])
        self.assertEqual(self._elem_tags(e[3::-sys.maxsize]), ['a3'])
        self.assertEqual(self._elem_tags(e[3::-sys.maxsize-1]), ['a3'])
        self.assertEqual(self._elem_tags(e[3::-sys.maxsize<<64]), ['a3'])
    def test_delslice(self):
        e = self._make_elem_with_children(4)
        del e[0:2]
        self.assertEqual(self._subelem_tags(e), ['a2', 'a3'])
        e = self._make_elem_with_children(4)
        del e[0:]
        self.assertEqual(self._subelem_tags(e), [])
        e = self._make_elem_with_children(4)
        del e[::-1]
        self.assertEqual(self._subelem_tags(e), [])
        e = self._make_elem_with_children(4)
        del e[::-2]
        self.assertEqual(self._subelem_tags(e), ['a0', 'a2'])
        e = self._make_elem_with_children(4)
        del e[1::2]
        self.assertEqual(self._subelem_tags(e), ['a0', 'a2'])
        e = self._make_elem_with_children(2)
        del e[::2]
        self.assertEqual(self._subelem_tags(e), ['a1'])
    def test_setslice_single_index(self):
        e = self._make_elem_with_children(4)
        e[1] = ET.Element('b')
        self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3'])
        e[-2] = ET.Element('c')
        self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'c', 'a3'])
        with self.assertRaises(IndexError):
            e[5] = ET.Element('d')
        with self.assertRaises(IndexError):
            e[-5] = ET.Element('d')
        self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'c', 'a3'])
    def test_setslice_range(self):
        e = self._make_elem_with_children(4)
        e[1:3] = [ET.Element('b%s' % i) for i in range(2)]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'b1', 'a3'])
        e = self._make_elem_with_children(4)
        e[1:3] = [ET.Element('b')]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a3'])
        e = self._make_elem_with_children(4)
        e[1:3] = [ET.Element('b%s' % i) for i in range(3)]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'b1', 'b2', 'a3'])
    def test_setslice_steps(self):
        e = self._make_elem_with_children(6)
        e[1:5:2] = [ET.Element('b%s' % i) for i in range(2)]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b0', 'a2', 'b1', 'a4', 'a5'])
        e = self._make_elem_with_children(6)
        with self.assertRaises(ValueError):
            e[1:5:2] = [ET.Element('b')]
        with self.assertRaises(ValueError):
            e[1:5:2] = [ET.Element('b%s' % i) for i in range(3)]
        with self.assertRaises(ValueError):
            e[1:5:2] = []
        self.assertEqual(self._subelem_tags(e), ['a0', 'a1', 'a2', 'a3', 'a4', 'a5'])
        e = self._make_elem_with_children(4)
        e[1::sys.maxsize] = [ET.Element('b')]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3'])
        e[1::sys.maxsize<<64] = [ET.Element('c')]
        self.assertEqual(self._subelem_tags(e), ['a0', 'c', 'a2', 'a3'])
    def test_setslice_negative_steps(self):
        e = self._make_elem_with_children(4)
        e[2:0:-1] = [ET.Element('b%s' % i) for i in range(2)]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b1', 'b0', 'a3'])
        e = self._make_elem_with_children(4)
        with self.assertRaises(ValueError):
            e[2:0:-1] = [ET.Element('b')]
        with self.assertRaises(ValueError):
            e[2:0:-1] = [ET.Element('b%s' % i) for i in range(3)]
        with self.assertRaises(ValueError):
            e[2:0:-1] = []
        self.assertEqual(self._subelem_tags(e), ['a0', 'a1', 'a2', 'a3'])
        e = self._make_elem_with_children(4)
        e[1::-sys.maxsize] = [ET.Element('b')]
        self.assertEqual(self._subelem_tags(e), ['a0', 'b', 'a2', 'a3'])
        e[1::-sys.maxsize-1] = [ET.Element('c')]
        self.assertEqual(self._subelem_tags(e), ['a0', 'c', 'a2', 'a3'])
        e[1::-sys.maxsize<<64] = [ET.Element('d')]
        self.assertEqual(self._subelem_tags(e), ['a0', 'd', 'a2', 'a3'])
class IOTest(unittest.TestCase):
    def test_encoding(self):
        # Test encoding issues.
        elem = ET.Element("tag")
        elem.text = "abc"
        self.assertEqual(serialize(elem), 'abc ')
        for enc in ("utf-8", "us-ascii"):
            with self.subTest(enc):
                self.assertEqual(serialize(elem, encoding=enc),
                        b'abc ')
                self.assertEqual(serialize(elem, encoding=enc.upper()),
                        b'abc ')
        for enc in ("iso-8859-1", "utf-16", "utf-32"):
            with self.subTest(enc):
                self.assertEqual(serialize(elem, encoding=enc),
                        ("\n"
                         "abc " % enc).encode(enc))
                upper = enc.upper()
                self.assertEqual(serialize(elem, encoding=upper),
                        ("\n"
                         "abc " % upper).encode(enc))
        elem = ET.Element("tag")
        elem.text = "<&\"\'>"
        self.assertEqual(serialize(elem), '<&"\'> ')
        self.assertEqual(serialize(elem, encoding="utf-8"),
                b'<&"\'> ')
        self.assertEqual(serialize(elem, encoding="us-ascii"),
                b'<&"\'> ')
        for enc in ("iso-8859-1", "utf-16", "utf-32"):
            self.assertEqual(serialize(elem, encoding=enc),
                    ("\n"
                     "<&\"'> " % enc).encode(enc))
        elem = ET.Element("tag")
        elem.attrib["key"] = "<&\"\'>"
        self.assertEqual(serialize(elem), '\xe5\xf6\xf6<> ')
        self.assertEqual(serialize(elem, encoding="utf-8"),
                b'\xc3\xa5\xc3\xb6\xc3\xb6<> ')
        self.assertEqual(serialize(elem, encoding="us-ascii"),
                b'åöö<> ')
        for enc in ("iso-8859-1", "utf-16", "utf-32"):
            self.assertEqual(serialize(elem, encoding=enc),
                    ("\n"
                     "åöö<> " % enc).encode(enc))
        elem = ET.Element("tag")
        elem.attrib["key"] = '\xe5\xf6\xf6<>'
        self.assertEqual(serialize(elem), 'foo ')
        self.assertEqual(
            ET.tostring(root, 'unicode'),
            ''.join(ET.tostringlist(root, 'unicode')))
        self.assertEqual(
            ET.tostring(root, 'utf-16'),
            b''.join(ET.tostringlist(root, 'utf-16')))
    def test_short_empty_elements(self):
        root = ET.fromstring('a ')
        self.assertEqual(
            ET.tostring(root, 'unicode'),
            'a ')
        self.assertEqual(
            ET.tostring(root, 'unicode', short_empty_elements=True),
            'a ')
        self.assertEqual(
            ET.tostring(root, 'unicode', short_empty_elements=False),
            'a ')
class ParseErrorTest(unittest.TestCase):
    def test_subclass(self):
        self.assertIsInstance(ET.ParseError(), SyntaxError)
    def _get_error(self, s):
        try:
            ET.fromstring(s)
        except ET.ParseError as e:
            return e
    def test_error_position(self):
        self.assertEqual(self._get_error('foo').position, (1, 0))
        self.assertEqual(self._get_error('&foo; ').position, (1, 5))
        self.assertEqual(self._get_error('foobar<').position, (1, 6))
    def test_error_code(self):
        import xml.parsers.expat.errors as ERRORS
        self.assertEqual(self._get_error('foo').code,
                ERRORS.codes[ERRORS.XML_ERROR_SYNTAX])
class KeywordArgsTest(unittest.TestCase):
    # Test various issues with keyword arguments passed to ET.Element
    # constructor and methods
    def test_issue14818(self):
        x = ET.XML("foo ")
        self.assertEqual(x.find('a', None),
                         x.find(path='a', namespaces=None))
        self.assertEqual(x.findtext('a', None, None),
                         x.findtext(path='a', default=None, namespaces=None))
        self.assertEqual(x.findall('a', None),
                         x.findall(path='a', namespaces=None))
        self.assertEqual(list(x.iterfind('a', None)),
                         list(x.iterfind(path='a', namespaces=None)))
        self.assertEqual(ET.Element('a').attrib, {})
        elements = [
            ET.Element('a', dict(href="#", id="foo")),
            ET.Element('a', attrib=dict(href="#", id="foo")),
            ET.Element('a', dict(href="#"), id="foo"),
            ET.Element('a', href="#", id="foo"),
            ET.Element('a', dict(href="#", id="foo"), href="#", id="foo"),
        ]
        for e in elements:
            self.assertEqual(e.tag, 'a')
            self.assertEqual(e.attrib, dict(href="#", id="foo"))
        e2 = ET.SubElement(elements[0], 'foobar', attrib={'key1': 'value1'})
        self.assertEqual(e2.attrib['key1'], 'value1')
        with self.assertRaisesRegex(TypeError, 'must be dict, not str'):
            ET.Element('a', "I'm not a dict")
        with self.assertRaisesRegex(TypeError, 'must be dict, not str'):
            ET.Element('a', attrib="I'm not a dict")
# --------------------------------------------------------------------
class NoAcceleratorTest(unittest.TestCase):
    def setUp(self):
        if not pyET:
            raise unittest.SkipTest('only for the Python version')
    # Test that the C accelerator was not imported for pyET
    def test_correct_import_pyET(self):
        # The type of methods defined in Python code is types.FunctionType,
        # while the type of methods defined inside _elementtree is
        # 
        self.assertIsInstance(pyET.Element.__init__, types.FunctionType)
        self.assertIsInstance(pyET.XMLParser.__init__, types.FunctionType)
# --------------------------------------------------------------------
def c14n_roundtrip(xml, **options):
    return pyET.canonicalize(xml, **options)
class C14NTest(unittest.TestCase):
    maxDiff = None
    #
    # simple roundtrip tests (from c14n.py)
    def test_simple_roundtrip(self):
        # Basics
        self.assertEqual(c14n_roundtrip("Hello, world! "),
            'Hello, world! ')
        self.assertEqual(c14n_roundtrip("2 "),
            '2 ')
        self.assertEqual(c14n_roundtrip('"0" && value<"10" ?"valid":"error"]]> '),
            'value>"0" && value<"10" ?"valid":"error" ')
        self.assertEqual(c14n_roundtrip('''valid '''),
            'valid ')
        self.assertEqual(c14n_roundtrip("
            
                abtext 
             
            btext 
            
                dtext 
             
         
        """)
        self.assertEqual(
            c14n_roundtrip(xml, strip_text=True),
            ''
            'abtext btext '
            'dtext  ')
        self.assertEqual(
            c14n_roundtrip(xml, strip_text=True, exclude_attrs=['{http://example.com/x}attr']),
            ''
            'abtext btext '
            'dtext  ')
        self.assertEqual(
            c14n_roundtrip(xml, strip_text=True, exclude_tags=['{http://example.com/x}d']),
            ''
            'abtext btext '
            ' ')
        self.assertEqual(
            c14n_roundtrip(xml, strip_text=True, exclude_attrs=['{http://example.com/x}attr'],
                           exclude_tags=['{http://example.com/x}d']),
            ''
            'abtext btext '
            ' ')
        self.assertEqual(
            c14n_roundtrip(xml, strip_text=True, exclude_tags=['a', 'b']),
            ''
            'dtext  ')
        self.assertEqual(
            c14n_roundtrip(xml, exclude_tags=['a', 'b']),
            '\n'
            '    \n'
            '    \n'
            '    \n'
            '        dtext \n'
            '     \n'
            ' ')
        self.assertEqual(
            c14n_roundtrip(xml, strip_text=True, exclude_tags=['{http://example.com/x}d', 'b']),
            ''
            ' ')
        self.assertEqual(
            c14n_roundtrip(xml, exclude_tags=['{http://example.com/x}d', 'b']),
            '\n'
            '    \n'
            '        \n'
            '     \n'
            '    \n'
            '    \n'
            '        \n'
            '     \n'
            ' ')
    #
    # basic method=c14n tests from the c14n 2.0 specification.  uses
    # test files under xmltestdata/c14n-20.
    # note that this uses generated C14N versions of the standard ET.write
    # output, not roundtripped C14N (see above).
    def test_xml_c14n2(self):
        datadir = findfile("c14n-20", subdir="xmltestdata")
        full_path = partial(os.path.join, datadir)
        files = [filename[:-4] for filename in sorted(os.listdir(datadir))
                 if filename.endswith('.xml')]
        input_files = [
            filename for filename in files
            if filename.startswith('in')
        ]
        configs = {
            filename: {
                # sequential 
                option.tag.split('}')[-1]: ((option.text or '').strip(), option)
                for option in ET.parse(full_path(filename) + ".xml").getroot()
            }
            for filename in files
            if filename.startswith('c14n')
        }
        tests = {
            input_file: [
                (filename, configs[filename.rsplit('_', 1)[-1]])
                for filename in files
                if filename.startswith(f'out_{input_file}_')
                and filename.rsplit('_', 1)[-1] in configs
            ]
            for input_file in input_files
        }
        # Make sure we found all test cases.
        self.assertEqual(30, len([
            output_file for output_files in tests.values()
            for output_file in output_files]))
        def get_option(config, option_name, default=None):
            return config.get(option_name, (default, ()))[0]
        for input_file, output_files in tests.items():
            for output_file, config in output_files:
                keep_comments = get_option(
                    config, 'IgnoreComments') == 'true'  # no, it's right :)
                strip_text = get_option(
                    config, 'TrimTextNodes') == 'true'
                rewrite_prefixes = get_option(
                    config, 'PrefixRewrite') == 'sequential'
                if 'QNameAware' in config:
                    qattrs = [
                        f"{{{el.get('NS')}}}{el.get('Name')}"
                        for el in config['QNameAware'][1].findall(
                            '{http://www.w3.org/2010/xml-c14n2}QualifiedAttr')
                    ]
                    qtags = [
                        f"{{{el.get('NS')}}}{el.get('Name')}"
                        for el in config['QNameAware'][1].findall(
                            '{http://www.w3.org/2010/xml-c14n2}Element')
                    ]
                else:
                    qtags = qattrs = None
                # Build subtest description from config.
                config_descr = ','.join(
                    f"{name}={value or ','.join(c.tag.split('}')[-1] for c in children)}"
                    for name, (value, children) in sorted(config.items())
                )
                with self.subTest(f"{output_file}({config_descr})"):
                    if input_file == 'inNsRedecl' and not rewrite_prefixes:
                        self.skipTest(
                            f"Redeclared namespace handling is not supported in {output_file}")
                    if input_file == 'inNsSuperfluous' and not rewrite_prefixes:
                        self.skipTest(
                            f"Redeclared namespace handling is not supported in {output_file}")
                    if 'QNameAware' in config and config['QNameAware'][1].find(
                            '{http://www.w3.org/2010/xml-c14n2}XPathElement') is not None:
                        self.skipTest(
                            f"QName rewriting in XPath text is not supported in {output_file}")
                    f = full_path(input_file + ".xml")
                    if input_file == 'inC14N5':
                        # Hack: avoid setting up external entity resolution in the parser.
                        with open(full_path('world.txt'), 'rb') as entity_file:
                            with open(f, 'rb') as f:
                                f = io.BytesIO(f.read().replace(b'&ent2;', entity_file.read()))
                    text = ET.canonicalize(
                        from_file=f,
                        with_comments=keep_comments,
                        strip_text=strip_text,
                        rewrite_prefixes=rewrite_prefixes,
                        qname_aware_tags=qtags, qname_aware_attrs=qattrs)
                    with open(full_path(output_file + ".xml"), 'r', encoding='utf8') as f:
                        expected = f.read()
                        if input_file == 'inC14N3':
                            # FIXME: cET resolves default attributes but ET does not!
                            expected = expected.replace(' attr="default"', '')
                            text = text.replace(' attr="default"', '')
                    self.assertEqual(expected, text)
# --------------------------------------------------------------------
def test_main(module=None):
    # When invoked without a module, runs the Python ET tests by loading pyET.
    # Otherwise, uses the given module as the ET.
    global pyET
    pyET = import_fresh_module('xml.etree.ElementTree',
                               blocked=['_elementtree'])
    if module is None:
        module = pyET
    global ET
    ET = module
    test_classes = [
        ModuleTest,
        ElementSlicingTest,
        BasicElementTest,
        BadElementTest,
        BadElementPathTest,
        ElementTreeTest,
        IOTest,
        ParseErrorTest,
        XIncludeTest,
        ElementTreeTypeTest,
        ElementFindTest,
        ElementIterTest,
        TreeBuilderTest,
        XMLParserTest,
        XMLPullParserTest,
        BugsTest,
        KeywordArgsTest,
        C14NTest,
        ]
    # These tests will only run for the pure-Python version that doesn't import
    # _elementtree. We can't use skipUnless here, because pyET is filled in only
    # after the module is loaded.
    if pyET is not ET:
        test_classes.extend([
            NoAcceleratorTest,
            ])
    # Provide default namespace mapping and path cache.
    from xml.etree import ElementPath
    nsmap = ET.register_namespace._namespace_map
    # Copy the default namespace mapping
    nsmap_copy = nsmap.copy()
    # Copy the path cache (should be empty)
    path_cache = ElementPath._cache
    ElementPath._cache = path_cache.copy()
    # Align the Comment/PI factories.
    if hasattr(ET, '_set_factories'):
        old_factories = ET._set_factories(ET.Comment, ET.PI)
    else:
        old_factories = None
    try:
        support.run_unittest(*test_classes)
    finally:
        from xml.etree import ElementPath
        # Restore mapping and path cache
        nsmap.clear()
        nsmap.update(nsmap_copy)
        ElementPath._cache = path_cache
        if old_factories is not None:
            ET._set_factories(*old_factories)
        # don't interfere with subsequent tests
        ET = pyET = None
if __name__ == '__main__':
    test_main()