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