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