tor-browser

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

Range-insertNode.html (12933B)


      1 <!doctype html>
      2 <title>Range.insertNode() tests</title>
      3 <link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name>
      4 <meta name=timeout content=long>
      5 <p>To debug test failures, add a query parameter "subtest" with the test id (like
      6 "?subtest=5,16").  Only that test will be run.  Then you can look at the resulting
      7 iframes in the DOM.
      8 <div id=log></div>
      9 <script src=/resources/testharness.js></script>
     10 <script src=/resources/testharnessreport.js></script>
     11 <script src=../common.js></script>
     12 <script>
     13 "use strict";
     14 
     15 testDiv.parentNode.removeChild(testDiv);
     16 
     17 function restoreIframe(iframe, i, j) {
     18    // Most of this function is designed to work around the fact that Opera
     19    // doesn't let you add a doctype to a document that no longer has one, in
     20    // any way I can figure out.  I eventually compromised on something that
     21    // will still let Opera pass most tests that don't actually involve
     22    // doctypes.
     23    while (iframe.contentDocument.firstChild
     24    && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) {
     25        iframe.contentDocument.removeChild(iframe.contentDocument.firstChild);
     26    }
     27 
     28    while (iframe.contentDocument.lastChild
     29    && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) {
     30        iframe.contentDocument.removeChild(iframe.contentDocument.lastChild);
     31    }
     32 
     33    if (!iframe.contentDocument.firstChild) {
     34        // This will throw an exception in Opera if we reach here, which is why
     35        // I try to avoid it.  It will never happen in a browser that obeys the
     36        // spec, so it's really just insurance.  I don't think it actually gets
     37        // hit by anything.
     38        iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", ""));
     39    }
     40    iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true));
     41    iframe.contentWindow.setupRangeTests();
     42    iframe.contentWindow.testRangeInput = testRangesShort[i];
     43    iframe.contentWindow.testNodeInput = testNodesShort[j];
     44    iframe.contentWindow.run();
     45 }
     46 
     47 function testInsertNode(i, j) {
     48    var actualRange;
     49    var expectedRange;
     50    var actualNode;
     51    var expectedNode;
     52    var actualRoots = [];
     53    var expectedRoots = [];
     54 
     55    var detached = false;
     56 
     57    domTests[i][j].step(function() {
     58        restoreIframe(actualIframe, i, j);
     59        restoreIframe(expectedIframe, i, j);
     60 
     61        actualRange = actualIframe.contentWindow.testRange;
     62        expectedRange = expectedIframe.contentWindow.testRange;
     63        actualNode = actualIframe.contentWindow.testNode;
     64        expectedNode = expectedIframe.contentWindow.testNode;
     65 
     66        try {
     67            actualRange.collapsed;
     68        } catch (e) {
     69            detached = true;
     70        }
     71 
     72        assert_equals(actualIframe.contentWindow.unexpectedException, null,
     73            "Unexpected exception thrown when setting up Range for actual insertNode()");
     74        assert_equals(expectedIframe.contentWindow.unexpectedException, null,
     75            "Unexpected exception thrown when setting up Range for simulated insertNode()");
     76        assert_equals(typeof actualRange, "object",
     77            "typeof Range produced in actual iframe");
     78        assert_not_equals(actualRange, null,
     79            "Range produced in actual iframe was null");
     80        assert_equals(typeof expectedRange, "object",
     81            "typeof Range produced in expected iframe");
     82        assert_not_equals(expectedRange, null,
     83            "Range produced in expected iframe was null");
     84        assert_equals(typeof actualNode, "object",
     85            "typeof Node produced in actual iframe");
     86        assert_not_equals(actualNode, null,
     87            "Node produced in actual iframe was null");
     88        assert_equals(typeof expectedNode, "object",
     89            "typeof Node produced in expected iframe");
     90        assert_not_equals(expectedNode, null,
     91            "Node produced in expected iframe was null");
     92 
     93        // We want to test that the trees containing the ranges are equal, and
     94        // also the trees containing the moved nodes.  These might not be the
     95        // same, if we're inserting a node from a detached tree or a different
     96        // document.
     97        //
     98        // Detached ranges are always in the contentDocument.
     99        if (detached) {
    100            actualRoots.push(actualIframe.contentDocument);
    101            expectedRoots.push(expectedIframe.contentDocument);
    102        } else {
    103            actualRoots.push(furthestAncestor(actualRange.startContainer));
    104            expectedRoots.push(furthestAncestor(expectedRange.startContainer));
    105        }
    106 
    107        if (furthestAncestor(actualNode) != actualRoots[0]) {
    108            actualRoots.push(furthestAncestor(actualNode));
    109        }
    110        if (furthestAncestor(expectedNode) != expectedRoots[0]) {
    111            expectedRoots.push(furthestAncestor(expectedNode));
    112        }
    113 
    114        assert_equals(actualRoots.length, expectedRoots.length,
    115            "Either the actual node and actual range are in the same tree but the expected are in different trees, or vice versa");
    116 
    117        // This doctype stuff is to work around the fact that Opera 11.00 will
    118        // move around doctypes within a document, even to totally invalid
    119        // positions, but it won't allow a new doctype to be added to a
    120        // document in any way I can figure out.  So if we try moving a doctype
    121        // to some invalid place, in Opera it will actually succeed, and then
    122        // restoreIframe() will remove the doctype along with the root element,
    123        // and then nothing can re-add the doctype.  So instead, we catch it
    124        // during the test itself and move it back to the right place while we
    125        // still can.
    126        //
    127        // I spent *way* too much time debugging and working around this bug.
    128        var actualDoctype = actualIframe.contentDocument.doctype;
    129        var expectedDoctype = expectedIframe.contentDocument.doctype;
    130 
    131        var result;
    132        try {
    133            result = myInsertNode(expectedRange, expectedNode);
    134        } catch (e) {
    135            if (expectedDoctype != expectedIframe.contentDocument.firstChild) {
    136                expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild);
    137            }
    138            throw e;
    139        }
    140        if (typeof result == "string") {
    141            assert_throws_dom(result, actualIframe.contentWindow.DOMException, function() {
    142                try {
    143                    actualRange.insertNode(actualNode);
    144                } catch (e) {
    145                    if (expectedDoctype != expectedIframe.contentDocument.firstChild) {
    146                        expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild);
    147                    }
    148                    if (actualDoctype != actualIframe.contentDocument.firstChild) {
    149                        actualIframe.contentDocument.insertBefore(actualDoctype, actualIframe.contentDocument.firstChild);
    150                    }
    151                    throw e;
    152                }
    153            }, "A " + result + " DOMException must be thrown in this case");
    154            // Don't return, we still need to test DOM equality
    155        } else {
    156            try {
    157                actualRange.insertNode(actualNode);
    158            } catch (e) {
    159                if (expectedDoctype != expectedIframe.contentDocument.firstChild) {
    160                    expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild);
    161                }
    162                if (actualDoctype != actualIframe.contentDocument.firstChild) {
    163                    actualIframe.contentDocument.insertBefore(actualDoctype, actualIframe.contentDocument.firstChild);
    164                }
    165                throw e;
    166            }
    167        }
    168 
    169        for (var k = 0; k < actualRoots.length; k++) {
    170            assertNodesEqual(actualRoots[k], expectedRoots[k], k ? "moved node's tree root" : "range's tree root");
    171        }
    172    });
    173    domTests[i][j].done();
    174 
    175    positionTests[i][j].step(function() {
    176        assert_equals(actualIframe.contentWindow.unexpectedException, null,
    177            "Unexpected exception thrown when setting up Range for actual insertNode()");
    178        assert_equals(expectedIframe.contentWindow.unexpectedException, null,
    179            "Unexpected exception thrown when setting up Range for simulated insertNode()");
    180        assert_equals(typeof actualRange, "object",
    181            "typeof Range produced in actual iframe");
    182        assert_not_equals(actualRange, null,
    183            "Range produced in actual iframe was null");
    184        assert_equals(typeof expectedRange, "object",
    185            "typeof Range produced in expected iframe");
    186        assert_not_equals(expectedRange, null,
    187            "Range produced in expected iframe was null");
    188        assert_equals(typeof actualNode, "object",
    189            "typeof Node produced in actual iframe");
    190        assert_not_equals(actualNode, null,
    191            "Node produced in actual iframe was null");
    192        assert_equals(typeof expectedNode, "object",
    193            "typeof Node produced in expected iframe");
    194        assert_not_equals(expectedNode, null,
    195            "Node produced in expected iframe was null");
    196 
    197        for (var k = 0; k < actualRoots.length; k++) {
    198            assertNodesEqual(actualRoots[k], expectedRoots[k], k ? "moved node's tree root" : "range's tree root");
    199        }
    200 
    201        if (detached) {
    202            // No further tests we can do
    203            return;
    204        }
    205 
    206        assert_equals(actualRange.startOffset, expectedRange.startOffset,
    207            "Unexpected startOffset after insertNode()");
    208        assert_equals(actualRange.endOffset, expectedRange.endOffset,
    209            "Unexpected endOffset after insertNode()");
    210        // How do we decide that the two nodes are equal, since they're in
    211        // different trees?  Since the DOMs are the same, it's enough to check
    212        // that the index in the parent is the same all the way up the tree.
    213        // But we can first cheat by just checking they're actually equal.
    214        assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer),
    215            "Unexpected startContainer after insertNode(), expected " +
    216            expectedRange.startContainer.nodeName.toLowerCase() + " but got " +
    217            actualRange.startContainer.nodeName.toLowerCase());
    218        var currentActual = actualRange.startContainer;
    219        var currentExpected = expectedRange.startContainer;
    220        var actual = "";
    221        var expected = "";
    222        while (currentActual && currentExpected) {
    223            actual = indexOf(currentActual) + "-" + actual;
    224            expected = indexOf(currentExpected) + "-" + expected;
    225 
    226            currentActual = currentActual.parentNode;
    227            currentExpected = currentExpected.parentNode;
    228        }
    229        actual = actual.substr(0, actual.length - 1);
    230        expected = expected.substr(0, expected.length - 1);
    231        assert_equals(actual, expected,
    232            "startContainer superficially looks right but is actually the wrong node if you trace back its index in all its ancestors (I'm surprised this actually happened");
    233    });
    234    positionTests[i][j].done();
    235 }
    236 
    237 testRanges.unshift('"detached"');
    238 
    239 var iStart = 0;
    240 var iStop = testRangesShort.length;
    241 var jStart = 0;
    242 var jStop = testNodesShort.length;
    243 
    244 if (/subtest=[0-9]+,[0-9]+/.test(location.search)) {
    245    var matches = /subtest=([0-9]+),([0-9]+)/.exec(location.search);
    246    iStart = Number(matches[1]);
    247    iStop = Number(matches[1]) + 1;
    248    jStart = Number(matches[2]) + 0;
    249    jStop = Number(matches[2]) + 1;
    250 }
    251 
    252 var domTests = [];
    253 var positionTests = [];
    254 for (var i = iStart; i < iStop; i++) {
    255    domTests[i] = [];
    256    positionTests[i] = [];
    257    for (var j = jStart; j < jStop; j++) {
    258        domTests[i][j] = async_test(i + "," + j + ": resulting DOM for range " + testRangesShort[i] + ", node " + testNodesShort[j]);
    259        positionTests[i][j] = async_test(i + "," + j + ": resulting range position for range " + testRangesShort[i] + ", node " + testNodesShort[j]);
    260    }
    261 }
    262 
    263 var actualIframe = document.createElement("iframe");
    264 actualIframe.style.display = "none";
    265 document.body.appendChild(actualIframe);
    266 
    267 var expectedIframe = document.createElement("iframe");
    268 expectedIframe.style.display = "none";
    269 document.body.appendChild(expectedIframe);
    270 
    271 var referenceDoc = document.implementation.createHTMLDocument("");
    272 referenceDoc.removeChild(referenceDoc.documentElement);
    273 
    274 actualIframe.onload = function() {
    275    expectedIframe.onload = function() {
    276        for (var i = iStart; i < iStop; i++) {
    277            for (var j = jStart; j < jStop; j++) {
    278                testInsertNode(i, j);
    279            }
    280        }
    281    }
    282    expectedIframe.src = "Range-test-iframe.html";
    283    referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true));
    284 }
    285 actualIframe.src = "Range-test-iframe.html";
    286 </script>