66# monkey-patched when running the "test_xml_etree_c" test suite.
77
88import copy
9+ import itertools
910import functools
1011import html
1112import io
@@ -109,6 +110,11 @@ def newtest(*args, **kwargs):
109110return decorator
110111
111112
113+ #-----------------------------------------------------------------------------
114+ # UNIT TESTS
115+ #-----------------------------------------------------------------------------
116+
117+
112118class ModuleTest (unittest .TestCase ):
113119def test_sanity (self ):
114120# Import sanity.
@@ -122,6 +128,104 @@ def test_all(self):
122128support .check__all__ (self ,ET ,names ,blacklist = ("HTML_EMPTY" ,))
123129
124130
131+ class ElementTree_Element_UnitTest (unittest .TestCase ):
132+
133+ def test___init__ (self ):
134+ tag = "foo"
135+ attrib = {"zix" :"wyp" }
136+
137+ element_foo = ET .Element (tag ,attrib )
138+
139+ with self .subTest ("traits of an element" ):
140+ self .assertIsInstance (element_foo ,ET .Element )
141+ self .assertIn ("tag" ,dir (element_foo ))
142+ self .assertIn ("attrib" ,dir (element_foo ))
143+ self .assertIn ("text" ,dir (element_foo ))
144+ self .assertIn ("tail" ,dir (element_foo ))
145+
146+ with self .subTest ("string attributes have expected values" ):
147+ self .assertEqual (element_foo .tag ,tag )
148+ self .assertIsNone (element_foo .text )
149+ self .assertIsNone (element_foo .tail )
150+
151+ with self .subTest ("attrib is a copy" ):
152+ self .assertIsNot (element_foo .attrib ,attrib )
153+ self .assertEqual (element_foo .attrib ,attrib )
154+
155+ with self .subTest ("attrib isn't linked" ):
156+ attrib ["bar" ]= "baz"
157+
158+ self .assertIsNot (element_foo .attrib ,attrib )
159+ self .assertNotEqual (element_foo .attrib ,attrib )
160+
161+
162+ def test___copy__ (self ):
163+ element_foo = ET .Element ("foo" , {"zix" :"wyp" })
164+ element_foo .append (ET .Element ("bar" , {"baz" :"qix" }))
165+
166+ element_foo2 = copy .copy (element_foo )
167+
168+ with self .subTest ("elements are not the same" ):
169+ self .assertIsNot (element_foo2 ,element_foo )
170+
171+ with self .subTest ("string attributes are the same" ):
172+ self .assertIs (element_foo2 .tag ,element_foo .tag )
173+ self .assertIs (element_foo2 .text ,element_foo .text )
174+ self .assertIs (element_foo2 .tail ,element_foo .tail )
175+
176+ with self .subTest ("string attributes are equal" ):
177+ self .assertEqual (element_foo2 .tag ,element_foo .tag )
178+ self .assertEqual (element_foo2 .text ,element_foo .text )
179+ self .assertEqual (element_foo2 .tail ,element_foo .tail )
180+
181+ with self .subTest ("children are the same" ):
182+ for (child1 ,child2 )in itertools .zip_longest (element_foo ,element_foo2 ):
183+ self .assertIs (child1 ,child2 )
184+
185+ with self .subTest ("attrib is a copy" ):
186+ self .assertEqual (element_foo2 .attrib ,element_foo .attrib )
187+
188+
189+ def test___deepcopy__ (self ):
190+ element_foo = ET .Element ("foo" , {"zix" :"wyp" })
191+ element_foo .append (ET .Element ("bar" , {"baz" :"qix" }))
192+
193+ element_foo2 = copy .deepcopy (element_foo )
194+
195+ with self .subTest ("elements are not the same" ):
196+ self .assertIsNot (element_foo2 ,element_foo )
197+
198+ # Strings should still be the same in a deep copy.
199+ with self .subTest ("string attributes are the same" ):
200+ self .assertIs (element_foo2 .tag ,element_foo .tag )
201+ self .assertIs (element_foo2 .text ,element_foo .text )
202+ self .assertIs (element_foo2 .tail ,element_foo .tail )
203+
204+ with self .subTest ("string attributes are equal" ):
205+ self .assertEqual (element_foo2 .tag ,element_foo .tag )
206+ self .assertEqual (element_foo2 .text ,element_foo .text )
207+ self .assertEqual (element_foo2 .tail ,element_foo .tail )
208+
209+ with self .subTest ("children are not the same" ):
210+ for (child1 ,child2 )in itertools .zip_longest (element_foo ,element_foo2 ):
211+ self .assertIsNot (child1 ,child2 )
212+
213+ with self .subTest ("attrib is a copy" ):
214+ self .assertIsNot (element_foo2 .attrib ,element_foo .attrib )
215+ self .assertEqual (element_foo2 .attrib ,element_foo .attrib )
216+
217+ with self .subTest ("attrib isn't linked" ):
218+ element_foo .attrib ["bar" ]= "baz"
219+
220+ self .assertIsNot (element_foo2 .attrib ,element_foo .attrib )
221+ self .assertNotEqual (element_foo2 .attrib ,element_foo .attrib )
222+
223+
224+ #-----------------------------------------------------------------------------
225+ # INTEGRATION TESTS
226+ #-----------------------------------------------------------------------------
227+
228+
125229def serialize (elem ,to_string = True ,encoding = 'unicode' ,** options ):
126230if encoding != 'unicode' :
127231file = io .BytesIO ()
@@ -1961,36 +2065,38 @@ def test_cyclic_gc(self):
19612065class Dummy :
19622066pass
19632067
1964- # Test the shortest cycle: d->element->d
1965- d = Dummy ()
1966- d .dummyref = ET .Element ('joe' ,attr = d )
1967- wref = weakref .ref (d )
1968- del d
1969- gc_collect ()
1970- self .assertIsNone (wref ())
1971-
1972- # A longer cycle: d->e->e2->d
1973- e = ET .Element ('joe' )
1974- d = Dummy ()
1975- d .dummyref = e
1976- wref = weakref .ref (d )
1977- e2 = ET .SubElement (e ,'foo' ,attr = d )
1978- del d ,e ,e2
1979- gc_collect ()
1980- self .assertIsNone (wref ())
1981-
1982- # A cycle between Element objects as children of one another
1983- # e1->e2->e3->e1
1984- e1 = ET .Element ('e1' )
1985- e2 = ET .Element ('e2' )
1986- e3 = ET .Element ('e3' )
1987- e1 .append (e2 )
1988- e2 .append (e2 )
1989- e3 .append (e1 )
1990- wref = weakref .ref (e1 )
1991- del e1 ,e2 ,e3
1992- gc_collect ()
1993- self .assertIsNone (wref ())
2068+ with self .subTest ("Test the shortest cycle: d->element->d" ):
2069+ d = Dummy ()
2070+ d .dummyref = ET .Element ('joe' ,attr = d )
2071+ wref = weakref .ref (d )
2072+ del d
2073+ gc_collect ()
2074+ self .assertIsNone (wref ())
2075+
2076+ with self .subTest ("A longer cycle: d->e->e2->d" ):
2077+ e = ET .Element ('joe' )
2078+ d = Dummy ()
2079+ d .dummyref = e
2080+ wref = weakref .ref (d )
2081+ e2 = ET .SubElement (e ,'foo' ,attr = d )
2082+ del d ,e ,e2
2083+ gc_collect ()
2084+ self .assertIsNone (wref ())
2085+
2086+ with self .subTest (
2087+ "A cycle between Element objects as children of one another: "
2088+ "e1->e2->e3->e1"
2089+ ):
2090+ e1 = ET .Element ('e1' )
2091+ e2 = ET .Element ('e2' )
2092+ e3 = ET .Element ('e3' )
2093+ e3 .append (e1 )
2094+ e2 .append (e3 )
2095+ e1 .append (e2 )
2096+ wref = weakref .ref (e1 )
2097+ del e1 ,e2 ,e3
2098+ gc_collect ()
2099+ self .assertIsNone (wref ())
19942100
19952101def test_weakref (self ):
19962102flag = False
@@ -3302,6 +3408,7 @@ def test_main(module=None):
33023408
33033409test_classes = [
33043410ModuleTest ,
3411+ ElementTree_Element_UnitTest ,
33053412ElementSlicingTest ,
33063413BasicElementTest ,
33073414BadElementTest ,