tor-browser

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

Range-extractContents.html (10505B)


      1 <!doctype html>
      2 <title>Range.extractContents() 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").  Only that test will be run.  Then you can look at the resulting
      7 iframe 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 var actualIframe = document.createElement("iframe");
     18 actualIframe.style.display = "none";
     19 document.body.appendChild(actualIframe);
     20 
     21 var expectedIframe = document.createElement("iframe");
     22 expectedIframe.style.display = "none";
     23 document.body.appendChild(expectedIframe);
     24 
     25 function restoreIframe(iframe, i) {
     26  // Most of this function is designed to work around the fact that Opera
     27  // doesn't let you add a doctype to a document that no longer has one, in
     28  // any way I can figure out.  I eventually compromised on something that
     29  // will still let Opera pass most tests that don't actually involve
     30  // doctypes.
     31  while (iframe.contentDocument.firstChild
     32  && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) {
     33    iframe.contentDocument.removeChild(iframe.contentDocument.firstChild);
     34  }
     35 
     36  while (iframe.contentDocument.lastChild
     37  && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) {
     38    iframe.contentDocument.removeChild(iframe.contentDocument.lastChild);
     39  }
     40 
     41  if (!iframe.contentDocument.firstChild) {
     42    // This will throw an exception in Opera if we reach here, which is why
     43    // I try to avoid it.  It will never happen in a browser that obeys the
     44    // spec, so it's really just insurance.  I don't think it actually gets
     45    // hit by anything.
     46    iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", ""));
     47  }
     48  iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true));
     49  iframe.contentWindow.setupRangeTests();
     50  iframe.contentWindow.testRangeInput = testRanges[i];
     51  iframe.contentWindow.run();
     52 }
     53 
     54 function testExtractContents(i) {
     55  restoreIframe(actualIframe, i);
     56  restoreIframe(expectedIframe, i);
     57 
     58  var actualRange = actualIframe.contentWindow.testRange;
     59  var expectedRange = expectedIframe.contentWindow.testRange;
     60  var actualFrag, expectedFrag;
     61  var actualRoots, expectedRoots;
     62 
     63  domTests[i].step(function() {
     64    assert_equals(actualIframe.contentWindow.unexpectedException, null,
     65      "Unexpected exception thrown when setting up Range for actual extractContents()");
     66    assert_equals(expectedIframe.contentWindow.unexpectedException, null,
     67      "Unexpected exception thrown when setting up Range for simulated extractContents()");
     68    assert_equals(typeof actualRange, "object",
     69      "typeof Range produced in actual iframe");
     70    assert_equals(typeof expectedRange, "object",
     71      "typeof Range produced in expected iframe");
     72 
     73    // Just to be pedantic, we'll test not only that the tree we're
     74    // modifying is the same in expected vs. actual, but also that all the
     75    // nodes originally in it were the same.  Typically some nodes will
     76    // become detached when the algorithm is run, but they still exist and
     77    // references can still be kept to them, so they should also remain the
     78    // same.
     79    //
     80    // We initialize the list to all nodes, and later on remove all the
     81    // ones which still have parents, since the parents will presumably be
     82    // tested for isEqualNode() and checking the children would be
     83    // redundant.
     84    var actualAllNodes = [];
     85    var node = furthestAncestor(actualRange.startContainer);
     86    do {
     87      actualAllNodes.push(node);
     88    } while (node = nextNode(node));
     89 
     90    var expectedAllNodes = [];
     91    var node = furthestAncestor(expectedRange.startContainer);
     92    do {
     93      expectedAllNodes.push(node);
     94    } while (node = nextNode(node));
     95 
     96    expectedFrag = myExtractContents(expectedRange);
     97    if (typeof expectedFrag == "string") {
     98      assert_throws_dom(
     99        expectedFrag,
    100        actualIframe.contentWindow.DOMException,
    101        function() {
    102          actualRange.extractContents();
    103        }
    104      );
    105    } else {
    106      actualFrag = actualRange.extractContents();
    107    }
    108 
    109    actualRoots = [];
    110    for (var j = 0; j < actualAllNodes.length; j++) {
    111      if (!actualAllNodes[j].parentNode) {
    112        actualRoots.push(actualAllNodes[j]);
    113      }
    114    }
    115 
    116    expectedRoots = [];
    117    for (var j = 0; j < expectedAllNodes.length; j++) {
    118      if (!expectedAllNodes[j].parentNode) {
    119        expectedRoots.push(expectedAllNodes[j]);
    120      }
    121    }
    122 
    123    for (var j = 0; j < actualRoots.length; j++) {
    124      assertNodesEqual(actualRoots[j], expectedRoots[j], j ? "detached node #" + j : "tree root");
    125 
    126      if (j == 0) {
    127        // Clearly something is wrong if the node lists are different
    128        // lengths.  We want to report this only after we've already
    129        // checked the main tree for equality, though, so it doesn't
    130        // mask more interesting errors.
    131        assert_equals(actualRoots.length, expectedRoots.length,
    132          "Actual and expected DOMs were broken up into a different number of pieces by extractContents() (this probably means you created or detached nodes when you weren't supposed to)");
    133      }
    134    }
    135  });
    136  domTests[i].done();
    137 
    138  positionTests[i].step(function() {
    139    assert_equals(actualIframe.contentWindow.unexpectedException, null,
    140      "Unexpected exception thrown when setting up Range for actual extractContents()");
    141    assert_equals(expectedIframe.contentWindow.unexpectedException, null,
    142      "Unexpected exception thrown when setting up Range for simulated extractContents()");
    143    assert_equals(typeof actualRange, "object",
    144      "typeof Range produced in actual iframe");
    145    assert_equals(typeof expectedRange, "object",
    146      "typeof Range produced in expected iframe");
    147 
    148    assert_true(actualRoots[0].isEqualNode(expectedRoots[0]),
    149      "The resulting DOMs were not equal, so comparing positions makes no sense");
    150 
    151    if (typeof expectedFrag == "string") {
    152      // It's no longer true that, e.g., startContainer and endContainer
    153      // must always be the same
    154      return;
    155    }
    156    assert_equals(actualRange.startContainer, actualRange.endContainer,
    157      "startContainer and endContainer must always be the same after extractContents()");
    158    assert_equals(actualRange.startOffset, actualRange.endOffset,
    159      "startOffset and endOffset must always be the same after extractContents()");
    160    assert_equals(expectedRange.startContainer, expectedRange.endContainer,
    161      "Test bug!  Expected startContainer and endContainer must always be the same after extractContents()");
    162    assert_equals(expectedRange.startOffset, expectedRange.endOffset,
    163      "Test bug!  Expected startOffset and endOffset must always be the same after extractContents()");
    164 
    165    assert_equals(actualRange.startOffset, expectedRange.startOffset,
    166      "Unexpected startOffset after extractContents()");
    167    // How do we decide that the two nodes are equal, since they're in
    168    // different trees?  Since the DOMs are the same, it's enough to check
    169    // that the index in the parent is the same all the way up the tree.
    170    // But we can first cheat by just checking they're actually equal.
    171    assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer),
    172      "Unexpected startContainer after extractContents(), expected " +
    173      expectedRange.startContainer.nodeName.toLowerCase() + " but got " +
    174      actualRange.startContainer.nodeName.toLowerCase());
    175    var currentActual = actualRange.startContainer;
    176    var currentExpected = expectedRange.startContainer;
    177    var actual = "";
    178    var expected = "";
    179    while (currentActual && currentExpected) {
    180      actual = indexOf(currentActual) + "-" + actual;
    181      expected = indexOf(currentExpected) + "-" + expected;
    182 
    183      currentActual = currentActual.parentNode;
    184      currentExpected = currentExpected.parentNode;
    185    }
    186    actual = actual.substr(0, actual.length - 1);
    187    expected = expected.substr(0, expected.length - 1);
    188    assert_equals(actual, expected,
    189      "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");
    190  });
    191  positionTests[i].done();
    192 
    193  fragTests[i].step(function() {
    194    assert_equals(actualIframe.contentWindow.unexpectedException, null,
    195      "Unexpected exception thrown when setting up Range for actual extractContents()");
    196    assert_equals(expectedIframe.contentWindow.unexpectedException, null,
    197      "Unexpected exception thrown when setting up Range for simulated extractContents()");
    198    assert_equals(typeof actualRange, "object",
    199      "typeof Range produced in actual iframe");
    200    assert_equals(typeof expectedRange, "object",
    201      "typeof Range produced in expected iframe");
    202 
    203    if (typeof expectedFrag == "string") {
    204      // Comparing makes no sense
    205      return;
    206    }
    207    assertNodesEqual(actualFrag, expectedFrag,
    208      "returned fragment");
    209  });
    210  fragTests[i].done();
    211 }
    212 
    213 // First test a detached Range, synchronously
    214 test(function() {
    215  var range = document.createRange();
    216  range.detach();
    217  assert_array_equals(range.extractContents().childNodes, []);
    218 }, "Detached Range");
    219 
    220 var iStart = 0;
    221 var iStop = testRanges.length;
    222 
    223 if (/subtest=[0-9]+/.test(location.search)) {
    224  var matches = /subtest=([0-9]+)/.exec(location.search);
    225  iStart = Number(matches[1]);
    226  iStop = Number(matches[1]) + 1;
    227 }
    228 
    229 var domTests = [];
    230 var positionTests = [];
    231 var fragTests = [];
    232 
    233 for (var i = iStart; i < iStop; i++) {
    234  domTests[i] = async_test("Resulting DOM for range " + i + " " + testRanges[i]);
    235  positionTests[i] = async_test("Resulting cursor position for range " + i + " " + testRanges[i]);
    236  fragTests[i] = async_test("Returned fragment for range " + i + " " + testRanges[i]);
    237 }
    238 
    239 var referenceDoc = document.implementation.createHTMLDocument("");
    240 referenceDoc.removeChild(referenceDoc.documentElement);
    241 
    242 actualIframe.onload = function() {
    243  expectedIframe.onload = function() {
    244    for (var i = iStart; i < iStop; i++) {
    245      testExtractContents(i);
    246    }
    247  }
    248  expectedIframe.src = "Range-test-iframe.html";
    249  referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true));
    250 }
    251 actualIframe.src = "Range-test-iframe.html";
    252 </script>