1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html.xpath;
16
17 import org.htmlunit.WebDriverTestCase;
18 import org.htmlunit.junit.annotation.Alerts;
19 import org.junit.jupiter.api.Test;
20
21
22
23
24
25
26
27
28 public class HtmlUnitXPath2Test extends WebDriverTestCase {
29
30
31
32
33 @Override
34 protected boolean isWebClientCached() {
35 return true;
36 }
37
38
39
40
41 @Test
42 @Alerts({"4", "null"})
43 public void xPathNull() throws Exception {
44 final String content = DOCTYPE_HTML
45 + "<html><head>\n"
46 + "<script>\n"
47 + LOG_TITLE_FUNCTION
48 + "function test() {\n"
49 + " try {\n"
50 + " var node = '';"
51 + " var expr = null;\n"
52 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
53 + " node = result.iterateNext();\n"
54 + " log(result.resultType);\n"
55 + " log(node);\n"
56 + " } catch(e) { logEx(e) }\n"
57 + "}\n"
58 + "</script></head>\n"
59 + "<body onload='test()'>\n"
60 + " <select name='test'><option value='1'>foo and foo</option></select>\n"
61 + "</body></html>";
62
63 loadPageVerifyTitle2(content);
64 }
65
66
67
68
69 @Test
70 @Alerts({"4", "null"})
71 public void xPathUndefined() throws Exception {
72 final String content = DOCTYPE_HTML
73 + "<html><head>\n"
74 + "<script>\n"
75 + LOG_TITLE_FUNCTION
76 + "function test() {\n"
77 + " try {\n"
78 + " var node = '';"
79 + " var expr = undefined;\n"
80 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
81 + " node = result.iterateNext();\n"
82 + " log(result.resultType);\n"
83 + " log(node);\n"
84 + " } catch(e) { logEx(e) }\n"
85 + "}\n"
86 + "</script></head>\n"
87 + "<body onload='test()'>\n"
88 + " <select name='test'><option value='1'>foo and foo</option></select>\n"
89 + "</body></html>";
90
91 loadPageVerifyTitle2(content);
92 }
93
94
95
96
97 @Test
98 @Alerts({"102", "111", "111", "160", "97", "110", "100", "160", "102", "111", "111"})
99 public void optionText() throws Exception {
100 final String content = DOCTYPE_HTML
101 + "<html><head>\n"
102 + "<script>\n"
103 + LOG_TITLE_FUNCTION
104 + "function test() {\n"
105 + " try {\n"
106 + " var expr = 'string(//option)';\n"
107 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
108 + " var value = result.stringValue;\n"
109 + " for (var i = 0; i < value.length; i++) {\n"
110 + " log(value.charCodeAt(i));\n"
111 + " }\n"
112 + " } catch(e) { logEx(e) }\n"
113 + "}\n"
114 + "</script></head>\n"
115 + "<body onload='test()'>\n"
116 + " <select name='test'><option value='1'>foo and foo</option></select>\n"
117 + "</body></html>";
118
119 loadPageVerifyTitle2(content);
120 }
121
122
123
124
125 @Test
126 @Alerts("[object HTMLParagraphElement][object HTMLDivElement]")
127 public void pipe() throws Exception {
128 final String content = DOCTYPE_HTML
129 + "<html>\n"
130 + "<head>\n"
131 + "<script>\n"
132 + LOG_TITLE_FUNCTION
133 + "function test() {\n"
134 + " try {\n"
135 + " var res = '';"
136 + " var expr = '//p | //div';\n"
137 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
138 + " while (node = result.iterateNext()) {\n"
139 + " res += node;\n"
140 + " }\n"
141 + " log(res);\n"
142 + " } catch(e) { logEx(e) }\n"
143 + "}\n"
144 + "</script></head>\n"
145 + "<body onload='test()'>\n"
146 + " <p></p>\n"
147 + " <div></div>\n"
148 + "</body></html>";
149
150 loadPageVerifyTitle2(content);
151 }
152
153
154
155
156 @Test
157 @Alerts("a")
158 public void math() throws Exception {
159 final String content = DOCTYPE_HTML
160 + "<html>\n"
161 + "<head>\n"
162 + "<script>\n"
163 + LOG_TITLE_FUNCTION
164 + "function test() {\n"
165 + " try {\n"
166 + " var res = '';"
167 + " var expr = '//p[position()=(1+5-(2*2))div 2]';\n"
168 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
169 + " while (node = result.iterateNext()) {\n"
170 + " res += node.id;\n"
171 + " }\n"
172 + " log(res);\n"
173 + " } catch(e) { logEx(e) }\n"
174 + "}\n"
175 + "</script></head>\n"
176 + "<body onload='test()'>\n"
177 + " <div>\n"
178 + " <p id='a'></p>\n"
179 + " <p id='b'></p>\n"
180 + " </div>\n"
181 + "</body></html>";
182
183 loadPageVerifyTitle2(content);
184 }
185
186
187
188
189 @Test
190 @Alerts("b")
191 public void gt() throws Exception {
192 compare("//p[position()>1]");
193 }
194
195
196
197
198 @Test
199 @Alerts("ab")
200 public void gte() throws Exception {
201 compare("//p[position()>=1]");
202 }
203
204
205
206
207 @Test
208 @Alerts("a")
209 public void lt() throws Exception {
210 compare("//p[position()<2]");
211 }
212
213
214
215
216 @Test
217 @Alerts("ab")
218 public void lte() throws Exception {
219 compare("//p[position()<=2]");
220 }
221
222
223
224
225 @Test
226 @Alerts("b")
227 public void eq() throws Exception {
228 compare("//p[position()=2]");
229 }
230
231
232
233
234 @Test
235 @Alerts("b")
236 public void neq() throws Exception {
237 compare("//p[position()!=1]");
238 }
239
240
241
242
243 @Test
244 @Alerts("a")
245 public void and() throws Exception {
246 compare("//p[@x>= 0 and @y=7]");
247 }
248
249
250
251
252 @Test
253 @Alerts("ab")
254 public void or() throws Exception {
255 compare("//p[@x>= 0 or @y>4]");
256 }
257
258
259
260
261 @Test
262 @Alerts("ab")
263 public void mod() throws Exception {
264 compare("//p[@y mod 6 = 1]");
265 }
266
267
268
269
270 @Test
271 @Alerts("'adc'")
272 public void translate() throws Exception {
273 compareStringValue("translate(\"abc\", \"b\", \"d\")");
274 }
275
276
277
278
279 @Test
280 @Alerts("true")
281 public void trueTest() throws Exception {
282 compareBooleanValue("true()");
283 }
284
285
286
287
288 @Test
289 @Alerts("false")
290 public void falseTest() throws Exception {
291 compareBooleanValue("false()");
292 }
293
294
295
296
297 @Test
298 @Alerts("true")
299 public void booleanTest() throws Exception {
300 compareBooleanValue("boolean(7)");
301 }
302
303
304
305
306 @Test
307 @Alerts("false")
308 public void booleanTestFalse() throws Exception {
309 compareBooleanValue("boolean(0)");
310 }
311
312
313
314
315 @Test
316 @Alerts("b")
317 public void number() throws Exception {
318 compare("//p[@y=number(\" 13\t \")]");
319 }
320
321
322
323
324 @Test
325 @Alerts("false")
326 public void startsWith() throws Exception {
327 compareBooleanValue("starts-with(\"haystack\", \"needle\")");
328 }
329
330
331
332
333 @Test
334 @Alerts("true")
335 public void startsWithFound() throws Exception {
336 compareBooleanValue("starts-with(\"haystack\", \"hay\")");
337 }
338
339
340
341
342 @Test
343 @Alerts("true")
344 public void startsWithWhole() throws Exception {
345 compareBooleanValue("starts-with(\"haystack\", \"haystack\")");
346 }
347
348
349
350
351 @Test
352 @Alerts("true")
353 public void startsWithEmpty() throws Exception {
354 compareBooleanValue("starts-with(\"haystack\", \"\")");
355 }
356
357
358
359
360 @Test
361 @Alerts("true")
362 public void startsWithEmptyEmpty() throws Exception {
363 compareBooleanValue("starts-with(\"\", \"\")");
364 }
365
366
367
368
369 @Test
370 @Alerts("'tml'")
371 public void substring() throws Exception {
372 compareStringValue("substring(\"HtmlUnit\", 2, 3)");
373 }
374
375
376
377
378 @Test
379 @Alerts("''")
380 public void substringWithNegativeLength() throws Exception {
381 compareStringValue("substring(\"HtmlUnit\", 2, -1)");
382 }
383
384
385
386
387 @Test
388 @Alerts("''")
389 public void substringNegativeStartWithLength() throws Exception {
390 compareStringValue("substring(\"HtmlUnit\", -50, 20)");
391 }
392
393
394
395
396 @Test
397 @Alerts("'Unit'")
398 public void substringAfter() throws Exception {
399 compareStringValue("substring-after(\"HtmlUnit\", \"tml\")");
400 }
401
402
403
404
405 @Test
406 @Alerts("'Html'")
407 public void substringBefore() throws Exception {
408 compareStringValue("substring-before(\"HtmlUnit\", \"Uni\")");
409 }
410
411
412
413
414 @Test
415 @Alerts("false")
416 public void not() throws Exception {
417 compareBooleanValue("not(\"HtmlUnit\")");
418 }
419
420
421
422
423 @Test
424 @Alerts("a")
425 public void attrib() throws Exception {
426 compare("//p[@x=1]");
427 }
428
429
430
431
432 @Test
433 @Alerts("SyntaxError/DOMException")
434 public void lowerCaseNotSupported() throws Exception {
435 compareError("//*[lower-case(@id) = \"a\"]");
436 }
437
438
439
440
441 @Test
442 @Alerts("SyntaxError/DOMException")
443 public void upperCaseNotSupported() throws Exception {
444 compareError("//*[upper-case(@id) = \"A\"]");
445 }
446
447
448
449
450 @Test
451 @Alerts("SyntaxError/DOMException")
452 public void endsWithNotSupported() throws Exception {
453 compareError("ends-with(\"haystack\", \"haystack\")");
454 }
455
456 private void compare(final String xpath) throws Exception {
457 final String content = DOCTYPE_HTML
458 + "<html>\n"
459 + "<head>\n"
460 + "<script>\n"
461 + LOG_TITLE_FUNCTION
462 + "function test() {\n"
463 + " try {\n"
464 + " var res = '';\n"
465 + " var expr = '" + xpath + "';\n"
466 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
467 + " while (node = result.iterateNext()) {\n"
468 + " res += node.id;\n"
469 + " }\n"
470 + " log(res);\n"
471 + " } catch(e) { logEx(e) }\n"
472 + "}\n"
473 + "</script></head>\n"
474 + "<body onload='test()'>\n"
475 + " <div>\n"
476 + " <p id='a' x='1' y='7'></p>\n"
477 + " <p id='b' y='13'></p>\n"
478 + " </div>\n"
479 + "</body></html>";
480
481 loadPageVerifyTitle2(content);
482 }
483
484 private void compareStringValue(final String xpath) throws Exception {
485 final String content = DOCTYPE_HTML
486 + "<html>\n"
487 + "<head>\n"
488 + "<script>\n"
489 + LOG_TITLE_FUNCTION
490 + "function test() {\n"
491 + " try {\n"
492 + " var res = '';\n"
493 + " var expr = '" + xpath + "';\n"
494 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
495 + " log(\"'\" + result.stringValue + \"'\");\n"
496 + " } catch(e) { logEx(e) }\n"
497 + "}\n"
498 + "</script></head>\n"
499 + "<body onload='test()'>\n"
500 + " <div>\n"
501 + " <p id='a' x='1' y='7'></p>\n"
502 + " <p id='b' y='13'></p>\n"
503 + " </div>\n"
504 + "</body></html>";
505
506 loadPageVerifyTitle2(content);
507 }
508
509 private void compareBooleanValue(final String xpath) throws Exception {
510 final String content = DOCTYPE_HTML
511 + "<html>\n"
512 + "<head>\n"
513 + "<script>\n"
514 + LOG_TITLE_FUNCTION
515 + "function test() {\n"
516 + " try {\n"
517 + " var res = '';\n"
518 + " var expr = '" + xpath + "';\n"
519 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
520 + " log(result.booleanValue);\n"
521 + " } catch(e) { logEx(e) }\n"
522 + "}\n"
523 + "</script></head>\n"
524 + "<body onload='test()'>\n"
525 + " <div>\n"
526 + " <p id='a' x='1' y='7'></p>\n"
527 + " <p id='b' y='13'></p>\n"
528 + " </div>\n"
529 + "</body></html>";
530
531 loadPageVerifyTitle2(content);
532 }
533
534 private void compareError(final String xpath) throws Exception {
535 final String content = DOCTYPE_HTML
536 + "<html>\n"
537 + "<head>\n"
538 + "<script>\n"
539 + LOG_TITLE_FUNCTION
540 + "function test() {\n"
541 + " try {\n"
542 + " var expr = '" + xpath + "';\n"
543 + " var result = document.evaluate(expr, document.documentElement, null, XPathResult.ANY_TYPE, null);\n"
544 + " log('error expected');\n"
545 + " } catch(e) { logEx(e) }\n"
546 + "}\n"
547 + "</script></head>\n"
548 + "<body onload='test()'>\n"
549 + "</body></html>";
550
551 loadPageVerifyTitle2(content);
552 }
553
554
555
556
557 @Test
558 @Alerts("mySpan")
559 public void minimalParameters() throws Exception {
560 final String content = DOCTYPE_HTML
561 + "<html>\n"
562 + "<head>\n"
563 + "<script>\n"
564 + LOG_TITLE_FUNCTION
565 + "function test() {\n"
566 + " try {\n"
567 + " var res = '';\n"
568 + " var result = document.evaluate('//span', document.documentElement);\n"
569 + " while (node = result.iterateNext()) {\n"
570 + " res += node.id;\n"
571 + " }\n"
572 + " log(res);\n"
573 + " } catch(e) { logEx(e) }\n"
574 + "}\n"
575 + "</script></head>\n"
576 + "<body onload='test()'>\n"
577 + " <div id='myDiv' attr='false'>false</span>\n"
578 + " <span id='mySpan' attr='true'>true</span>\n"
579 + "</body></html>";
580
581 loadPageVerifyTitle2(content);
582 }
583
584
585
586
587 @Test
588 @Alerts("mySpan")
589 public void undefinedResult() throws Exception {
590 final String content = DOCTYPE_HTML
591 + "<html>\n"
592 + "<head>\n"
593 + "<script>\n"
594 + LOG_TITLE_FUNCTION
595 + "function test() {\n"
596 + " try {\n"
597 + " var res = '';\n"
598 + " var result = document.evaluate('//span', "
599 + "document.documentElement, null, XPathResult.ANY_TYPE, undefined);\n"
600 + " while (node = result.iterateNext()) {\n"
601 + " res += node.id;\n"
602 + " }\n"
603 + " log(res);\n"
604 + " } catch(e) { logEx(e) }\n"
605 + "}\n"
606 + "</script></head>\n"
607 + "<body onload='test()'>\n"
608 + " <div id='myDiv' attr='false'>false</span>\n"
609 + " <span id='mySpan' attr='true'>true</span>\n"
610 + "</body></html>";
611
612 loadPageVerifyTitle2(content);
613 }
614
615
616
617
618 @Test
619 @Alerts("TypeError")
620 public void stringResult() throws Exception {
621 final String content = DOCTYPE_HTML
622 + "<html>\n"
623 + "<head>\n"
624 + "<script>\n"
625 + LOG_TITLE_FUNCTION
626 + "function test() {\n"
627 + " try {\n"
628 + " var res = '';\n"
629 + " var result = document.evaluate('//span', "
630 + "document.documentElement, null, XPathResult.ANY_TYPE, 'abcd');\n"
631 + " while (node = result.iterateNext()) {\n"
632 + " res += node.id;\n"
633 + " }\n"
634 + " log(res);\n"
635 + " } catch(e) { logEx(e) }\n"
636 + "}\n"
637 + "</script></head>\n"
638 + "<body onload='test()'>\n"
639 + " <div id='myDiv' attr='false'>false</span>\n"
640 + " <span id='mySpan' attr='true'>true</span>\n"
641 + "</body></html>";
642
643 loadPageVerifyTitle2(content);
644 }
645
646
647
648
649 @Test
650 @Alerts("mySpan")
651 public void objectResult() throws Exception {
652 final String content = DOCTYPE_HTML
653 + "<html>\n"
654 + "<head>\n"
655 + "<script>\n"
656 + LOG_TITLE_FUNCTION
657 + "function test() {\n"
658 + " try {\n"
659 + " var res = '';\n"
660 + " var result = document.evaluate('//span', "
661 + "document.documentElement, null, XPathResult.ANY_TYPE, {});\n"
662 + " while (node = result.iterateNext()) {\n"
663 + " res += node.id;\n"
664 + " }\n"
665 + " log(res);\n"
666 + " } catch(e) { logEx(e) }\n"
667 + "}\n"
668 + "</script></head>\n"
669 + "<body onload='test()'>\n"
670 + " <div id='myDiv' attr='false'>false</span>\n"
671 + " <span id='mySpan' attr='true'>true</span>\n"
672 + "</body></html>";
673
674 loadPageVerifyTitle2(content);
675 }
676
677
678
679
680 @Test
681 @Alerts(DEFAULT = "mySpan - - myDiv",
682 FF = "mySpan - myDiv - ",
683 FF_ESR = "mySpan - myDiv - ")
684 public void reuseResult() throws Exception {
685 final String content = DOCTYPE_HTML
686 + "<html>\n"
687 + "<head>\n"
688 + "<script>\n"
689 + LOG_TITLE_FUNCTION
690 + "function test() {\n"
691 + " try {\n"
692 + " var res = '';\n"
693 + " var result = document.evaluate('//span', "
694 + "document.documentElement, null, XPathResult.ANY_TYPE);\n"
695 + " while (node = result.iterateNext()) {\n"
696 + " res += node.id;\n"
697 + " }\n"
698 + " res += ' - ';\n"
699
700 + " var result2 = document.evaluate('//div', "
701 + "document.documentElement, null, XPathResult.ANY_TYPE, result);\n"
702 + " while (node = result.iterateNext()) {\n"
703 + " res += node.id;\n"
704 + " }\n"
705 + " res += ' - ';\n"
706
707 + " while (node = result2.iterateNext()) {\n"
708 + " res += node.id;\n"
709 + " }\n"
710
711 + " log(res);\n"
712 + " } catch(e) { logEx(e) }\n"
713 + "}\n"
714 + "</script></head>\n"
715 + "<body onload='test()'>\n"
716 + " <div id='myDiv' attr='false'>false</span>\n"
717 + " <span id='mySpan' attr='true'>true</span>\n"
718 + "</body></html>";
719
720 loadPageVerifyTitle2(content);
721 }
722
723
724
725
726 @Test
727 @Alerts("myDiv1")
728 public void documentEvaluateFirst() throws Exception {
729 final String content = DOCTYPE_HTML
730 + "<html>\n"
731 + "<head>\n"
732 + "<script>\n"
733 + LOG_TITLE_FUNCTION
734 + "function test() {\n"
735 + " try {\n"
736 + " var res = '';\n"
737 + " var result = document.evaluate('//div', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE);\n"
738 + " log(result.singleNodeValue.id);\n"
739 + " } catch(e) { logEx(e) }\n"
740 + "}\n"
741 + "</script></head>\n"
742 + "<body onload='test()'>\n"
743 + " <div id='myDiv1'>div1</div>\n"
744 + " <div id='myDiv2'>div1</div>\n"
745 + "</body></html>";
746
747 loadPageVerifyTitle2(content);
748 }
749 }