1 #ifndef PUGIXML_NO_XPATH
2 
3 #include "common.hpp"
4 
5 #include <string>
6 
TEST(xpath_variables_type_none)7 TEST(xpath_variables_type_none)
8 {
9 	xpath_variable_set set;
10 
11 	xpath_variable* var = set.add(STR("target"), xpath_type_none);
12 	CHECK(!var);
13 }
14 
TEST(xpath_variables_type_boolean)15 TEST(xpath_variables_type_boolean)
16 {
17 	xpath_variable_set set;
18 
19 	xpath_variable* var = set.add(STR("target"), xpath_type_boolean);
20 	CHECK(var);
21 
22 	CHECK(var->type() == xpath_type_boolean);
23 	CHECK_STRING(var->name(), STR("target"));
24 
25 	CHECK(var->get_boolean() == false);
26 	CHECK_DOUBLE_NAN(var->get_number());
27 	CHECK_STRING(var->get_string(), STR(""));
28 	CHECK(var->get_node_set().empty());
29 
30 	CHECK(var->set(true));
31 	CHECK(!var->set(1.0));
32 	CHECK(!var->set(STR("abc")));
33 	CHECK(!var->set(xpath_node_set()));
34 
35 	CHECK(var->get_boolean() == true);
36 	CHECK_DOUBLE_NAN(var->get_number());
37 	CHECK_STRING(var->get_string(), STR(""));
38 	CHECK(var->get_node_set().empty());
39 }
40 
TEST(xpath_variables_type_number)41 TEST(xpath_variables_type_number)
42 {
43 	xpath_variable_set set;
44 
45 	xpath_variable* var = set.add(STR("target"), xpath_type_number);
46 	CHECK(var);
47 
48 	CHECK(var->type() == xpath_type_number);
49 	CHECK_STRING(var->name(), STR("target"));
50 
51 	CHECK(var->get_boolean() == false);
52 	CHECK_DOUBLE(var->get_number(), 0);
53 	CHECK_STRING(var->get_string(), STR(""));
54 	CHECK(var->get_node_set().empty());
55 
56 	CHECK(!var->set(true));
57 	CHECK(var->set(1.0));
58 	CHECK(!var->set(STR("abc")));
59 	CHECK(!var->set(xpath_node_set()));
60 
61 	CHECK(var->get_boolean() == false);
62 	CHECK_DOUBLE(var->get_number(), 1);
63 	CHECK_STRING(var->get_string(), STR(""));
64 	CHECK(var->get_node_set().empty());
65 }
66 
TEST(xpath_variables_type_string)67 TEST(xpath_variables_type_string)
68 {
69 	xpath_variable_set set;
70 
71 	xpath_variable* var = set.add(STR("target"), xpath_type_string);
72 	CHECK(var);
73 
74 	CHECK(var->type() == xpath_type_string);
75 	CHECK_STRING(var->name(), STR("target"));
76 
77 	CHECK(var->get_boolean() == false);
78 	CHECK_DOUBLE_NAN(var->get_number());
79 	CHECK_STRING(var->get_string(), STR(""));
80 	CHECK(var->get_node_set().empty());
81 
82 	CHECK(!var->set(true));
83 	CHECK(!var->set(1.0));
84 	CHECK(var->set(STR("abc")));
85 	CHECK(!var->set(xpath_node_set()));
86 
87 	CHECK(var->get_boolean() == false);
88 	CHECK_DOUBLE_NAN(var->get_number());
89 	CHECK_STRING(var->get_string(), STR("abc"));
90 	CHECK(var->get_node_set().empty());
91 
92 	CHECK(var->set(STR("abcdef")));
93 	CHECK_STRING(var->get_string(), STR("abcdef"));
94 }
95 
96 TEST_XML(xpath_variables_type_node_set, "<node/>")
97 {
98 	xpath_variable_set set;
99 
100 	xpath_variable* var = set.add(STR("target"), xpath_type_node_set);
101 	CHECK(var);
102 
103 	CHECK(var->type() == xpath_type_node_set);
104 	CHECK_STRING(var->name(), STR("target"));
105 
106 	CHECK(var->get_boolean() == false);
107 	CHECK_DOUBLE_NAN(var->get_number());
108 	CHECK_STRING(var->get_string(), STR(""));
109 	CHECK(var->get_node_set().empty());
110 
111 	CHECK(!var->set(true));
112 	CHECK(!var->set(1.0));
113 	CHECK(!var->set(STR("abc")));
114 	CHECK(var->set(doc.select_nodes(STR("*"))));
115 
116 	CHECK(var->get_boolean() == false);
117 	CHECK_DOUBLE_NAN(var->get_number());
118 	CHECK_STRING(var->get_string(), STR(""));
119 	CHECK(var->get_node_set().size() == 1 && var->get_node_set()[0] == doc.first_child());
120 }
121 
TEST(xpath_variables_set_operations)122 TEST(xpath_variables_set_operations)
123 {
124 	xpath_variable_set set;
125 
126 	xpath_variable* v1 = set.add(STR("var1"), xpath_type_number);
127 	CHECK(v1);
128 
129 	xpath_variable* v2 = set.add(STR("var2"), xpath_type_string);
130 	CHECK(v2);
131 
132 	CHECK(v1 != v2);
133 
134 	CHECK(set.add(STR("var1"), xpath_type_number) == v1);
135 	CHECK(set.add(STR("var2"), xpath_type_string) == v2);
136 	CHECK(set.add(STR("var2"), xpath_type_node_set) == 0);
137 
138 	CHECK(set.get(STR("var1")) == v1);
139 	CHECK(set.get(STR("var2")) == v2);
140 	CHECK(set.get(STR("var")) == 0);
141 	CHECK(set.get(STR("var11")) == 0);
142 
143 	CHECK(static_cast<const xpath_variable_set&>(set).get(STR("var1")) == v1);
144 	CHECK(static_cast<const xpath_variable_set&>(set).get(STR("var3")) == 0);
145 }
146 
147 TEST_XML(xpath_variables_set_operations_set, "<node/>")
148 {
149 	xpath_variable_set set;
150 
151 	xpath_variable* v1 = set.add(STR("var1"), xpath_type_number);
152 	CHECK(v1);
153 
154 	xpath_variable* v2 = set.add(STR("var2"), xpath_type_string);
155 	CHECK(v2);
156 
157 	CHECK(set.set(STR("var1"), 1.0));
158 	CHECK_DOUBLE(v1->get_number(), 1.0);
159 
160 	CHECK(set.set(STR("var2"), STR("value")));
161 	CHECK_STRING(v2->get_string(), STR("value"));
162 
163 	CHECK(!set.set(STR("var1"), true));
164 
165 	CHECK(set.set(STR("var3"), doc.select_nodes(STR("*"))));
166 
167 	xpath_variable* v3 = set.get(STR("var3"));
168 
169 	CHECK(v3);
170 	CHECK(v3->type() == xpath_type_node_set);
171 	CHECK(v3->get_node_set().size() == 1);
172 }
173 
TEST(xpath_variables_set_out_of_memory)174 TEST(xpath_variables_set_out_of_memory)
175 {
176 	test_runner::_memory_fail_threshold = 1;
177 
178 	xpath_variable_set set;
179 
180 	xpath_variable* var = 0;
181 	CHECK_ALLOC_FAIL(var = set.add(STR("target"), xpath_type_number));
182 	CHECK(!var);
183 }
184 
TEST(xpath_variables_out_of_memory)185 TEST(xpath_variables_out_of_memory)
186 {
187 	test_runner::_memory_fail_threshold = 64;
188 
189 	xpath_variable_set set;
190 
191 	xpath_variable* var = set.add(STR("target"), xpath_type_string);
192 	CHECK(var);
193 
194 	CHECK_ALLOC_FAIL(CHECK(!var->set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))));
195 }
196 
197 TEST_XML(xpath_variables_evaluate, "<node/>")
198 {
199 	xpath_variable_set set;
200 	set.set(STR("var1"), true);
201 	set.set(STR("var2"), 0.5);
202 	set.set(STR("var3"), STR("value"));
203 	set.set(STR("var4"), doc.select_nodes(STR("*")));
204 
205 	CHECK_XPATH_BOOLEAN_VAR(doc, STR("$var1"), &set, true);
206 	CHECK_XPATH_NUMBER_VAR(doc, STR("$var2"), &set, 0.5);
207 	CHECK_XPATH_STRING_VAR(doc, STR("$var3"), &set, STR("value"));
208 	CHECK_XPATH_NODESET_VAR(doc, STR("$var4"), &set) % 2;
209 }
210 
211 TEST_XML(xpath_variables_evaluate_conversion, "<node>3</node>")
212 {
213 	xpath_variable_set set;
214 	set.set(STR("var"), doc.select_nodes(STR("*")));
215 
216 	CHECK_XPATH_BOOLEAN_VAR(doc, STR("$var"), &set, true);
217 	CHECK_XPATH_NUMBER_VAR(doc, STR("$var"), &set, 3);
218 	CHECK_XPATH_STRING_VAR(doc, STR("$var"), &set, STR("3"));
219 	CHECK_XPATH_NODESET_VAR(doc, STR("$var"), &set) % 2;
220 }
221 
TEST(xpath_variables_evaluate_node_set_fail)222 TEST(xpath_variables_evaluate_node_set_fail)
223 {
224 	xpath_variable_set set;
225 	set.set(STR("var"), false);
226 
227 	xpath_query q(STR("$var"), &set);
228 
229 #ifdef PUGIXML_NO_EXCEPTIONS
230 	CHECK(q.evaluate_node_set(xml_node()).empty());
231 #else
232 	try
233 	{
234 		q.evaluate_node_set(xml_node());
235 
236 		CHECK_FORCE_FAIL("Expected exception");
237 	}
238 	catch (const xpath_exception&)
239 	{
240 	}
241 #endif
242 }
243 
TEST(xpath_variables_multiple_documents)244 TEST(xpath_variables_multiple_documents)
245 {
246 	xml_document doc;
247 	doc.append_child().set_name(STR("node"));
248 
249 	xml_document doc1;
250 	doc1.append_child().set_name(STR("node"));
251 
252 	xml_document doc2;
253 	doc2.append_child().set_name(STR("node"));
254 
255 	xpath_variable_set set;
256 	set.set(STR("var1"), doc1.select_nodes(STR("*")));
257 	set.set(STR("var2"), doc2.select_nodes(STR("*")));
258 
259 	xpath_node_set ns = doc.select_nodes(STR("$var1 | $var2 | node"), &set);
260 	ns.sort();
261 
262 	CHECK(ns.size() == 3);
263 	CHECK(ns[0] != ns[1] && ns[0] != ns[2]);
264 
265 	xml_node n0 = doc.child(STR("node")), n1 = doc1.child(STR("node")), n2 = doc2.child(STR("node"));
266 
267 	CHECK(n0 == ns[0].node() || n0 == ns[1].node() || n0 == ns[2].node());
268 	CHECK(n1 == ns[0].node() || n1 == ns[1].node() || n1 == ns[2].node());
269 	CHECK(n2 == ns[0].node() || n2 == ns[1].node() || n2 == ns[2].node());
270 }
271 
TEST(xpath_variables_long_name)272 TEST(xpath_variables_long_name)
273 {
274 	xpath_variable_set set;
275 	set.set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), true);
276 
277 	CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set, true);
278 }
279 
TEST(xpath_variables_long_name_out_of_memory)280 TEST(xpath_variables_long_name_out_of_memory)
281 {
282 	xpath_variable_set set;
283 	set.set(STR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), true);
284 
285 	test_runner::_memory_fail_threshold = 4096 + 64 + 52 * sizeof(char_t);
286 
287 	CHECK_ALLOC_FAIL(CHECK(!xpath_query(STR("$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &set)));
288 }
289 
290 TEST_XML(xpath_variables_select, "<node attr='1'/><node attr='2'/>")
291 {
292 	xpath_variable_set set;
293 	set.set(STR("one"), 1.0);
294 
295 	xpath_node_set ns = doc.select_nodes(STR("node[@attr=$one+1]"), &set);
296 	CHECK(ns.size() == 1 && ns[0].node() == doc.last_child());
297 
298 	xpath_node n = doc.select_node(STR("node[@attr=$one+1]"), &set);
299 	CHECK(n == ns[0]);
300 }
301 
TEST(xpath_variables_empty_name)302 TEST(xpath_variables_empty_name)
303 {
304 	xpath_variable_set set;
305 	CHECK(!set.add(STR(""), xpath_type_number));
306 }
307 
308 TEST_XML(xpath_variables_inside_filter, "<node key='1' value='2'/><node key='2' value='1'/><node key='1' value='1'/>")
309 {
310 	xpath_variable_set set;
311 	set.set(STR("one"), 1.0);
312 
313 	xpath_node_set ns = doc.select_nodes(STR("(node[@key = $one])[@value = $one]"), &set);
314 	CHECK(ns.size() == 1 && ns[0].node() == doc.last_child());
315 }
316 
317 TEST_XML(xpath_variables_step, "<node><child/><child/><child><child/></child></node>")
318 {
319 	xpath_variable_set set;
320 	set.set(STR("root"), doc.select_nodes(STR("node")));
321 
322 	CHECK_XPATH_NODESET_VAR(xml_node(), STR("$root/child"), &set) % 3 % 4 % 5;
323 	CHECK_XPATH_NODESET_VAR(xml_node(), STR("$root//child"), &set) % 3 % 4 % 5 % 6;
324 }
325 
326 TEST_XML(xpath_variables_index, "<node><child/><child/><child><child/></child></node>")
327 {
328 	xpath_variable_set set;
329 	set.set(STR("index"), 2.0);
330 
331 	CHECK_XPATH_NODESET_VAR(doc, STR("node/child[$index]"), &set) % 4;
332 	CHECK_XPATH_NODESET_VAR(doc, STR("node/child[position()=$index]"), &set) % 4;
333 }
334 
TEST(xpath_variables_qname)335 TEST(xpath_variables_qname)
336 {
337 	xpath_variable_set set;
338 	set.set(STR("foo:bar"), true);
339 
340 	CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$foo:bar"), &set, true);
341 }
342 
TEST(xpath_variables_name_error)343 TEST(xpath_variables_name_error)
344 {
345 	xpath_variable_set set;
346 	set.set(STR("foo:"), true);
347 	set.set(STR(":bar"), true);
348 	set.set(STR("foo:*"), true);
349 	set.set(STR("foo"), true);
350 	set.set(STR("3"), true);
351 
352 	CHECK_XPATH_FAIL_VAR(STR("$foo:"), &set);
353 	CHECK_XPATH_FAIL_VAR(STR("$:bar"), &set);
354 	CHECK_XPATH_FAIL_VAR(STR("$foo:*"), &set);
355 	CHECK_XPATH_FAIL_VAR(STR("$foo:bar:baz"), &set);
356 	CHECK_XPATH_FAIL_VAR(STR("$ foo"), &set);
357 
358 	CHECK_XPATH_FAIL_VAR(STR("$3"), &set);
359 }
360 
TEST(xpath_variables_empty_string)361 TEST(xpath_variables_empty_string)
362 {
363 	xpath_variable_set set;
364 	set.add(STR("empty"), xpath_type_string);
365 
366 	CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$empty = substring-before('a', 'z')"), &set, true);
367 }
368 
TEST(xpath_variables_name_underscore)369 TEST(xpath_variables_name_underscore)
370 {
371 	xpath_variable_set set;
372 	set.set(STR("_foo_bar"), true);
373 
374 	CHECK_XPATH_BOOLEAN_VAR(xml_node(), STR("$_foo_bar"), &set, true);
375 }
376 
TEST(xpath_variables_name_case)377 TEST(xpath_variables_name_case)
378 {
379 	xpath_variable_set set;
380 	set.set(STR("i"), 5.0);
381 	set.set(STR("I"), 2.0);
382 
383 	CHECK_XPATH_NUMBER_VAR(xml_node(), STR("$i div $I"), &set, 2.5);
384 }
385 
TEST(xpath_variables_name_unicode)386 TEST(xpath_variables_name_unicode)
387 {
388 #ifdef PUGIXML_WCHAR_MODE
389 	#ifdef U_LITERALS
390 		const char_t* name = L"\u0400\u203D";
391 	#else
392 		const char_t* name = L"\x0400\x203D";
393 	#endif
394 #else
395 	const char_t* name = "\xd0\x80\xe2\x80\xbd";
396 #endif
397 
398 	xpath_variable_set set;
399 	set.set(name, STR("value"));
400 
401 	std::basic_string<char_t> var = STR("$");
402 	var += name;
403 
404 	CHECK_XPATH_STRING_VAR(xml_node(), var.c_str(), &set, STR("value"));
405 }
406 
407 TEST_XML(xpath_variables_count_sum, "<node><c1>12</c1><c2>23</c2><c3>34</c3></node>")
408 {
409 	xpath_variable_set set;
410 	set.set(STR("c12"), doc.select_nodes(STR("node/c1 | node/c2")));
411 	set.set(STR("c3"), doc.select_nodes(STR("node/c3")));
412 	set.set(STR("c"), doc.select_nodes(STR("node/*")));
413 
414 	CHECK_XPATH_NUMBER_VAR(xml_node(), STR("sum($c12) * count($c) - sum($c3)"), &set, 71);
415 }
416 
417 TEST_XML(xpath_variables_copy, "<node />")
418 {
419 	xpath_variable_set set1;
420 	set1.set(STR("a"), true);
421 	set1.set(STR("b"), 2.0);
422 	set1.set(STR("c"), STR("string"));
423 	set1.set(STR("d"), doc.select_nodes(STR("//*")));
424 
425 	CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set1, STR("ring"));
426 
427 	xpath_variable_set set2 = set1;
428 
429 	CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set2, STR("ring"));
430 
431 	xpath_variable_set set3;
432 
433 	CHECK(!set3.get(STR("a")));
434 
435 	set3 = set1;
436 
437 	CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set2, STR("ring"));
438 
439 	set3 = set3;
440 
441 	CHECK_XPATH_STRING_VAR(xml_node(), STR("substring($c, count($d[$a]) + $b)"), &set2, STR("ring"));
442 
443 	set3 = xpath_variable_set();
444 
445 	CHECK(!set3.get(STR("a")));
446 }
447 
448 TEST_XML(xpath_variables_copy_out_of_memory, "<node1 /><node2 />")
449 {
450 	xpath_variable_set set1;
451 	set1.set(STR("a"), true);
452 	set1.set(STR("b"), 2.0);
453 	set1.set(STR("c"), STR("string"));
454 	set1.set(STR("d"), doc.select_nodes(STR("//*")));
455 
456 	xpath_variable_set set2 = set1;
457 
458 	test_runner::_memory_fail_threshold = 32768 + 75 * sizeof(void*);
459 
460 	CHECK_ALLOC_FAIL(xpath_variable_set set3 = set1);
461 
462 	xpath_variable_set set4;
463 
464 	CHECK_ALLOC_FAIL(set4 = set1);
465 	CHECK(!set4.get(STR("a")) && !set4.get(STR("b")) && !set4.get(STR("c")) && !set4.get(STR("d")));
466 
467 	CHECK_ALLOC_FAIL(set2 = set1);
468 
469 	CHECK(set2.get(STR("a")) && set2.get(STR("b")) && set2.get(STR("c")) && set2.get(STR("d")));
470 
471 	CHECK(set2.get(STR("a"))->get_boolean() == true);
472 	CHECK(set2.get(STR("b"))->get_number() == 2.0);
473 	CHECK_STRING(set2.get(STR("c"))->get_string(), STR("string"));
474 	CHECK(set2.get(STR("d"))->get_node_set().size() == 2);
475 }
476 
477 #if __cplusplus >= 201103
478 TEST_XML(xpath_variables_move, "<node />")
479 {
480 	xpath_variable_set set;
481 	set.set(STR("a"), true);
482 	set.set(STR("b"), 2.0);
483 	set.set(STR("c"), STR("string"));
484 	set.set(STR("d"), doc.select_nodes(STR("//*")));
485 
486 	xpath_variable_set copy = set;
487 	copy.set(STR("e"), 42.0);
488 
489 	test_runner::_memory_fail_threshold = 1;
490 
491 	xpath_variable_set move1 = std::move(set);
492 
493 	CHECK(!set.get(STR("a")) && !set.get(STR("b")) && !set.get(STR("c")) && !set.get(STR("d")));
494 	CHECK(move1.get(STR("a")) && move1.get(STR("b")) && move1.get(STR("c")) && move1.get(STR("d")));
495 
496 	CHECK(move1.get(STR("a"))->get_boolean() == true);
497 	CHECK(move1.get(STR("b"))->get_number() == 2.0);
498 	CHECK_STRING(move1.get(STR("c"))->get_string(), STR("string"));
499 	CHECK(move1.get(STR("d"))->get_node_set().size() == 1);
500 
501 	xpath_variable_set move2;
502 	move2 = std::move(move1);
503 
504 	CHECK(!move1.get(STR("a")) && !move1.get(STR("b")) && !move1.get(STR("c")) && !move1.get(STR("d")));
505 	CHECK(move2.get(STR("a")) && move2.get(STR("b")) && move2.get(STR("c")) && move2.get(STR("d")));
506 
507 	CHECK(copy.get(STR("e")));
508 
509 	copy = std::move(move2);
510 
511 	CHECK(!move2.get(STR("a")) && !move2.get(STR("b")) && !move2.get(STR("c")) && !move2.get(STR("d")));
512 	CHECK(copy.get(STR("a")) && copy.get(STR("b")) && copy.get(STR("c")) && copy.get(STR("d")));
513 	CHECK(!copy.get(STR("e")));
514 
515 	CHECK(copy.get(STR("a"))->get_boolean() == true);
516 	CHECK(copy.get(STR("b"))->get_number() == 2.0);
517 	CHECK_STRING(copy.get(STR("c"))->get_string(), STR("string"));
518 	CHECK(copy.get(STR("d"))->get_node_set().size() == 1);
519 }
520 #endif
521 
TEST(xpath_variables_copy_big)522 TEST(xpath_variables_copy_big)
523 {
524 	xpath_variable_set set;
525 
526 	for (int i = 0; i < 100; ++i)
527 	{
528 		char_t name[4];
529 		name[0] = 'a';
530 		name[1] = char_t('0' + i / 10);
531 		name[2] = char_t('0' + i % 10);
532 		name[3] = 0;
533 
534 		set.set(name, double(i));
535 	}
536 
537 	xpath_variable_set copy = set;
538 
539 	for (int j = 0; j < 100; ++j)
540 	{
541 		char_t name[4];
542 		name[0] = 'a';
543 		name[1] = char_t('0' + j / 10);
544 		name[2] = char_t('0' + j % 10);
545 		name[3] = 0;
546 
547 		CHECK(copy.get(name) && copy.get(name)->get_number() == j);
548 	}
549 }
550 
TEST(xpath_variables_copy_big_out_of_memory)551 TEST(xpath_variables_copy_big_out_of_memory)
552 {
553 	xpath_variable_set set;
554 
555 	for (int i = 0; i < 100; ++i)
556 	{
557 		char_t name[4];
558 		name[0] = 'a';
559 		name[1] = char_t('0' + i / 10);
560 		name[2] = char_t('0' + i % 10);
561 		name[3] = 0;
562 
563 		set.set(name, double(i));
564 	}
565 
566 	test_runner::_memory_fail_threshold = 1;
567 
568 	xpath_variable_set copy;
569 	CHECK_ALLOC_FAIL(copy = set);
570 
571 	for (int j = 0; j < 100; ++j)
572 	{
573 		char_t name[4];
574 		name[0] = 'a';
575 		name[1] = char_t('0' + j / 10);
576 		name[2] = char_t('0' + j % 10);
577 		name[3] = 0;
578 
579 		CHECK(!copy.get(name));
580 	}
581 }
582 #endif
583