e0e285a779db3a12b2919e67afd04a10522686fa
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / dom / traversal / TreeWalker.html
1 <!doctype html>
2 <title>TreeWalker tests</title>
3 <link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name>
4 <meta name=timeout content=long>
5 <div id=log></div>
6 <script src=/resources/testharness.js></script>
7 <script src=/resources/testharnessreport.js></script>
8 <script src=../common.js></script>
9 <script>
10 "use strict";
11
12 // TODO .previousNode, .nextNode
13
14 function filterNode(node, whatToShow, filter) {
15     // "If active flag is set throw an "InvalidStateError"."
16     // Ignore active flag for these tests, we aren't calling recursively
17     // TODO Test me
18
19     // "Let n be node's nodeType attribute value minus 1."
20     var n = node.nodeType - 1;
21
22     // "If the nth bit (where 0 is the least significant bit) of whatToShow is
23     // not set, return FILTER_SKIP."
24     if (!(whatToShow & (1 << n))) {
25         return NodeFilter.FILTER_SKIP;
26     }
27
28     // "If filter is null, return FILTER_ACCEPT."
29     if (!filter) {
30         return NodeFilter.FILTER_ACCEPT;
31     }
32
33     // "Set the active flag."
34     //
35     // "Let result be the return value of invoking filter."
36     //
37     // "Unset the active flag."
38     //
39     // "If an exception was thrown, re-throw the exception."
40     // TODO Test me
41     //
42     // "Return result."
43     return filter(node);
44 }
45
46 function testTraverseChildren(type, walker, root, whatToShow, filter) {
47     // TODO We don't test .currentNode other than the root
48     walker.currentNode = root;
49     assert_equals(walker.currentNode, root, "Setting .currentNode");
50
51     var expectedReturn = null;
52     var expectedCurrentNode = root;
53
54     // "To traverse children of type type, run these steps:
55     //
56     // "Let node be the value of the currentNode attribute."
57     var node = walker.currentNode;
58
59     // "Set node to node's first child if type is first, and node's last child
60     // if type is last."
61     node = type == "first" ? node.firstChild : node.lastChild;
62
63     // "Main: While node is not null, run these substeps:"
64     while (node) {
65         // "Filter node and let result be the return value."
66         var result = filterNode(node, whatToShow, filter);
67
68         // "If result is FILTER_ACCEPT, then set the currentNode attribute to
69         // node and return node."
70         if (result == NodeFilter.FILTER_ACCEPT) {
71             expectedCurrentNode = expectedReturn = node;
72             break;
73         }
74
75         // "If result is FILTER_SKIP, run these subsubsteps:"
76         if (result == NodeFilter.FILTER_SKIP) {
77             // "Let child be node's first child if type is first, and node's
78             // last child if type is last."
79             var child = type == "first" ? node.firstChild : node.lastChild;
80
81             // "If child is not null, set node to child and goto Main."
82             if (child) {
83                 node = child;
84                 continue;
85             }
86         }
87
88         // "While node is not null, run these subsubsteps:"
89         while (node) {
90             // "Let sibling be node's next sibling if type is first, and node's
91             // previous sibling if type is last."
92             var sibling = type == "first" ? node.nextSibling
93                 : node.previousSibling;
94
95             // "If sibling is not null, set node to sibling and goto Main."
96             if (sibling) {
97                 node = sibling;
98                 break;
99             }
100
101             // "Let parent be node's parent."
102             var parent = node.parentNode;
103
104             // "If parent is null, parent is root, or parent is currentNode
105             // attribute's value, return null."
106             if (!parent || parent == root || parent == walker.currentNode) {
107                 expectedReturn = node = null;
108                 break;
109             } else {
110             // "Otherwise, set node to parent."
111                 node = parent;
112             }
113         }
114     }
115
116     if (type == "first") {
117         assert_equals(walker.firstChild(), expectedReturn, ".firstChild()");
118         assert_equals(walker.currentNode, expectedCurrentNode,
119             ".currentNode after .firstChild()");
120     } else {
121         assert_equals(walker.lastChild(), expectedReturn, ".lastChild()");
122         assert_equals(walker.currentNode, expectedCurrentNode,
123         ".currentNode after .lastChild()");
124     }
125 }
126
127 function testTraverseSiblings(type, walker, root, whatToShow, filter) {
128     // TODO We don't test .currentNode other than the root's first or last child
129     if (!root.firstChild) {
130         // Nothing much to test
131
132         walker.currentNode = root;
133         assert_equals(walker.currentNode, root, "Setting .currentNode");
134
135         if (type == "next") {
136             assert_equals(walker.nextSibling(), null, ".nextSibling()");
137             assert_equals(walker.currentNode, root,
138                 ".currentNode after .nextSibling()")
139         } else {
140             assert_equals(walker.previousSibling(), null, ".previousSibling()");
141             assert_equals(walker.currentNode, root,
142                 ".currentNode after .previousSibling()")
143         }
144         return;
145     }
146
147     if (type == "next") {
148         walker.currentNode = root.firstChild;
149         assert_equals(walker.currentNode, root.firstChild,
150             "Setting .currentNode");
151     } else {
152         walker.currentNode = root.lastChild;
153         assert_equals(walker.currentNode, root.lastChild,
154             "Setting .currentNode");
155     }
156
157     var expectedReturn = null;
158     var expectedCurrentNode = type == "next" ? root.firstChild : root.lastChild;
159
160     // "To traverse siblings of type type run these steps:"
161     (function() {
162         // "Let node be the value of the currentNode attribute."
163         var node = type == "next" ? root.firstChild : root.lastChild;
164
165         // "If node is root, return null.
166         //
167         // "Run these substeps:
168         do {
169             // "Let sibling be node's next sibling if type is next, and node's
170             // previous sibling if type is previous."
171             var sibling = type == "next" ? node.nextSibling :
172                 node.previousSibling;
173
174             // "While sibling is not null, run these subsubsteps:"
175             while (sibling) {
176                 // "Set node to sibling."
177                 node = sibling;
178
179                 // "Filter node and let result be the return value."
180                 var result = filterNode(node, whatToShow, filter);
181
182                 // "If result is FILTER_ACCEPT, then set the currentNode
183                 // attribute to node and return node."
184                 if (result == NodeFilter.FILTER_ACCEPT) {
185                     expectedCurrentNode = expectedReturn = node;
186                     return;
187                 }
188
189                 // "Set sibling to node's first child if type is next, and
190                 // node's last child if type is previous."
191                 sibling = type == "next" ? node.firstChild : node.lastChild;
192
193                 // "If result is FILTER_REJECT or sibling is null, then set
194                 // sibling to node's next sibling if type is next, and node's
195                 // previous sibling if type is previous."
196                 if (result == NodeFilter.FILTER_REJECT || !sibling) {
197                     sibling = type == "next" ? node.nextSibling :
198                         node.previousSibling;
199                 }
200             }
201
202             // "Set node to its parent."
203             node = node.parentNode;
204
205             // "If node is null or is root, return null.
206             if (!node || node == root) {
207                 return;
208             }
209             // "Filter node and if the return value is FILTER_ACCEPT, then
210             // return null."
211             if (filterNode(node, whatToShow, filter)) {
212                 return;
213             }
214
215             // "Run these substeps again."
216         } while (true);
217     })();
218
219     if (type == "next") {
220         assert_equals(walker.nextSibling(), expectedReturn, ".nextSibling()");
221         assert_equals(walker.currentNode, expectedCurrentNode,
222             ".currentNode after .nextSibling()");
223     } else {
224         assert_equals(walker.previousSibling(), expectedReturn, ".previousSibling()");
225         assert_equals(walker.currentNode, expectedCurrentNode,
226             ".currentNode after .previousSibling()");
227     }
228 }
229
230 function testWalker(root, whatToShow, filter) {
231     var walker = document.createTreeWalker(root, whatToShow, filter);
232
233     assert_equals(walker.root, root, ".root");
234     assert_equals(walker.whatToShow, whatToShow, ".whatToShow");
235     assert_equals(walker.filter, filter, ".filter");
236     assert_equals(walker.currentNode, root, ".currentNode");
237
238     var expectedReturn = null;
239     var expectedCurrentNode = walker.currentNode;
240     // "The parentNode() method must run these steps:"
241     //
242     // "Let node be the value of the currentNode attribute."
243     var node = walker.currentNode;
244
245     // "While node is not null and is not root, run these substeps:"
246     while (node && node != root) {
247         // "Let node be node's parent."
248         node = node.parentNode;
249
250         // "If node is not null and filtering node returns FILTER_ACCEPT, then
251         // set the currentNode attribute to node, return node."
252         if (node && filterNode(node, whatToShow, filter) ==
253         NodeFilter.FILTER_ACCEPT) {
254             expectedCurrentNode = expectedReturn = node;
255         }
256     }
257     assert_equals(walker.parentNode(), expectedReturn, ".parentNode()");
258     assert_equals(walker.currentNode, expectedCurrentNode,
259         ".currentNode after .parentNode()");
260
261     testTraverseChildren("first", walker, root, whatToShow, filter);
262     testTraverseChildren("last", walker, root, whatToShow, filter);
263
264     testTraverseSiblings("next", walker, root, whatToShow, filter);
265     testTraverseSiblings("previous", walker, root, whatToShow, filter);
266 }
267
268 var whatToShows = [
269     "0",
270     "0xFFFFFFFF",
271     "NodeFilter.SHOW_ELEMENT",
272     "NodeFilter.SHOW_ATTRIBUTE",
273     "NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_DOCUMENT",
274 ];
275
276 var callbacks = [
277     "null",
278     "(function(node) { return true })",
279     "(function(node) { return false })",
280     "(function(node) { return node.nodeName[0] == '#' })",
281 ];
282
283 var tests = [];
284 for (var i = 0; i < testNodes.length; i++) {
285     for (var j = 0; j < whatToShows.length; j++) {
286         for (var k = 0; k < callbacks.length; k++) {
287             tests.push([
288                 "document.createTreeWalker(" + testNodes[i] +
289                     ", " + whatToShows[j] + ", " + callbacks[k] + ")",
290                 eval(testNodes[i]), eval(whatToShows[j]), eval(callbacks[k])
291             ]);
292         }
293     }
294 }
295 generate_tests(testWalker, tests);
296
297 testDiv.style.display = "none";
298 </script>