| <!doctype html> | |
| <title>TreeWalker tests</title> | |
| <link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> | |
| <meta name=timeout content=long> | |
| <div id=log></div> | |
| <script src=/resources/testharness.js></script> | |
| <script src=/resources/testharnessreport.js></script> | |
| <script src=../common.js></script> | |
| <script> | |
| "use strict"; | |
| // TODO .previousNode, .nextNode | |
| function filterNode(node, whatToShow, filter) { | |
| // "If active flag is set throw an "InvalidStateError"." | |
| // Ignore active flag for these tests, we aren't calling recursively | |
| // TODO Test me | |
| // "Let n be node's nodeType attribute value minus 1." | |
| var n = node.nodeType - 1; | |
| // "If the nth bit (where 0 is the least significant bit) of whatToShow is | |
| // not set, return FILTER_SKIP." | |
| if (!(whatToShow & (1 << n))) { | |
| return NodeFilter.FILTER_SKIP; | |
| } | |
| // "If filter is null, return FILTER_ACCEPT." | |
| if (!filter) { | |
| return NodeFilter.FILTER_ACCEPT; | |
| } | |
| // "Set the active flag." | |
| // | |
| // "Let result be the return value of invoking filter." | |
| // | |
| // "Unset the active flag." | |
| // | |
| // "If an exception was thrown, re-throw the exception." | |
| // TODO Test me | |
| // | |
| // "Return result." | |
| return filter(node); | |
| } | |
| function testTraverseChildren(type, walker, root, whatToShow, filter) { | |
| // TODO We don't test .currentNode other than the root | |
| walker.currentNode = root; | |
| assert_equals(walker.currentNode, root, "Setting .currentNode"); | |
| var expectedReturn = null; | |
| var expectedCurrentNode = root; | |
| // "To traverse children of type type, run these steps: | |
| // | |
| // "Let node be the value of the currentNode attribute." | |
| var node = walker.currentNode; | |
| // "Set node to node's first child if type is first, and node's last child | |
| // if type is last." | |
| node = type == "first" ? node.firstChild : node.lastChild; | |
| // "Main: While node is not null, run these substeps:" | |
| while (node) { | |
| // "Filter node and let result be the return value." | |
| var result = filterNode(node, whatToShow, filter); | |
| // "If result is FILTER_ACCEPT, then set the currentNode attribute to | |
| // node and return node." | |
| if (result == NodeFilter.FILTER_ACCEPT) { | |
| expectedCurrentNode = expectedReturn = node; | |
| break; | |
| } | |
| // "If result is FILTER_SKIP, run these subsubsteps:" | |
| if (result == NodeFilter.FILTER_SKIP) { | |
| // "Let child be node's first child if type is first, and node's | |
| // last child if type is last." | |
| var child = type == "first" ? node.firstChild : node.lastChild; | |
| // "If child is not null, set node to child and goto Main." | |
| if (child) { | |
| node = child; | |
| continue; | |
| } | |
| } | |
| // "While node is not null, run these subsubsteps:" | |
| while (node) { | |
| // "Let sibling be node's next sibling if type is first, and node's | |
| // previous sibling if type is last." | |
| var sibling = type == "first" ? node.nextSibling | |
| : node.previousSibling; | |
| // "If sibling is not null, set node to sibling and goto Main." | |
| if (sibling) { | |
| node = sibling; | |
| break; | |
| } | |
| // "Let parent be node's parent." | |
| var parent = node.parentNode; | |
| // "If parent is null, parent is root, or parent is currentNode | |
| // attribute's value, return null." | |
| if (!parent || parent == root || parent == walker.currentNode) { | |
| expectedReturn = node = null; | |
| break; | |
| } else { | |
| // "Otherwise, set node to parent." | |
| node = parent; | |
| } | |
| } | |
| } | |
| if (type == "first") { | |
| assert_equals(walker.firstChild(), expectedReturn, ".firstChild()"); | |
| assert_equals(walker.currentNode, expectedCurrentNode, | |
| ".currentNode after .firstChild()"); | |
| } else { | |
| assert_equals(walker.lastChild(), expectedReturn, ".lastChild()"); | |
| assert_equals(walker.currentNode, expectedCurrentNode, | |
| ".currentNode after .lastChild()"); | |
| } | |
| } | |
| function testTraverseSiblings(type, walker, root, whatToShow, filter) { | |
| // TODO We don't test .currentNode other than the root's first or last child | |
| if (!root.firstChild) { | |
| // Nothing much to test | |
| walker.currentNode = root; | |
| assert_equals(walker.currentNode, root, "Setting .currentNode"); | |
| if (type == "next") { | |
| assert_equals(walker.nextSibling(), null, ".nextSibling()"); | |
| assert_equals(walker.currentNode, root, | |
| ".currentNode after .nextSibling()") | |
| } else { | |
| assert_equals(walker.previousSibling(), null, ".previousSibling()"); | |
| assert_equals(walker.currentNode, root, | |
| ".currentNode after .previousSibling()") | |
| } | |
| return; | |
| } | |
| if (type == "next") { | |
| walker.currentNode = root.firstChild; | |
| assert_equals(walker.currentNode, root.firstChild, | |
| "Setting .currentNode"); | |
| } else { | |
| walker.currentNode = root.lastChild; | |
| assert_equals(walker.currentNode, root.lastChild, | |
| "Setting .currentNode"); | |
| } | |
| var expectedReturn = null; | |
| var expectedCurrentNode = type == "next" ? root.firstChild : root.lastChild; | |
| // "To traverse siblings of type type run these steps:" | |
| (function() { | |
| // "Let node be the value of the currentNode attribute." | |
| var node = type == "next" ? root.firstChild : root.lastChild; | |
| // "If node is root, return null. | |
| // | |
| // "Run these substeps: | |
| do { | |
| // "Let sibling be node's next sibling if type is next, and node's | |
| // previous sibling if type is previous." | |
| var sibling = type == "next" ? node.nextSibling : | |
| node.previousSibling; | |
| // "While sibling is not null, run these subsubsteps:" | |
| while (sibling) { | |
| // "Set node to sibling." | |
| node = sibling; | |
| // "Filter node and let result be the return value." | |
| var result = filterNode(node, whatToShow, filter); | |
| // "If result is FILTER_ACCEPT, then set the currentNode | |
| // attribute to node and return node." | |
| if (result == NodeFilter.FILTER_ACCEPT) { | |
| expectedCurrentNode = expectedReturn = node; | |
| return; | |
| } | |
| // "Set sibling to node's first child if type is next, and | |
| // node's last child if type is previous." | |
| sibling = type == "next" ? node.firstChild : node.lastChild; | |
| // "If result is FILTER_REJECT or sibling is null, then set | |
| // sibling to node's next sibling if type is next, and node's | |
| // previous sibling if type is previous." | |
| if (result == NodeFilter.FILTER_REJECT || !sibling) { | |
| sibling = type == "next" ? node.nextSibling : | |
| node.previousSibling; | |
| } | |
| } | |
| // "Set node to its parent." | |
| node = node.parentNode; | |
| // "If node is null or is root, return null. | |
| if (!node || node == root) { | |
| return; | |
| } | |
| // "Filter node and if the return value is FILTER_ACCEPT, then | |
| // return null." | |
| if (filterNode(node, whatToShow, filter)) { | |
| return; | |
| } | |
| // "Run these substeps again." | |
| } while (true); | |
| })(); | |
| if (type == "next") { | |
| assert_equals(walker.nextSibling(), expectedReturn, ".nextSibling()"); | |
| assert_equals(walker.currentNode, expectedCurrentNode, | |
| ".currentNode after .nextSibling()"); | |
| } else { | |
| assert_equals(walker.previousSibling(), expectedReturn, ".previousSibling()"); | |
| assert_equals(walker.currentNode, expectedCurrentNode, | |
| ".currentNode after .previousSibling()"); | |
| } | |
| } | |
| function testWalker(root, whatToShow, filter) { | |
| var walker = document.createTreeWalker(root, whatToShow, filter); | |
| assert_equals(walker.root, root, ".root"); | |
| assert_equals(walker.whatToShow, whatToShow, ".whatToShow"); | |
| assert_equals(walker.filter, filter, ".filter"); | |
| assert_equals(walker.currentNode, root, ".currentNode"); | |
| var expectedReturn = null; | |
| var expectedCurrentNode = walker.currentNode; | |
| // "The parentNode() method must run these steps:" | |
| // | |
| // "Let node be the value of the currentNode attribute." | |
| var node = walker.currentNode; | |
| // "While node is not null and is not root, run these substeps:" | |
| while (node && node != root) { | |
| // "Let node be node's parent." | |
| node = node.parentNode; | |
| // "If node is not null and filtering node returns FILTER_ACCEPT, then | |
| // set the currentNode attribute to node, return node." | |
| if (node && filterNode(node, whatToShow, filter) == | |
| NodeFilter.FILTER_ACCEPT) { | |
| expectedCurrentNode = expectedReturn = node; | |
| } | |
| } | |
| assert_equals(walker.parentNode(), expectedReturn, ".parentNode()"); | |
| assert_equals(walker.currentNode, expectedCurrentNode, | |
| ".currentNode after .parentNode()"); | |
| testTraverseChildren("first", walker, root, whatToShow, filter); | |
| testTraverseChildren("last", walker, root, whatToShow, filter); | |
| testTraverseSiblings("next", walker, root, whatToShow, filter); | |
| testTraverseSiblings("previous", walker, root, whatToShow, filter); | |
| } | |
| var whatToShows = [ | |
| "0", | |
| "0xFFFFFFFF", | |
| "NodeFilter.SHOW_ELEMENT", | |
| "NodeFilter.SHOW_ATTRIBUTE", | |
| "NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_DOCUMENT", | |
| ]; | |
| var callbacks = [ | |
| "null", | |
| "(function(node) { return true })", | |
| "(function(node) { return false })", | |
| "(function(node) { return node.nodeName[0] == '#' })", | |
| ]; | |
| var tests = []; | |
| for (var i = 0; i < testNodes.length; i++) { | |
| for (var j = 0; j < whatToShows.length; j++) { | |
| for (var k = 0; k < callbacks.length; k++) { | |
| tests.push([ | |
| "document.createTreeWalker(" + testNodes[i] + | |
| ", " + whatToShows[j] + ", " + callbacks[k] + ")", | |
| eval(testNodes[i]), eval(whatToShows[j]), eval(callbacks[k]) | |
| ]); | |
| } | |
| } | |
| } | |
| generate_tests(testWalker, tests); | |
| testDiv.style.display = "none"; | |
| </script> |