tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>