1 // Copyright 2018 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/fxcrt/fx_string.h"
6 #include "core/fxcrt/xml/cfx_xmlelement.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8
9 namespace {
10
ChildrenString(CFX_XMLElement * pParent)11 WideString ChildrenString(CFX_XMLElement* pParent) {
12 WideString result;
13 for (CFX_XMLNode* pChild = pParent->GetFirstChild(); pChild;
14 pChild = pChild->GetNextSibling()) {
15 result += static_cast<CFX_XMLElement*>(pChild)->GetName();
16 }
17 return result;
18 }
19
ReverseChildrenString(CFX_XMLElement * pParent)20 WideString ReverseChildrenString(CFX_XMLElement* pParent) {
21 WideString result;
22 for (CFX_XMLNode* pChild = pParent->GetLastChild(); pChild;
23 pChild = pChild->GetPrevSibling()) {
24 result = static_cast<CFX_XMLElement*>(pChild)->GetName() + result;
25 }
26 return result;
27 }
28
29 } // namespace
30
TEST(CFX_XMLNodeTest,GetParent)31 TEST(CFX_XMLNodeTest, GetParent) {
32 CFX_XMLElement node1(L"node");
33 CFX_XMLElement node2(L"node2");
34 CFX_XMLElement node3(L"node3");
35
36 node1.AppendLastChild(&node2);
37 node2.AppendLastChild(&node3);
38
39 EXPECT_EQ(nullptr, node1.GetParent());
40 EXPECT_EQ(&node1, node2.GetParent());
41 EXPECT_EQ(&node2, node3.GetParent());
42 }
43
TEST(CFX_XMLNodeTest,GetRoot)44 TEST(CFX_XMLNodeTest, GetRoot) {
45 CFX_XMLElement node1(L"node");
46 CFX_XMLElement node2(L"node2");
47 CFX_XMLElement node3(L"node3");
48
49 node1.AppendLastChild(&node2);
50 node2.AppendLastChild(&node3);
51
52 EXPECT_EQ(&node1, node1.GetRoot());
53 EXPECT_EQ(&node1, node2.GetRoot());
54 EXPECT_EQ(&node1, node3.GetRoot());
55 }
56
TEST(CFX_XMLNodeTest,GetChildren)57 TEST(CFX_XMLNodeTest, GetChildren) {
58 CFX_XMLElement node1(L"node");
59 CFX_XMLElement node2(L"node2");
60 CFX_XMLElement node3(L"node3");
61 CFX_XMLElement node4(L"node4");
62
63 node1.AppendLastChild(&node2);
64 node1.AppendLastChild(&node4);
65 node2.AppendLastChild(&node3);
66
67 EXPECT_EQ(&node2, node1.GetFirstChild());
68
69 EXPECT_EQ(&node4, node2.GetNextSibling());
70 EXPECT_EQ(&node3, node2.GetFirstChild());
71
72 EXPECT_TRUE(node3.GetNextSibling() == nullptr);
73 EXPECT_TRUE(node3.GetFirstChild() == nullptr);
74
75 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
76 EXPECT_TRUE(node4.GetFirstChild() == nullptr);
77 }
78
TEST(CFX_XMLNodeTest,DeleteChildren)79 TEST(CFX_XMLNodeTest, DeleteChildren) {
80 CFX_XMLElement node1(L"node");
81 CFX_XMLElement node2(L"node2");
82 CFX_XMLElement node3(L"node3");
83 CFX_XMLElement node4(L"node4");
84
85 node1.AppendLastChild(&node2);
86 node1.AppendLastChild(&node4);
87 node2.AppendLastChild(&node3);
88
89 node1.RemoveAllChildren();
90 EXPECT_TRUE(node1.GetFirstChild() == nullptr);
91 EXPECT_TRUE(node2.GetParent() == nullptr);
92 EXPECT_TRUE(node4.GetParent() == nullptr);
93
94 // node2 and node4 should no longer be siblings.
95 EXPECT_TRUE(node2.GetNextSibling() == nullptr);
96 EXPECT_TRUE(node4.GetPrevSibling() == nullptr);
97
98 // Deleting children doesn't change deleted substructure
99 EXPECT_EQ(&node3, node2.GetFirstChild());
100 EXPECT_TRUE(node3.GetParent() == &node2);
101 }
102
TEST(CFX_XMLNodeTest,AddingChildren)103 TEST(CFX_XMLNodeTest, AddingChildren) {
104 CFX_XMLElement parent(L"Root");
105 CFX_XMLElement nodeA(L"A");
106 CFX_XMLElement nodeB(L"B");
107
108 parent.AppendLastChild(&nodeA);
109 parent.AppendLastChild(&nodeB);
110
111 EXPECT_EQ(L"AB", ChildrenString(&parent));
112 EXPECT_EQ(L"AB", ReverseChildrenString(&parent));
113 EXPECT_EQ(&parent, nodeA.GetParent());
114 EXPECT_EQ(&parent, nodeB.GetParent());
115 EXPECT_EQ(&nodeA, parent.GetFirstChild());
116 EXPECT_EQ(&nodeB, nodeA.GetNextSibling());
117 EXPECT_TRUE(nodeB.GetNextSibling() == nullptr);
118
119 // Insert to negative appends last child.
120 CFX_XMLElement nodeC(L"C");
121 parent.InsertChildNode(&nodeC, -1);
122 EXPECT_EQ(L"ABC", ChildrenString(&parent));
123 EXPECT_EQ(L"ABC", ReverseChildrenString(&parent));
124 EXPECT_EQ(&parent, nodeC.GetParent());
125 EXPECT_EQ(&nodeC, nodeB.GetNextSibling());
126 EXPECT_TRUE(nodeC.GetNextSibling() == nullptr);
127
128 // Insertion occurs before a zero based index.
129 CFX_XMLElement nodeD(L"D");
130 parent.InsertChildNode(&nodeD, 1);
131 EXPECT_EQ(L"ADBC", ChildrenString(&parent));
132 EXPECT_EQ(L"ADBC", ReverseChildrenString(&parent));
133
134 // Insert to 0 appends first child.
135 CFX_XMLElement nodeE(L"E");
136 parent.InsertChildNode(&nodeE, 0);
137 EXPECT_EQ(L"EADBC", ChildrenString(&parent));
138 EXPECT_EQ(L"EADBC", ReverseChildrenString(&parent));
139
140 // Insert to out-of-bounds index appends last child.
141 CFX_XMLElement nodeF(L"F");
142 parent.InsertChildNode(&nodeF, 10);
143 EXPECT_EQ(L"EADBCF", ChildrenString(&parent));
144 EXPECT_EQ(L"EADBCF", ReverseChildrenString(&parent));
145 }
146
TEST(CFX_XMLNodeTest,RemovingMiddleChild)147 TEST(CFX_XMLNodeTest, RemovingMiddleChild) {
148 CFX_XMLElement node1(L"node1");
149 CFX_XMLElement node2(L"node2");
150 CFX_XMLElement node3(L"node3");
151 CFX_XMLElement node4(L"node4");
152
153 node1.AppendLastChild(&node2);
154 node1.AppendLastChild(&node3);
155 node1.AppendLastChild(&node4);
156
157 EXPECT_EQ(L"node2node3node4", ChildrenString(&node1));
158 EXPECT_EQ(L"node2node3node4", ReverseChildrenString(&node1));
159 EXPECT_EQ(&node2, node1.GetFirstChild());
160 EXPECT_EQ(&node3, node2.GetNextSibling());
161 EXPECT_EQ(&node4, node3.GetNextSibling());
162 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
163
164 node1.RemoveChild(&node3);
165
166 EXPECT_EQ(L"node2node4", ChildrenString(&node1));
167 EXPECT_EQ(L"node2node4", ReverseChildrenString(&node1));
168 EXPECT_TRUE(node3.GetParent() == nullptr);
169 EXPECT_TRUE(node3.GetNextSibling() == nullptr);
170 EXPECT_TRUE(node3.GetPrevSibling() == nullptr);
171 EXPECT_EQ(&node2, node1.GetFirstChild());
172 EXPECT_EQ(&node4, node2.GetNextSibling());
173 EXPECT_EQ(&node2, node4.GetPrevSibling());
174 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
175 }
176
TEST(CFX_XMLNodeTest,RemovingFirstChild)177 TEST(CFX_XMLNodeTest, RemovingFirstChild) {
178 CFX_XMLElement node1(L"node1");
179 CFX_XMLElement node2(L"node2");
180 CFX_XMLElement node3(L"node3");
181 CFX_XMLElement node4(L"node4");
182
183 node1.AppendLastChild(&node2);
184 node1.AppendLastChild(&node3);
185 node1.AppendLastChild(&node4);
186
187 EXPECT_EQ(L"node2node3node4", ChildrenString(&node1));
188 EXPECT_EQ(L"node2node3node4", ReverseChildrenString(&node1));
189 EXPECT_EQ(&node2, node1.GetFirstChild());
190 EXPECT_EQ(&node3, node2.GetNextSibling());
191 EXPECT_EQ(&node4, node3.GetNextSibling());
192 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
193
194 node1.RemoveChild(&node2);
195
196 EXPECT_EQ(L"node3node4", ChildrenString(&node1));
197 EXPECT_EQ(L"node3node4", ReverseChildrenString(&node1));
198 EXPECT_TRUE(node2.GetParent() == nullptr);
199 EXPECT_TRUE(node2.GetNextSibling() == nullptr);
200 EXPECT_TRUE(node2.GetPrevSibling() == nullptr);
201 EXPECT_EQ(&node3, node1.GetFirstChild());
202 EXPECT_TRUE(node3.GetPrevSibling() == nullptr);
203 EXPECT_EQ(&node4, node3.GetNextSibling());
204 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
205 }
206
TEST(CFX_XMLNodeTest,RemovingLastChild)207 TEST(CFX_XMLNodeTest, RemovingLastChild) {
208 CFX_XMLElement node1(L"node1");
209 CFX_XMLElement node2(L"node2");
210 CFX_XMLElement node3(L"node3");
211 CFX_XMLElement node4(L"node4");
212
213 node1.AppendLastChild(&node2);
214 node1.AppendLastChild(&node3);
215 node1.AppendLastChild(&node4);
216
217 EXPECT_EQ(L"node2node3node4", ChildrenString(&node1));
218 EXPECT_EQ(L"node2node3node4", ReverseChildrenString(&node1));
219 EXPECT_EQ(&node2, node1.GetFirstChild());
220 EXPECT_EQ(&node3, node2.GetNextSibling());
221 EXPECT_EQ(&node4, node3.GetNextSibling());
222 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
223
224 node1.RemoveChild(&node4);
225
226 EXPECT_EQ(L"node2node3", ChildrenString(&node1));
227 EXPECT_EQ(L"node2node3", ReverseChildrenString(&node1));
228 EXPECT_TRUE(node4.GetParent() == nullptr);
229 EXPECT_TRUE(node4.GetNextSibling() == nullptr);
230 EXPECT_TRUE(node4.GetPrevSibling() == nullptr);
231 EXPECT_EQ(&node2, node1.GetFirstChild());
232 EXPECT_EQ(&node3, node2.GetNextSibling());
233 EXPECT_TRUE(node3.GetNextSibling() == nullptr);
234 }
235
TEST(CFX_XMLNodeTest,RemovingOnlyChild)236 TEST(CFX_XMLNodeTest, RemovingOnlyChild) {
237 CFX_XMLElement node1(L"node1");
238 CFX_XMLElement node2(L"node2");
239
240 node1.AppendLastChild(&node2);
241
242 EXPECT_EQ(&node2, node1.GetFirstChild());
243 EXPECT_TRUE(node2.GetNextSibling() == nullptr);
244
245 node1.RemoveChild(&node2);
246 EXPECT_TRUE(node2.GetParent() == nullptr);
247
248 EXPECT_TRUE(node1.GetFirstChild() == nullptr);
249 EXPECT_TRUE(node2.GetNextSibling() == nullptr);
250 EXPECT_TRUE(node2.GetPrevSibling() == nullptr);
251 }
252
TEST(CFX_XMLNodeTest,RemoveMissingChild)253 TEST(CFX_XMLNodeTest, RemoveMissingChild) {
254 CFX_XMLElement node1(L"node1");
255 CFX_XMLElement node2(L"node2");
256 CFX_XMLElement node3(L"node3");
257
258 node1.AppendLastChild(&node2);
259 EXPECT_DEATH(node1.RemoveChild(&node3), "");
260 }
261