<!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>