Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Side by Side Diff: third_party/WebKit/LayoutTests/imported/wpt/dom/ranges/Range-deleteContents.html

Issue 2482213003: Import WPT tests which require non-test HTML resources. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!doctype html>
2 <title>Range.deleteContents() 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 (lik e
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.cre ateDocumentType("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 myDeleteContents(range) {
55 // "If the context object's start and end are the same, abort this method."
56 if (range.startContainer == range.endContainer
57 && range.startOffset == range.endOffset) {
58 return;
59 }
60
61 // "Let original start node, original start offset, original end node, and
62 // original end offset be the context object's start and end nodes and
63 // offsets, respectively."
64 var originalStartNode = range.startContainer;
65 var originalStartOffset = range.startOffset;
66 var originalEndNode = range.endContainer;
67 var originalEndOffset = range.endOffset;
68
69 // "If original start node and original end node are the same, and they are
70 // a Text, ProcessingInstruction, or Comment node, replace data with node
71 // original start node, offset original start offset, count original end
72 // offset minus original start offset, and data the empty string, and then
73 // terminate these steps"
74 if (originalStartNode == originalEndNode
75 && (range.startContainer.nodeType == Node.TEXT_NODE
76 || range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE
77 || range.startContainer.nodeType == Node.COMMENT_NODE)) {
78 originalStartNode.deleteData(originalStartOffset, originalEndOffset - origin alStartOffset);
79 return;
80 }
81
82 // "Let nodes to remove be a list of all the Nodes that are contained in
83 // the context object, in tree order, omitting any Node whose parent is
84 // also contained in the context object."
85 //
86 // We rely on the fact that the contained nodes must lie in tree order
87 // between the start node, and the end node's last descendant (inclusive).
88 var nodesToRemove = [];
89 var stop = nextNodeDescendants(range.endContainer);
90 for (var node = range.startContainer; node != stop; node = nextNode(node)) {
91 if (isContained(node, range)
92 && !(node.parentNode && isContained(node.parentNode, range))) {
93 nodesToRemove.push(node);
94 }
95 }
96
97 // "If original start node is an ancestor container of original end node,
98 // set new node to original start node and new offset to original start
99 // offset."
100 var newNode;
101 var newOffset;
102 if (originalStartNode == originalEndNode
103 || originalEndNode.compareDocumentPosition(originalStartNode) & Node.DOCUMENT_ POSITION_CONTAINS) {
104 newNode = originalStartNode;
105 newOffset = originalStartOffset;
106 // "Otherwise:"
107 } else {
108 // "Let reference node equal original start node."
109 var referenceNode = originalStartNode;
110
111 // "While reference node's parent is not null and is not an ancestor
112 // container of original end node, set reference node to its parent."
113 while (referenceNode.parentNode
114 && referenceNode.parentNode != originalEndNode
115 && !(originalEndNode.compareDocumentPosition(referenceNode.parentNode) & Nod e.DOCUMENT_POSITION_CONTAINS)) {
116 referenceNode = referenceNode.parentNode;
117 }
118
119 // "Set new node to the parent of reference node, and new offset to one
120 // plus the index of reference node."
121 newNode = referenceNode.parentNode;
122 newOffset = 1 + indexOf(referenceNode);
123 }
124
125 // "If original start node is a Text, ProcessingInstruction, or Comment node,
126 // replace data with node original start node, offset original start offset,
127 // count original start node's length minus original start offset, data the
128 // empty start"
129 if (originalStartNode.nodeType == Node.TEXT_NODE
130 || originalStartNode.nodeType == Node.PROCESSING_INSTRUCTION_NODE
131 || originalStartNode.nodeType == Node.COMMENT_NODE) {
132 originalStartNode.deleteData(originalStartOffset, nodeLength(originalStartNo de) - originalStartOffset);
133 }
134
135 // "For each node in nodes to remove, in order, remove node from its
136 // parent."
137 for (var i = 0; i < nodesToRemove.length; i++) {
138 nodesToRemove[i].parentNode.removeChild(nodesToRemove[i]);
139 }
140
141 // "If original end node is a Text, ProcessingInstruction, or Comment node,
142 // replace data with node original end node, offset 0, count original end
143 // offset, and data the empty string."
144 if (originalEndNode.nodeType == Node.TEXT_NODE
145 || originalEndNode.nodeType == Node.PROCESSING_INSTRUCTION_NODE
146 || originalEndNode.nodeType == Node.COMMENT_NODE) {
147 originalEndNode.deleteData(0, originalEndOffset);
148 }
149
150 // "Set the context object's start and end to (new node, new offset)."
151 range.setStart(newNode, newOffset);
152 range.setEnd(newNode, newOffset);
153 }
154
155 function testDeleteContents(i) {
156 restoreIframe(actualIframe, i);
157 restoreIframe(expectedIframe, i);
158
159 var actualRange = actualIframe.contentWindow.testRange;
160 var expectedRange = expectedIframe.contentWindow.testRange;
161 var actualRoots, expectedRoots;
162
163 domTests[i].step(function() {
164 assert_equals(actualIframe.contentWindow.unexpectedException, null,
165 "Unexpected exception thrown when setting up Range for actual deleteConten ts()");
166 assert_equals(expectedIframe.contentWindow.unexpectedException, null,
167 "Unexpected exception thrown when setting up Range for simulated deleteCon tents()");
168 assert_equals(typeof actualRange, "object",
169 "typeof Range produced in actual iframe");
170 assert_equals(typeof expectedRange, "object",
171 "typeof Range produced in expected iframe");
172
173 // Just to be pedantic, we'll test not only that the tree we're
174 // modifying is the same in expected vs. actual, but also that all the
175 // nodes originally in it were the same. Typically some nodes will
176 // become detached when the algorithm is run, but they still exist and
177 // references can still be kept to them, so they should also remain the
178 // same.
179 //
180 // We initialize the list to all nodes, and later on remove all the
181 // ones which still have parents, since the parents will presumably be
182 // tested for isEqualNode() and checking the children would be
183 // redundant.
184 var actualAllNodes = [];
185 var node = furthestAncestor(actualRange.startContainer);
186 do {
187 actualAllNodes.push(node);
188 } while (node = nextNode(node));
189
190 var expectedAllNodes = [];
191 var node = furthestAncestor(expectedRange.startContainer);
192 do {
193 expectedAllNodes.push(node);
194 } while (node = nextNode(node));
195
196 actualRange.deleteContents();
197 myDeleteContents(expectedRange);
198
199 actualRoots = [];
200 for (var j = 0; j < actualAllNodes.length; j++) {
201 if (!actualAllNodes[j].parentNode) {
202 actualRoots.push(actualAllNodes[j]);
203 }
204 }
205
206 expectedRoots = [];
207 for (var j = 0; j < expectedAllNodes.length; j++) {
208 if (!expectedAllNodes[j].parentNode) {
209 expectedRoots.push(expectedAllNodes[j]);
210 }
211 }
212
213 for (var j = 0; j < actualRoots.length; j++) {
214 if (!actualRoots[j].isEqualNode(expectedRoots[j])) {
215 var msg = j ? "detached node #" + j : "tree root";
216 msg = "Actual and expected mismatch for " + msg + ". ";
217
218 // Find the specific error
219 var actual = actualRoots[j];
220 var expected = expectedRoots[j];
221
222 while (actual && expected) {
223 assert_equals(actual.nodeType, expected.nodeType,
224 msg + "First difference: differing nodeType");
225 assert_equals(actual.nodeName, expected.nodeName,
226 msg + "First difference: differing nodeName");
227 assert_equals(actual.nodeValue, expected.nodeValue,
228 msg + 'First difference: differing nodeValue (nodeName = "' + actual .nodeName + '")');
229 assert_equals(actual.childNodes.length, expected.childNodes.length,
230 msg + 'First difference: differing number of children (nodeName = "' + actual.nodeName + '")');
231 actual = nextNode(actual);
232 expected = nextNode(expected);
233 }
234
235 assert_unreached("DOMs were not equal but we couldn't figure out why");
236 }
237
238 if (j == 0) {
239 // Clearly something is wrong if the node lists are different
240 // lengths. We want to report this only after we've already
241 // checked the main tree for equality, though, so it doesn't
242 // mask more interesting errors.
243 assert_equals(actualRoots.length, expectedRoots.length,
244 "Actual and expected DOMs were broken up into a different number of pi eces by deleteContents() (this probably means you created or detached nodes when you weren't supposed to)");
245 }
246 }
247 });
248 domTests[i].done();
249
250 positionTests[i].step(function() {
251 assert_equals(actualIframe.contentWindow.unexpectedException, null,
252 "Unexpected exception thrown when setting up Range for actual deleteConten ts()");
253 assert_equals(expectedIframe.contentWindow.unexpectedException, null,
254 "Unexpected exception thrown when setting up Range for simulated deleteCon tents()");
255 assert_equals(typeof actualRange, "object",
256 "typeof Range produced in actual iframe");
257 assert_equals(typeof expectedRange, "object",
258 "typeof Range produced in expected iframe");
259 assert_true(actualRoots[0].isEqualNode(expectedRoots[0]),
260 "The resulting DOMs were not equal, so comparing positions makes no sense" );
261
262 assert_equals(actualRange.startContainer, actualRange.endContainer,
263 "startContainer and endContainer must always be the same after deleteConte nts()");
264 assert_equals(actualRange.startOffset, actualRange.endOffset,
265 "startOffset and endOffset must always be the same after deleteContents()" );
266 assert_equals(expectedRange.startContainer, expectedRange.endContainer,
267 "Test bug! Expected startContainer and endContainer must always be the sa me after deleteContents()");
268 assert_equals(expectedRange.startOffset, expectedRange.endOffset,
269 "Test bug! Expected startOffset and endOffset must always be the same aft er deleteContents()");
270
271 assert_equals(actualRange.startOffset, expectedRange.startOffset,
272 "Unexpected startOffset after deleteContents()");
273 // How do we decide that the two nodes are equal, since they're in
274 // different trees? Since the DOMs are the same, it's enough to check
275 // that the index in the parent is the same all the way up the tree.
276 // But we can first cheat by just checking they're actually equal.
277 assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContai ner),
278 "Unexpected startContainer after deleteContents(), expected " +
279 expectedRange.startContainer.nodeName.toLowerCase() + " but got " +
280 actualRange.startContainer.nodeName.toLowerCase());
281 var currentActual = actualRange.startContainer;
282 var currentExpected = expectedRange.startContainer;
283 var actual = "";
284 var expected = "";
285 while (currentActual && currentExpected) {
286 actual = indexOf(currentActual) + "-" + actual;
287 expected = indexOf(currentExpected) + "-" + expected;
288
289 currentActual = currentActual.parentNode;
290 currentExpected = currentExpected.parentNode;
291 }
292 actual = actual.substr(0, actual.length - 1);
293 expected = expected.substr(0, expected.length - 1);
294 assert_equals(actual, expected,
295 "startContainer superficially looks right but is actually the wrong node i f you trace back its index in all its ancestors (I'm surprised this actually hap pened");
296 });
297 positionTests[i].done();
298 }
299
300 // First test a detached Range, synchronously
301 test(function() {
302 var range = document.createRange();
303 range.detach();
304 range.deleteContents();
305 }, "Detached Range");
306
307 var iStart = 0;
308 var iStop = testRanges.length;
309
310 if (/subtest=[0-9]+/.test(location.search)) {
311 var matches = /subtest=([0-9]+)/.exec(location.search);
312 iStart = Number(matches[1]);
313 iStop = Number(matches[1]) + 1;
314 }
315
316 var domTests = [];
317 var positionTests = [];
318
319 for (var i = iStart; i < iStop; i++) {
320 domTests[i] = async_test("Resulting DOM for range " + i + " " + testRanges[i]) ;
321 positionTests[i] = async_test("Resulting cursor position for range " + i + " " + testRanges[i]);
322 }
323
324 var referenceDoc = document.implementation.createHTMLDocument("");
325 referenceDoc.removeChild(referenceDoc.documentElement);
326
327 actualIframe.onload = function() {
328 expectedIframe.onload = function() {
329 for (var i = iStart; i < iStop; i++) {
330 testDeleteContents(i);
331 }
332 }
333 expectedIframe.src = "Range-test-iframe.html";
334 referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNod e(true));
335 }
336 actualIframe.src = "Range-test-iframe.html";
337 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698