-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_nodes.py
290 lines (216 loc) · 8.39 KB
/
test_nodes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
import pytest
from _delb.nodes import _wrapper_cache
from delb import (
altered_default_filters,
is_tag_node,
is_text_node,
new_tag_node,
tag,
Document,
TagNode,
TextNode,
)
from delb.exceptions import InvalidOperation
def test_add_preceding_siblings():
root = Document("<root><e1/></root>").root
result = root[0].add_preceding_siblings(tag("e2"), tag("e3"))
assert str(root) == "<root><e3/><e2/><e1/></root>"
assert isinstance(result, tuple)
assert len(result) == 2
assert all(isinstance(n, TagNode) for n in result)
assert result[0].local_name == "e2"
assert result[1].local_name == "e3"
def test_add_following_siblings():
root = Document("<root><e1/></root>").root
result = root[0].add_following_siblings(tag("e2"), tag("e3"))
assert str(root) == "<root><e1/><e2/><e3/></root>"
assert isinstance(result, tuple)
assert len(result) == 2
assert all(isinstance(n, TagNode) for n in result)
assert result[0].local_name == "e2"
assert result[1].local_name == "e3"
def test_iterate_ancestors():
document = Document(
"<root><left/>abc<middle><node>0</node></middle><right>xyz<xyz"
"/></right></root>"
)
zero = document.root[2][0][0]
assert isinstance(zero, TextNode)
assert zero == "0"
assert tuple(x.local_name for x in zero.iterate_ancestors()) == (
"node",
"middle",
"root",
)
def test_ancestors_of_detached_node():
node = TextNode("x")
assert tuple(node.iterate_ancestors()) == ()
def test_comment_is_ignored():
root = Document("<root><a/><!-- bla --><b/></root>").root
a = root[0]
b = a.fetch_following_sibling()
assert isinstance(b, TagNode)
assert b.local_name == "b"
def test_index():
root = Document("<root><zero/>is<my/>country</root>").root
assert root.index is None
for index in range(4):
assert root[index].index == index
#
root = Document("<root><a/><!-- bla --><b/></root>").root
a = root[0]
assert isinstance(a, TagNode)
assert a.local_name == "a"
b = root[1]
assert isinstance(b, TagNode)
assert b.local_name == "b"
assert len(root) == 2
def test_insert_issue_in_a_more_complex_situation():
document = Document("<root><foo><div1><bar><div2/></bar> </div1></foo></root>")
for node in document.root.css_select("bar,foo"):
node.detach(retain_child_nodes=True)
assert str(document) == (
'<?xml version="1.0" encoding="UTF-8"?>' "<root><div1><div2/> </div1></root>"
)
def test_wrapper_consistency():
# this test is the result of an investigation that asked why
# `test_insert_issue_in_a_more_complex_situation` failed.
# as a result, the way how node wrapper are tracked has been refactored.
# so this test is looking on under-the-hood-expectations for aspects of the
# mentioned test. when maintaining this requires effort, it should rather be
# dropped.
def node_ids():
return {
"root": id(root),
"foo": id(foo),
"div1": id(div1),
"div2": id(div2),
"text": id(text),
}
with _wrapper_cache:
document = Document("<root><foo><div1><div2/>text</div1></foo></root>")
root = document.root
foo = root.first_child
div1 = foo.first_child
div2 = div1.first_child
text = div1.last_child
original_ids = node_ids()
div1.detach()
foo = root.first_child
div2 = div1.first_child
text = div1.last_child
assert node_ids() == original_ids
foo.detach()
assert node_ids() == original_ids
root.insert_children(0, div1)
div1 = root.first_child
div2 = div1.first_child
text = div1.last_child
assert node_ids() == original_ids
other_doc = Document(str(document))
div1 = other_doc.css_select("div1").first
div2 = other_doc.css_select("div2").first
div2.detach()
div1.insert_children(0, div2)
div1 = document.css_select("div1").first
div2 = document.css_select("div2").first
div2.detach()
div1 = root.first_child
text = div1.first_child
assert node_ids() == original_ids
div1.insert_children(0, div2)
def test_invalid_operations():
document_1 = Document("<root/>")
document_2 = Document("<root><replacement/>parts</root>")
with pytest.raises(InvalidOperation):
document_1.root.append_children(document_2.root[0])
new_node = new_tag_node("newNode")
document_1.root.append_children(new_node)
with pytest.raises(InvalidOperation):
new_node.add_following_siblings(document_2.root[0])
with pytest.raises(InvalidOperation):
new_node.add_preceding_siblings(document_2.root[0])
def test_iter_following_nodes_over_long_stream(files_path):
root = Document(files_path / "marx_manifestws_1848.TEI-P5.xml").root
node = root.fetch_following(lambda _: False)
assert node is None
all_node_locations = set()
for node in root.iterate_descendants(is_tag_node):
all_node_locations.add(node.location_path)
encountered_location_paths = set()
for node in root.iterate_following(is_tag_node):
location_path = node.location_path
assert location_path not in encountered_location_paths
encountered_location_paths.add(location_path)
assert encountered_location_paths == all_node_locations
expected_text = root.full_text # operates in tree dimension
collected_text = ""
for node in root.iterate_following(is_text_node):
collected_text += node.content
assert collected_text == expected_text
def test_no_following_node():
document = Document("<root><a/></root>")
assert document.root[0].fetch_following() is None
def test_no_preceding_node():
document = Document("<root><a/></root>")
assert document.root.fetch_preceding() is None
@pytest.mark.parametrize("yes_or_no", (True, False))
def test_parse(yes_or_no):
data = "<node>foo<child><!--bar--></child></node>"
if yes_or_no:
data = data.encode()
with pytest.deprecated_call():
node = TagNode.parse(data)
child = node.last_child
assert node.document is None
assert node.local_name == "node"
assert node.first_child.content == "foo"
assert child.local_name == "child"
with altered_default_filters():
assert child.first_child.content == "bar"
def test_replace_with():
root = Document("<root><a>b</a>c<d>e</d></root>").root
b_text = root[0][0]
b_text.replace_with(tag("b"))
expected_new = root[0][0]
assert b_text.parent is None
assert expected_new is not b_text
assert isinstance(expected_new, TagNode)
assert expected_new.local_name == "b"
assert str(root) == "<root><a><b/></a>c<d>e</d></root>"
c_text = root[1]
c_text.replace_with(tag("c"))
expected_new = root[1]
assert c_text.parent is None
assert expected_new is not c_text
assert isinstance(expected_new, TagNode)
assert expected_new.local_name == "c"
assert str(root) == "<root><a><b/></a><c/><d>e</d></root>"
with pytest.raises(InvalidOperation):
root.replace_with(tag("new"))
def test_replace_with_tag_definition():
root = Document('<root xmlns="https://name.space"><node/></root>').root
root.first_child.replace_with(tag("vertex", {"type": "xml"}))
assert root.first_child.namespace == "https://name.space"
assert str(root) == '<root xmlns="https://name.space"><vertex type="xml"/></root>'
def test_root_takes_no_siblings():
root = Document("<root/>").root
with pytest.raises(TypeError):
root.add_following_siblings(tag("x"))
with pytest.raises(TypeError):
root.add_following_siblings("x")
with pytest.raises(TypeError):
root.add_preceding_siblings(tag("x"))
with pytest.raises(TypeError):
root.add_preceding_siblings("x")
def test_siblings_filter():
document = Document("<root><e1/>ham<e2/>spam<e3/></root>")
root = document.root
e2 = root[2]
assert isinstance(e2.fetch_preceding_sibling(), TextNode)
assert isinstance(e2.fetch_following_sibling(), TextNode)
assert isinstance(e2.fetch_preceding_sibling(is_tag_node), TagNode)
assert isinstance(e2.fetch_following_sibling(is_tag_node), TagNode)
spam = root[3]
spam.add_following_siblings("plate")
assert isinstance(spam.fetch_following_sibling(is_tag_node), TagNode)