Rename files for brevity
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 11 Oct 2011 15:35:33 -0600
changeset 644 2a39ece41cdb
parent 643 8e67144eadbd
child 645 78d3e43c01a3
Rename files for brevity
selecttest/Selection-addRange.html
selecttest/Selection-collapse.html
selecttest/Selection-collapseToStartEnd.html
selecttest/Selection-dir.html
selecttest/Selection-extend.html
selecttest/Selection-getRangeAt.html
selecttest/addRange.html
selecttest/collapse.html
selecttest/collapseToStartEnd.html
selecttest/dir.html
selecttest/extend.html
selecttest/getRangeAt.html
--- a/selecttest/Selection-addRange.html	Tue Oct 11 15:30:30 2011 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-<!doctype html>
-<title>Selection.addRange() tests</title>
-<div id=log></div>
-<script src=http://w3c-test.org/resources/testharness.js></script>
-<script src=common.js></script>
-<script>
-"use strict";
-
-function testAddRange(exception, range, endpoints, qualifier, testName) {
-	test(function() {
-		assert_equals(exception, null, "Test setup must not throw exceptions");
-
-		selection.addRange(range);
-
-		assert_equals(range.startContainer, endpoints[0],
-			"addRange() must not modify the startContainer of the Range it's given");
-		assert_equals(range.startOffset, endpoints[1],
-			"addRange() must not modify the startOffset of the Range it's given");
-		assert_equals(range.endContainer, endpoints[2],
-			"addRange() must not modify the endContainer of the Range it's given");
-		assert_equals(range.endOffset, endpoints[3],
-			"addRange() must not modify the endOffset of the Range it's given");
-	}, testName + ": " + qualifier + " addRange() must not throw exceptions or modify the range it's given");
-
-	test(function() {
-		assert_equals(exception, null, "Test setup must not throw exceptions");
-
-		assert_equals(selection.rangeCount, 1, "rangeCount must be 1");
-	}, testName + ": " + qualifier + " addRange() must result in rangeCount being 1");
-
-	// From here on out we check selection.getRangeAt(selection.rangeCount - 1)
-	// so as not to double-fail Gecko.
-
-	test(function() {
-		assert_equals(exception, null, "Test setup must not throw exceptions");
-		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
-
-		var newRange = selection.getRangeAt(selection.rangeCount - 1);
-
-		assert_not_equals(newRange, null,
-			"getRangeAt(rangeCount - 1) must not return null");
-		assert_equals(typeof newRange, "object",
-			"getRangeAt(rangeCount - 1) must return an object");
-
-		assert_equals(newRange.startContainer, range.startContainer,
-			"startContainer of the Selection's last Range must match the added Range");
-		assert_equals(newRange.startOffset, range.startOffset,
-			"startOffset of the Selection's last Range must match the added Range");
-		assert_equals(newRange.endContainer, range.endContainer,
-			"endContainer of the Selection's last Range must match the added Range");
-		assert_equals(newRange.endOffset, range.endOffset,
-			"endOffset of the Selection's last Range must match the added Range");
-	}, testName + ": " + qualifier + " addRange() must result in the selection's last range having the specified endpoints");
-
-	test(function() {
-		assert_equals(exception, null, "Test setup must not throw exceptions");
-		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
-
-		assert_equals(selection.getRangeAt(selection.rangeCount - 1), range,
-			"getRangeAt(rangeCount - 1) must return the same object we added");
-	}, testName + ": " + qualifier + " addRange() must result in the selection's last range being the same object we added");
-
-	// Let's not test many different modifications -- one should be enough.
-	test(function() {
-		assert_equals(exception, null, "Test setup must not throw exceptions");
-		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
-
-		if (range.startContainer == paras[0].firstChild
-		&& range.startOffset == 0
-		&& range.endContainer == paras[0].firstChild
-		&& range.endOffset == 2) {
-			// Just in case . . .
-			range.setStart(paras[0].firstChild, 1);
-		} else {
-			range.setStart(paras[0].firstChild, 0);
-			range.setEnd(paras[0].firstChild, 2);
-		}
-
-		var newRange = selection.getRangeAt(selection.rangeCount - 1);
-
-		assert_equals(newRange.startContainer, range.startContainer,
-			"After mutating the " + qualifier + " added Range, startContainer of the Selection's last Range must match the added Range");
-		assert_equals(newRange.startOffset, range.startOffset,
-			"After mutating the " + qualifier + " added Range, startOffset of the Selection's last Range must match the added Range");
-		assert_equals(newRange.endContainer, range.endContainer,
-			"After mutating the " + qualifier + " added Range, endContainer of the Selection's last Range must match the added Range");
-		assert_equals(newRange.endOffset, range.endOffset,
-			"After mutating the " + qualifier + " added Range, endOffset of the Selection's last Range must match the added Range");
-	}, testName + ": modifying the " + qualifier + " added range must modify the Selection's last Range");
-
-	// Now test the other way too.
-	test(function() {
-		assert_equals(exception, null, "Test setup must not throw exceptions");
-		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
-
-		var newRange = selection.getRangeAt(selection.rangeCount - 1);
-
-		if (newRange.startContainer == paras[0].firstChild
-		&& newRange.startOffset == 4
-		&& newRange.endContainer == paras[0].firstChild
-		&& newRange.endOffset == 6) {
-			newRange.setStart(paras[0].firstChild, 5);
-		} else {
-			newRange.setStart(paras[0].firstChild, 4);
-			newRange.setStart(paras[0].firstChild, 6);
-		}
-
-		assert_equals(newRange.startContainer, range.startContainer,
-			"After " + qualifier + " addRange(), after mutating the Selection's last Range, startContainer of the Selection's last Range must match the added Range");
-		assert_equals(newRange.startOffset, range.startOffset,
-			"After " + qualifier + " addRange(), after mutating the Selection's last Range, startOffset of the Selection's last Range must match the added Range");
-		assert_equals(newRange.endContainer, range.endContainer,
-			"After " + qualifier + " addRange(), after mutating the Selection's last Range, endContainer of the Selection's last Range must match the added Range");
-		assert_equals(newRange.endOffset, range.endOffset,
-			"After " + qualifier + " addRange(), after mutating the Selection's last Range, endOffset of the Selection's last Range must match the added Range");
-	}, testName + ": modifying the Selection's last Range must modify the " + qualifier + " added Range");
-}
-
-// Do only n evals, not n^2
-var testRangesEvaled = testRanges.map(eval);
-
-for (var i = 0; i < testRanges.length; i++) {
-	for (var j = 0; j < testRanges.length; j++) {
-		var testName = "Range " + i + " " + testRanges[i]
-			+ " followed by Range " + j + " " + testRanges[j];
-
-		var exception = null;
-		try {
-			selection.removeAllRanges();
-
-			var endpoints1 = testRangesEvaled[i];
-			var range1 = ownerDocument(endpoints1[0]).createRange();
-			range1.setStart(endpoints1[0], endpoints1[1]);
-			range1.setEnd(endpoints1[2], endpoints1[3]);
-
-			if (range1.startContainer !== endpoints1[0]) {
-				throw "Sanity check: the first Range we created must have the desired startContainer";
-			}
-			if (range1.startOffset !== endpoints1[1]) {
-				throw "Sanity check: the first Range we created must have the desired startOffset";
-			}
-			if (range1.endContainer !== endpoints1[2]) {
-				throw "Sanity check: the first Range we created must have the desired endContainer";
-			}
-			if (range1.endOffset !== endpoints1[3]) {
-				throw "Sanity check: the first Range we created must have the desired endOffset";
-			}
-
-			var endpoints2 = testRangesEvaled[j];
-			var range2 = ownerDocument(endpoints2[0]).createRange();
-			range2.setStart(endpoints2[0], endpoints2[1]);
-			range2.setEnd(endpoints2[2], endpoints2[3]);
-
-			if (range2.startContainer !== endpoints2[0]) {
-				throw "Sanity check: the second Range we created must have the desired startContainer";
-			}
-			if (range2.startOffset !== endpoints2[1]) {
-				throw "Sanity check: the second Range we created must have the desired startOffset";
-			}
-			if (range2.endContainer !== endpoints2[2]) {
-				throw "Sanity check: the second Range we created must have the desired endContainer";
-			}
-			if (range2.endOffset !== endpoints2[3]) {
-				throw "Sanity check: the second Range we created must have the desired endOffset";
-			}
-		} catch (e) {
-			exception = e;
-		}
-
-		testAddRange(exception, range1, endpoints1, "first", testName);
-		testAddRange(exception, range2, endpoints2, "second", testName);
-	}
-}
-
-testDiv.style.display = "none";
-</script>
--- a/selecttest/Selection-collapse.html	Tue Oct 11 15:30:30 2011 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-<!doctype html>
-<title>Selection.collapse() tests</title>
-<div id=log></div>
-<script src=http://w3c-test.org/resources/testharness.js></script>
-<script src=common.js></script>
-<script>
-"use strict";
-
-function testCollapse(range, point) {
-	selection.removeAllRanges();
-	var addedRange;
-	if (range) {
-		addedRange = range.cloneRange();
-		selection.addRange(addedRange);
-	}
-
-	if (point[0].nodeType == Node.DOCUMENT_TYPE_NODE
-	|| point[0].nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
-		assert_throws("INVALID_NODE_TYPE_ERR", function() {
-			selection.collapse(point[0], point[1]);
-		}, "Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType or ProcessingInstruction");
-		return;
-	}
-
-	if (point[1] < 0 || point[1] > nodeLength(point[0])) {
-		assert_throws("INDEX_SIZE_ERR", function() {
-			selection.collapse(point[0], point[1]);
-		}, "Must throw INDEX_SIZE_ERR when collapse()ing if the offset is negative or greater than the node's length");
-		return;
-	}
-
-	selection.collapse(point[0], point[1]);
-
-	assert_equals(selection.rangeCount, 1,
-		"selection.rangeCount must equal 1 after collapse()");
-	assert_equals(selection.focusNode, point[0],
-		"focusNode must equal the node we collapse()d to");
-	assert_equals(selection.focusOffset, point[1],
-		"focusOffset must equal the offset we collapse()d to");
-	assert_equals(selection.focusNode, selection.anchorNode,
-		"focusNode and anchorNode must be equal after collapse()");
-	assert_equals(selection.focusOffset, selection.anchorOffset,
-		"focusOffset and anchorOffset must be equal after collapse()");
-	if (range) {
-		assert_equals(addedRange.startContainer, range.startContainer,
-			"collapse() must not change the startContainer of a preexisting Range");
-		assert_equals(addedRange.endContainer, range.endContainer,
-			"collapse() must not change the endContainer of a preexisting Range");
-		assert_equals(addedRange.startOffset, range.startOffset,
-			"collapse() must not change the startOffset of a preexisting Range");
-		assert_equals(addedRange.endOffset, range.endOffset,
-			"collapse() must not change the endOffset of a preexisting Range");
-	}
-}
-
-// Also test a selection with no ranges
-testRanges.unshift("[]");
-
-// Don't want to eval() each point a bazillion times
-var testPointsCached = [];
-for (var i = 0; i < testPoints.length; i++) {
-	testPointsCached.push(eval(testPoints[i]));
-}
-
-var tests = [];
-for (var i = 0; i < testRanges.length; i++) {
-	var endpoints = eval(testRanges[i]);
-	var range;
-	test(function() {
-		if (endpoints.length) {
-			range = ownerDocument(endpoints[0]).createRange();
-			range.setStart(endpoints[0], endpoints[1]);
-			range.setEnd(endpoints[2], endpoints[3]);
-		} else {
-			// Empty selection
-			range = null;
-		}
-	}, "Set up range " + i + " " + testRanges[i]);
-	for (var j = 0; j < testPoints.length; j++) {
-		tests.push(["Range " + i + " " + testRanges[i] + ", point " + j + " " + testPoints[j], range, testPointsCached[j]]);
-	}
-}
-
-generate_tests(testCollapse, tests);
-
-testDiv.style.display = "none";
-</script>
--- a/selecttest/Selection-collapseToStartEnd.html	Tue Oct 11 15:30:30 2011 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-<!doctype html>
-<title>Selection.collapseTo(Start|End)() tests</title>
-<div id=log></div>
-<script src=http://w3c-test.org/resources/testharness.js></script>
-<script src=common.js></script>
-<script>
-"use strict";
-
-function testCollapseToStartEnd(range) {
-}
-
-// Also test a selection with no ranges
-testRanges.unshift("[]");
-
-for (var i = 0; i < testRanges.length; i++) {
-	test(function() {
-		selection.removeAllRanges();
-		var endpoints = eval(testRanges[i]);
-		if (!endpoints.length) {
-			assert_throws("INVALID_STATE_ERR", function() {
-				selection.collapseToStart();
-			}, "Must throw InvalidStateErr if the selection's range is null");
-			return;
-		}
-
-		var addedRange = ownerDocument(endpoints[0]).createRange();
-		addedRange.setStart(endpoints[0], endpoints[1]);
-		addedRange.setEnd(endpoints[2], endpoints[3]);
-		selection.addRange(addedRange);
-
-		// We don't penalize browsers here for mishandling addRange() and
-		// adding a different range than we specified.  They fail addRange()
-		// tests for that, and don't have to fail collapseToStart/End() tests
-		// too.  They do fail if they throw unexpectedly, though.  I also fail
-		// them if there's no range at all, because otherwise they could pass
-		// all tests if addRange() always does nothing and collapseToStart()
-		// always throws.
-		assert_equals(selection.rangeCount, 1,
-			"Sanity check: rangeCount must equal 1 after addRange()");
-
-		var expectedEndpoint = [
-			selection.getRangeAt(0).startContainer,
-			selection.getRangeAt(0).startOffset
-		];
-
-		selection.collapseToStart();
-
-		assert_equals(selection.rangeCount, 1,
-			"selection.rangeCount must equal 1");
-		assert_equals(selection.focusNode, expectedEndpoint[0],
-			"focusNode must equal the original start node");
-		assert_equals(selection.focusOffset, expectedEndpoint[1],
-			"focusOffset must equal the original start offset");
-		assert_equals(selection.anchorNode, expectedEndpoint[0],
-			"anchorNode must equal the original start node");
-		assert_equals(selection.anchorOffset, expectedEndpoint[1],
-			"anchorOffset must equal the original start offset");
-		assert_equals(addedRange.startContainer, endpoints[0],
-			"collapseToStart() must not change the startContainer of the selection's original range");
-		assert_equals(addedRange.startOffset, endpoints[1],
-			"collapseToStart() must not change the startOffset of the selection's original range");
-		assert_equals(addedRange.endContainer, endpoints[2],
-			"collapseToStart() must not change the endContainer of the selection's original range");
-		assert_equals(addedRange.endOffset, endpoints[3],
-			"collapseToStart() must not change the endOffset of the selection's original range");
-	}, "Range " + i + " " + testRanges[i] + " collapseToStart()");
-
-	// Copy-paste of above
-	test(function() {
-		selection.removeAllRanges();
-		var endpoints = eval(testRanges[i]);
-		if (!endpoints.length) {
-			assert_throws("INVALID_STATE_ERR", function() {
-				selection.collapseToEnd();
-			}, "Must throw InvalidStateErr if the selection's range is null");
-			return;
-		}
-
-		var addedRange = ownerDocument(endpoints[0]).createRange();
-		addedRange.setStart(endpoints[0], endpoints[1]);
-		addedRange.setEnd(endpoints[2], endpoints[3]);
-		selection.addRange(addedRange);
-
-		// We don't penalize browsers here for mishandling addRange() and
-		// adding a different range than we specified.  They fail addRange()
-		// tests for that, and don't have to fail collapseToStart/End() tests
-		// too.  They do fail if they throw unexpectedly, though.  I also fail
-		// them if there's no range at all, because otherwise they could pass
-		// all tests if addRange() always does nothing and collapseToStart()
-		// always throws.
-		assert_equals(selection.rangeCount, 1,
-			"Sanity check: rangeCount must equal 1 after addRange()");
-
-		var expectedEndpoint = [
-			selection.getRangeAt(0).endContainer,
-			selection.getRangeAt(0).endOffset
-		];
-
-		selection.collapseToEnd();
-
-		assert_equals(selection.rangeCount, 1,
-			"selection.rangeCount must equal 1");
-		assert_equals(selection.focusNode, expectedEndpoint[0],
-			"focusNode must equal the original end node");
-		assert_equals(selection.focusOffset, expectedEndpoint[1],
-			"focusOffset must equal the original end offset");
-		assert_equals(selection.anchorNode, expectedEndpoint[0],
-			"anchorNode must equal the original end node");
-		assert_equals(selection.anchorOffset, expectedEndpoint[1],
-			"anchorOffset must equal the original end offset");
-		assert_equals(addedRange.startContainer, endpoints[0],
-			"collapseToEnd() must not change the startContainer of the selection's original range");
-		assert_equals(addedRange.startOffset, endpoints[1],
-			"collapseToEnd() must not change the startOffset of the selection's original range");
-		assert_equals(addedRange.endContainer, endpoints[2],
-			"collapseToEnd() must not change the endContainer of the selection's original range");
-		assert_equals(addedRange.endOffset, endpoints[3],
-			"collapseToEnd() must not change the endOffset of the selection's original range");
-	}, "Range " + i + " " + testRanges[i] + " collapseToEnd()");
-}
-
-testDiv.style.display = "none";
-</script>
--- a/selecttest/Selection-dir.html	Tue Oct 11 15:30:30 2011 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-<!doctype html>
-<title>Selection direction tests</title>
-<meta charset=utf-8>
-<div id=test>
-	<p>This is a manual test, since there's no way to synthesize keyboard or
-	mouse input.  Click after the letter "c" in the following paragraph and
-	drag backwards so that both the "b" and the "c" are highlighted, then click
-	the "Test" button:
-
-	<p>abcd <button onclick=testDirection()>Test</button>
-
-	<p>efghi
-</div>
-<div id=log></div>
-<script src=http://w3c-test.org/resources/testharness.js></script>
-<script>
-setup({explicit_done: true});
-
-function testDirection() {
-	var testDiv = document.getElementById("test");
-	var p = testDiv.getElementsByTagName("p")[1].firstChild;
-	var selection = getSelection();
-	var range = selection.getRangeAt(0);
-	test(function() {
-		assert_equals(range.toString(), "bc");
-	}, "The expected range is selected");
-	test(function() {
-		assert_equals(selection.anchorNode, p);
-		assert_equals(selection.focusNode, p);
-	}, "Expected node is initially selected");
-	test(function() {
-		assert_array_equals([selection.anchorOffset, selection.focusOffset].sort(), [1, 3]);
-	}, "Expected offsets are initially selected (maybe not in order)");
-	test(function() {
-		assert_equals(selection.anchorOffset, 3);
-		assert_equals(selection.focusOffset, 1);
-	}, "Offsets are backwards for initial selection"),
-	test(function() {
-		assert_equals(selection.anchorNode, range.endContainer);
-		assert_equals(selection.anchorOffset, range.endOffset);
-		assert_equals(selection.focusNode, range.startContainer);
-		assert_equals(selection.focusOffset, range.startOffset);
-	}, "Offsets match the range for initial selection");
-
-	// Per spec, the direction of the selection remains even if you zap a range
-	// and add a new one.
-	test(function() {
-		selection.removeRange(range);
-		range = document.createRange();
-		p = testDiv.getElementsByTagName("p")[0].firstChild;
-		range.setStart(p, 0);
-		range.setEnd(p, 4);
-		assert_equals(range.toString(), "This");
-		selection.addRange(range);
-	}, "removeRange()/addRange() successful");
-	test(function() {
-		assert_equals(selection.anchorNode, p);
-		assert_equals(selection.focusNode, p);
-	}, "Expected node is selected after remove/addRange()");
-	test(function() {
-		assert_array_equals([selection.anchorOffset, selection.focusOffset].sort(), [0, 4]);
-	}, "Expected offsets are selected after remove/addRange() (maybe not in order)");
-	test(function() {
-		assert_equals(selection.anchorOffset, 4);
-		assert_equals(selection.focusOffset, 0);
-	}, "Offsets are backwards after remove/addRange()"),
-	test(function() {
-		assert_equals(selection.anchorNode, range.endContainer);
-		assert_equals(selection.anchorOffset, range.endOffset);
-		assert_equals(selection.focusNode, range.startContainer);
-		assert_equals(selection.focusOffset, range.startOffset);
-	}, "Offsets match the range after remove/addRange()");
-
-	// But if you call removeAllRanges(), the direction should reset to
-	// forwards.
-	test(function() {
-		selection.removeAllRanges();
-		range = document.createRange();
-		p = testDiv.getElementsByTagName("p")[2].firstChild;
-		range.setStart(p, 2);
-		range.setEnd(p, 5);
-		assert_equals(range.toString(), "ghi");
-		selection.addRange(range);
-	}, "removeAllRanges() successful");
-	test(function() {
-		assert_equals(selection.anchorNode, p);
-		assert_equals(selection.focusNode, p);
-	}, "Expected node is selected after removeAllRanges()");
-	test(function() {
-		assert_array_equals([selection.anchorOffset, selection.focusOffset].sort(), [2, 5]);
-	}, "Expected offsets are selected after removeAllRanges() (maybe not in order)");
-	test(function() {
-		assert_equals(selection.anchorOffset, 2);
-		assert_equals(selection.focusOffset, 5);
-	}, "Offsets are forwards after removeAllRanges()");
-	test(function() {
-		assert_equals(selection.anchorNode, range.startContainer);
-		assert_equals(selection.anchorOffset, range.startOffset);
-		assert_equals(selection.focusNode, range.endContainer);
-		assert_equals(selection.focusOffset, range.endOffset);
-	}, "Offsets match the range after removeAllRanges()");
-
-	done();
-}
-</script>
--- a/selecttest/Selection-extend.html	Tue Oct 11 15:30:30 2011 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-<!doctype html>
-<title>Selection extend() tests</title>
-<meta charset=utf-8>
-<body>
-<script src=http://w3c-test.org/resources/testharness.js></script>
-<script src=common.js></script>
-<div id=log></div>
-<script>
-/**
- * Returns "forwards" if the selection direction is forwards, "backwards" if
- * it's backwards.  This appears not to work in WebKit at all, because there
- * seems to be no way of adding a range or replacing the current range without
- * calling removeAllRanges(), which resets the direction.  So we're nice and
- * look at the current range if possible; otherwise we do some stuff that
- * involves calling removeRange(), which doesn't exist in WebKit, so it will
- * fail the test.
- */
-function getSelectionDirection() {
-	if (selection.anchorNode != selection.focusNode
-	|| selection.anchorOffset != selection.focusOffset) {
-		var range = selection.getRangeAt(selection.rangeCount - 1);
-		// We can determine the direction without mangling anything.
-		if (selection.anchorNode == range.startContainer
-		&& selection.anchorOffset == range.startOffset) {
-			return "forwards";
-		}
-		if (selection.anchorNode == range.endContainer
-		&& selection.anchorOffset == range.endOffset) {
-			return "backwards";
-		}
-		throw "Something buggy with directions";
-	}
-
-	var range = document.createRange();
-	range.setStart(paras[0].firstChild, 0);
-	range.setEnd(paras[0].firstChild, 1);
-	selection.addRange(range);
-	if (selection.anchorOffset == range.startOffset) {
-		selection.removeRange(range);
-		return "forwards";
-	}
-	if (selection.anchorOffset == range.endOffset) {
-		selection.removeRange(range);
-		return "backwards";
-	}
-}
-
-/**
- * We test Selections that go both forwards and backwards here.  In the latter
- * case we need to use extend() to force it to go backwards, which is fair
- * enough, since that's what we're testing.
- */
-
-var originalSelectionDirection;
-
-function testExtendForwards(initialRanges, extendTarget) {
-	originalSelectionDirection = "forwards";
-	selection.removeAllRanges();
-
-	for (var i = 0; i < initialRanges.length; i += 4) {
-		var range = ownerDocument(initialRanges[i]).createRange();
-		range.setStart(initialRanges[i], initialRanges[i + 1]);
-		range.setEnd(initialRanges[i + 2], initialRanges[i + 3]);
-		selection.addRange(range);
-	}
-
-	testExtend(extendTarget, initialRanges.length/4);
-}
-
-function testExtendBackwards(initialRanges, extendTarget) {
-	originalSelectionDirection = "backwards";
-	selection.removeAllRanges();
-
-	for (var i = 0; i < initialRanges.length; i += 4) {
-		// To get a backwards selection, we add ranges by appending a
-		// zero-length range at the end, then extend()ing backwards to the
-		// start.  This fails in Opera, since Opera ignores addRange() on a
-		// collapsed range.  FIXME: This doesn't actually make the initial
-		// selection backwards, if the range we're given is collapsed.
-		var range = ownerDocument(initialRanges[i]).createRange();
-		range.setStart(initialRanges[i + 2], initialRanges[i + 3]);
-		range.setEnd(initialRanges[i + 2], initialRanges[i + 3]);
-		selection.addRange(range);
-		selection.extend(initialRanges[i], initialRanges[i + 1]);
-	}
-
-	testExtend(extendTarget, initialRanges.length/4);
-}
-
-function testExtend(extendTarget, numRanges) {
-	assert_equals(selection.rangeCount, numRanges,
-		"Failed sanity check: selection.rangeCount is wrong.  Perhaps addRange() failed.");
-
-	var node = extendTarget[0];
-	var offset = extendTarget[1];
-
-	if (node === null) {
-		assert_throws("TYPE_MISMATCH_ERR", function() {
-			selection.extend(node, offset);
-		}, "extend(null, foo) must throw TYPE_MISMATCH_ERR");
-		return;
-	}
-
-	if (selection.rangeCount == 0) {
-		assert_throws("INVALID_STATE_ERR", function() {
-			selection.extend(node, offset);
-		}, "extend() when rangeCount is 0 must throw INVALID_STATE_ERR");
-		return;
-	}
-
-	if (node.nodeType == Node.DOCUMENT_TYPE_NODE
-	|| node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
-		assert_throws("INVALID_NODE_TYPE_ERR", function() {
-			selection.extend(node, offset);
-		}, "extend() to a doctype or PI must throw INVALID_NODE_TYPE_ERR");
-		return;
-	}
-
-	if (offset < 0 || offset > nodeLength(node)) {
-		assert_throws("INDEX_SIZE_ERR", function() {
-			selection.extend(node, offset);
-		}, "extend() to an offset that's negative or greater than node length (" + nodeLength(node) + ") must throw INDEX_SIZE_ERR");
-		return;
-	}
-
-	var range = selection.getRangeAt(selection.rangeCount - 1);
-	var rangeRoot = furthestAncestor(range.startContainer);
-	var nodeRoot = furthestAncestor(node);
-
-	assert_equals(rangeRoot, furthestAncestor(range.endContainer),
-		"The furthest ancestor of a Range's start and end must always be the same (I think)");
-
-	if (rangeRoot != nodeRoot) {
-		selection.extend(node, offset);
-		assert_equals(selection.anchorNode, node,
-			"If the furthest ancestors of the range and extend() target differ, anchorNode must be set to the target node");
-		assert_equals(selection.anchorOffset, offset,
-			"If the furthest ancestors of the range and extend() target differ, anchorOffset must be set to the target offset");
-		assert_equals(selection.focusNode, node,
-			"If the furthest ancestors of the range and extend() target differ, focusNode must be set to the target node");
-		assert_equals(selection.focusOffset, offset,
-			"If the furthest ancestors of the range and extend() target differ, focusOffset must be set to the target offset");
-		assert_equals(getSelectionDirection(), "backwards",
-			"If the furthest ancestors of the range and extent() target differ, the new selection must be backwards");
-		return;
-	}
-
-	if (selection.focusNode == node && selection.focusOffset == offset) {
-		// extend() must do nothing.
-		var oldFocusNode = selection.focusNode;
-		var oldFocusOffset = selection.focusOffset;
-		var oldAnchorNode = selection.anchorNode;
-		var oldAnchorOffset = selection.anchorOffset;
-		var oldRanges = [];
-		for (var i = 0; i < selection.rangeCount; i++) {
-			oldRanges.push(selection.getRangeAt(i));
-		}
-		selection.extend(node, offset);
-		assert_equals(selection.focusNode, oldFocusNode,
-			"extend() to the current focus must not change focusNode");
-		assert_equals(selection.focusOffset, oldFocusOffset,
-			"extend() to the current focus must not change focusOffset");
-		assert_equals(selection.anchorNode, oldAnchorNode,
-			"extend() to the current focus must not change anchorNode");
-		assert_equals(selection.anchorOffset, oldAnchorOffset,
-			"extend() to the current focus must not change anchorOffset");
-		assert_equals(selection.rangeCount, oldRanges.length,
-			"extend() to the current focus must not change rangeCount");
-		for (var i = 0; i < oldRanges.length; i++) {
-			assert_equals(selection.getRangeAt(i), oldRanges[i],
-				"extend() to the current focus must not change any Ranges");
-		}
-		assert_equals(getSelectionDirection(), originalSelectionDirection,
-			"extend() of a selection to the current focus must not change direction");
-		return;
-	}
-
-	var oldAnchorNode = selection.anchorNode;
-	var oldAnchorOffset = selection.anchorOffset;
-	var oldFocusNode = selection.focusNode;
-	var oldFocusOffset = selection.focusOffset;
-	var oldRanges = [];
-	for (var i = 0; i < selection.rangeCount; i++) {
-		oldRanges.push(selection.getRangeAt(i));
-	}
-	selection.extend(node, offset);
-	assert_equals(selection.anchorNode, oldAnchorNode,
-		"extend() must not change anchorNode in the usual case");
-	assert_equals(selection.anchorOffset, oldAnchorOffset,
-		"extend() must not change anchorOffset in the usual case");
-	assert_equals(selection.rangeCount, oldRanges.length,
-		"extend() must not change rangeCount in the usual case");
-	for (var i = 0; i < oldRanges.length - 1; i++) {
-		assert_equals(selection.getRangeAt(i), oldRanges[i],
-			"extend() must not change any Range but the last in the usual case");
-	}
-	assert_equals(selection.focusNode, node,
-		"extend() must update focusNode to the target node in the usual case");
-	assert_equals(selection.focusOffset, offset,
-		"extend() must update focusOffset to the target offset in the usual case");
-
-	var expectedDirection;
-	var range = document.createRange();
-	range.setStart(oldAnchorNode, oldAnchorOffset);
-	range.setEnd(oldAnchorNode, oldAnchorOffset);
-	if (range.comparePoint(node, offset) >= 0) {
-		expectedDirection = "forwards";
-	} else {
-		expectedDirection = "backwards";
-	}
-	assert_equals(getSelectionDirection(), expectedDirection,
-		"extend() must set direction appropriately in the usual case");
-}
-
-// Also test a selection with no ranges
-testRanges.unshift("[]");
-
-var tests = [];
-for (var i = 0; i < testRanges.length; i++) {
-	for (var j = 0; j < testPoints.length; j++) {
-		tests.push([
-			"extend() forwards with range " + i + " " + testRanges[i] + " and point " + j + " " + testPoints[j],
-			eval(testRanges[i]),
-			eval(testPoints[j])
-		]);
-	}
-}
-generate_tests(testExtendForwards, tests);
-
-// Copy-pasted with "forwards" changed to "backwards" :/
-var tests = [];
-for (var i = 0; i < testRanges.length; i++) {
-	for (var j = 0; j < testPoints.length; j++) {
-		tests.push([
-			"extend() backwards with range " + i + " " + testRanges[i] + " and point " + j + " " + testPoints[j],
-			eval(testRanges[i]),
-			eval(testPoints[j])
-		]);
-	}
-}
-generate_tests(testExtendBackwards, tests);
-
-// Let's be tidy.
-testDiv.style.display = "none";
-</script>
--- a/selecttest/Selection-getRangeAt.html	Tue Oct 11 15:30:30 2011 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<title>The getRangeAt method</title>
-<div id=log></div>
-<script src=http://w3c-test.org/resources/testharness.js></script>
-<script>
-test(function() {
-  var sel = getSelection();
-  var range = document.createRange();
-  sel.addRange(range);
-  assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(-1); })
-  assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(1); })
-});
-</script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/addRange.html	Tue Oct 11 15:35:33 2011 -0600
@@ -0,0 +1,176 @@
+<!doctype html>
+<title>Selection.addRange() tests</title>
+<div id=log></div>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script src=common.js></script>
+<script>
+"use strict";
+
+function testAddRange(exception, range, endpoints, qualifier, testName) {
+	test(function() {
+		assert_equals(exception, null, "Test setup must not throw exceptions");
+
+		selection.addRange(range);
+
+		assert_equals(range.startContainer, endpoints[0],
+			"addRange() must not modify the startContainer of the Range it's given");
+		assert_equals(range.startOffset, endpoints[1],
+			"addRange() must not modify the startOffset of the Range it's given");
+		assert_equals(range.endContainer, endpoints[2],
+			"addRange() must not modify the endContainer of the Range it's given");
+		assert_equals(range.endOffset, endpoints[3],
+			"addRange() must not modify the endOffset of the Range it's given");
+	}, testName + ": " + qualifier + " addRange() must not throw exceptions or modify the range it's given");
+
+	test(function() {
+		assert_equals(exception, null, "Test setup must not throw exceptions");
+
+		assert_equals(selection.rangeCount, 1, "rangeCount must be 1");
+	}, testName + ": " + qualifier + " addRange() must result in rangeCount being 1");
+
+	// From here on out we check selection.getRangeAt(selection.rangeCount - 1)
+	// so as not to double-fail Gecko.
+
+	test(function() {
+		assert_equals(exception, null, "Test setup must not throw exceptions");
+		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
+
+		var newRange = selection.getRangeAt(selection.rangeCount - 1);
+
+		assert_not_equals(newRange, null,
+			"getRangeAt(rangeCount - 1) must not return null");
+		assert_equals(typeof newRange, "object",
+			"getRangeAt(rangeCount - 1) must return an object");
+
+		assert_equals(newRange.startContainer, range.startContainer,
+			"startContainer of the Selection's last Range must match the added Range");
+		assert_equals(newRange.startOffset, range.startOffset,
+			"startOffset of the Selection's last Range must match the added Range");
+		assert_equals(newRange.endContainer, range.endContainer,
+			"endContainer of the Selection's last Range must match the added Range");
+		assert_equals(newRange.endOffset, range.endOffset,
+			"endOffset of the Selection's last Range must match the added Range");
+	}, testName + ": " + qualifier + " addRange() must result in the selection's last range having the specified endpoints");
+
+	test(function() {
+		assert_equals(exception, null, "Test setup must not throw exceptions");
+		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
+
+		assert_equals(selection.getRangeAt(selection.rangeCount - 1), range,
+			"getRangeAt(rangeCount - 1) must return the same object we added");
+	}, testName + ": " + qualifier + " addRange() must result in the selection's last range being the same object we added");
+
+	// Let's not test many different modifications -- one should be enough.
+	test(function() {
+		assert_equals(exception, null, "Test setup must not throw exceptions");
+		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
+
+		if (range.startContainer == paras[0].firstChild
+		&& range.startOffset == 0
+		&& range.endContainer == paras[0].firstChild
+		&& range.endOffset == 2) {
+			// Just in case . . .
+			range.setStart(paras[0].firstChild, 1);
+		} else {
+			range.setStart(paras[0].firstChild, 0);
+			range.setEnd(paras[0].firstChild, 2);
+		}
+
+		var newRange = selection.getRangeAt(selection.rangeCount - 1);
+
+		assert_equals(newRange.startContainer, range.startContainer,
+			"After mutating the " + qualifier + " added Range, startContainer of the Selection's last Range must match the added Range");
+		assert_equals(newRange.startOffset, range.startOffset,
+			"After mutating the " + qualifier + " added Range, startOffset of the Selection's last Range must match the added Range");
+		assert_equals(newRange.endContainer, range.endContainer,
+			"After mutating the " + qualifier + " added Range, endContainer of the Selection's last Range must match the added Range");
+		assert_equals(newRange.endOffset, range.endOffset,
+			"After mutating the " + qualifier + " added Range, endOffset of the Selection's last Range must match the added Range");
+	}, testName + ": modifying the " + qualifier + " added range must modify the Selection's last Range");
+
+	// Now test the other way too.
+	test(function() {
+		assert_equals(exception, null, "Test setup must not throw exceptions");
+		assert_not_equals(selection.rangeCount, 0, "Cannot proceed with tests if rangeCount is 0");
+
+		var newRange = selection.getRangeAt(selection.rangeCount - 1);
+
+		if (newRange.startContainer == paras[0].firstChild
+		&& newRange.startOffset == 4
+		&& newRange.endContainer == paras[0].firstChild
+		&& newRange.endOffset == 6) {
+			newRange.setStart(paras[0].firstChild, 5);
+		} else {
+			newRange.setStart(paras[0].firstChild, 4);
+			newRange.setStart(paras[0].firstChild, 6);
+		}
+
+		assert_equals(newRange.startContainer, range.startContainer,
+			"After " + qualifier + " addRange(), after mutating the Selection's last Range, startContainer of the Selection's last Range must match the added Range");
+		assert_equals(newRange.startOffset, range.startOffset,
+			"After " + qualifier + " addRange(), after mutating the Selection's last Range, startOffset of the Selection's last Range must match the added Range");
+		assert_equals(newRange.endContainer, range.endContainer,
+			"After " + qualifier + " addRange(), after mutating the Selection's last Range, endContainer of the Selection's last Range must match the added Range");
+		assert_equals(newRange.endOffset, range.endOffset,
+			"After " + qualifier + " addRange(), after mutating the Selection's last Range, endOffset of the Selection's last Range must match the added Range");
+	}, testName + ": modifying the Selection's last Range must modify the " + qualifier + " added Range");
+}
+
+// Do only n evals, not n^2
+var testRangesEvaled = testRanges.map(eval);
+
+for (var i = 0; i < testRanges.length; i++) {
+	for (var j = 0; j < testRanges.length; j++) {
+		var testName = "Range " + i + " " + testRanges[i]
+			+ " followed by Range " + j + " " + testRanges[j];
+
+		var exception = null;
+		try {
+			selection.removeAllRanges();
+
+			var endpoints1 = testRangesEvaled[i];
+			var range1 = ownerDocument(endpoints1[0]).createRange();
+			range1.setStart(endpoints1[0], endpoints1[1]);
+			range1.setEnd(endpoints1[2], endpoints1[3]);
+
+			if (range1.startContainer !== endpoints1[0]) {
+				throw "Sanity check: the first Range we created must have the desired startContainer";
+			}
+			if (range1.startOffset !== endpoints1[1]) {
+				throw "Sanity check: the first Range we created must have the desired startOffset";
+			}
+			if (range1.endContainer !== endpoints1[2]) {
+				throw "Sanity check: the first Range we created must have the desired endContainer";
+			}
+			if (range1.endOffset !== endpoints1[3]) {
+				throw "Sanity check: the first Range we created must have the desired endOffset";
+			}
+
+			var endpoints2 = testRangesEvaled[j];
+			var range2 = ownerDocument(endpoints2[0]).createRange();
+			range2.setStart(endpoints2[0], endpoints2[1]);
+			range2.setEnd(endpoints2[2], endpoints2[3]);
+
+			if (range2.startContainer !== endpoints2[0]) {
+				throw "Sanity check: the second Range we created must have the desired startContainer";
+			}
+			if (range2.startOffset !== endpoints2[1]) {
+				throw "Sanity check: the second Range we created must have the desired startOffset";
+			}
+			if (range2.endContainer !== endpoints2[2]) {
+				throw "Sanity check: the second Range we created must have the desired endContainer";
+			}
+			if (range2.endOffset !== endpoints2[3]) {
+				throw "Sanity check: the second Range we created must have the desired endOffset";
+			}
+		} catch (e) {
+			exception = e;
+		}
+
+		testAddRange(exception, range1, endpoints1, "first", testName);
+		testAddRange(exception, range2, endpoints2, "second", testName);
+	}
+}
+
+testDiv.style.display = "none";
+</script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/collapse.html	Tue Oct 11 15:35:33 2011 -0600
@@ -0,0 +1,87 @@
+<!doctype html>
+<title>Selection.collapse() tests</title>
+<div id=log></div>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script src=common.js></script>
+<script>
+"use strict";
+
+function testCollapse(range, point) {
+	selection.removeAllRanges();
+	var addedRange;
+	if (range) {
+		addedRange = range.cloneRange();
+		selection.addRange(addedRange);
+	}
+
+	if (point[0].nodeType == Node.DOCUMENT_TYPE_NODE
+	|| point[0].nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
+		assert_throws("INVALID_NODE_TYPE_ERR", function() {
+			selection.collapse(point[0], point[1]);
+		}, "Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType or ProcessingInstruction");
+		return;
+	}
+
+	if (point[1] < 0 || point[1] > nodeLength(point[0])) {
+		assert_throws("INDEX_SIZE_ERR", function() {
+			selection.collapse(point[0], point[1]);
+		}, "Must throw INDEX_SIZE_ERR when collapse()ing if the offset is negative or greater than the node's length");
+		return;
+	}
+
+	selection.collapse(point[0], point[1]);
+
+	assert_equals(selection.rangeCount, 1,
+		"selection.rangeCount must equal 1 after collapse()");
+	assert_equals(selection.focusNode, point[0],
+		"focusNode must equal the node we collapse()d to");
+	assert_equals(selection.focusOffset, point[1],
+		"focusOffset must equal the offset we collapse()d to");
+	assert_equals(selection.focusNode, selection.anchorNode,
+		"focusNode and anchorNode must be equal after collapse()");
+	assert_equals(selection.focusOffset, selection.anchorOffset,
+		"focusOffset and anchorOffset must be equal after collapse()");
+	if (range) {
+		assert_equals(addedRange.startContainer, range.startContainer,
+			"collapse() must not change the startContainer of a preexisting Range");
+		assert_equals(addedRange.endContainer, range.endContainer,
+			"collapse() must not change the endContainer of a preexisting Range");
+		assert_equals(addedRange.startOffset, range.startOffset,
+			"collapse() must not change the startOffset of a preexisting Range");
+		assert_equals(addedRange.endOffset, range.endOffset,
+			"collapse() must not change the endOffset of a preexisting Range");
+	}
+}
+
+// Also test a selection with no ranges
+testRanges.unshift("[]");
+
+// Don't want to eval() each point a bazillion times
+var testPointsCached = [];
+for (var i = 0; i < testPoints.length; i++) {
+	testPointsCached.push(eval(testPoints[i]));
+}
+
+var tests = [];
+for (var i = 0; i < testRanges.length; i++) {
+	var endpoints = eval(testRanges[i]);
+	var range;
+	test(function() {
+		if (endpoints.length) {
+			range = ownerDocument(endpoints[0]).createRange();
+			range.setStart(endpoints[0], endpoints[1]);
+			range.setEnd(endpoints[2], endpoints[3]);
+		} else {
+			// Empty selection
+			range = null;
+		}
+	}, "Set up range " + i + " " + testRanges[i]);
+	for (var j = 0; j < testPoints.length; j++) {
+		tests.push(["Range " + i + " " + testRanges[i] + ", point " + j + " " + testPoints[j], range, testPointsCached[j]]);
+	}
+}
+
+generate_tests(testCollapse, tests);
+
+testDiv.style.display = "none";
+</script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/collapseToStartEnd.html	Tue Oct 11 15:35:33 2011 -0600
@@ -0,0 +1,123 @@
+<!doctype html>
+<title>Selection.collapseTo(Start|End)() tests</title>
+<div id=log></div>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script src=common.js></script>
+<script>
+"use strict";
+
+function testCollapseToStartEnd(range) {
+}
+
+// Also test a selection with no ranges
+testRanges.unshift("[]");
+
+for (var i = 0; i < testRanges.length; i++) {
+	test(function() {
+		selection.removeAllRanges();
+		var endpoints = eval(testRanges[i]);
+		if (!endpoints.length) {
+			assert_throws("INVALID_STATE_ERR", function() {
+				selection.collapseToStart();
+			}, "Must throw InvalidStateErr if the selection's range is null");
+			return;
+		}
+
+		var addedRange = ownerDocument(endpoints[0]).createRange();
+		addedRange.setStart(endpoints[0], endpoints[1]);
+		addedRange.setEnd(endpoints[2], endpoints[3]);
+		selection.addRange(addedRange);
+
+		// We don't penalize browsers here for mishandling addRange() and
+		// adding a different range than we specified.  They fail addRange()
+		// tests for that, and don't have to fail collapseToStart/End() tests
+		// too.  They do fail if they throw unexpectedly, though.  I also fail
+		// them if there's no range at all, because otherwise they could pass
+		// all tests if addRange() always does nothing and collapseToStart()
+		// always throws.
+		assert_equals(selection.rangeCount, 1,
+			"Sanity check: rangeCount must equal 1 after addRange()");
+
+		var expectedEndpoint = [
+			selection.getRangeAt(0).startContainer,
+			selection.getRangeAt(0).startOffset
+		];
+
+		selection.collapseToStart();
+
+		assert_equals(selection.rangeCount, 1,
+			"selection.rangeCount must equal 1");
+		assert_equals(selection.focusNode, expectedEndpoint[0],
+			"focusNode must equal the original start node");
+		assert_equals(selection.focusOffset, expectedEndpoint[1],
+			"focusOffset must equal the original start offset");
+		assert_equals(selection.anchorNode, expectedEndpoint[0],
+			"anchorNode must equal the original start node");
+		assert_equals(selection.anchorOffset, expectedEndpoint[1],
+			"anchorOffset must equal the original start offset");
+		assert_equals(addedRange.startContainer, endpoints[0],
+			"collapseToStart() must not change the startContainer of the selection's original range");
+		assert_equals(addedRange.startOffset, endpoints[1],
+			"collapseToStart() must not change the startOffset of the selection's original range");
+		assert_equals(addedRange.endContainer, endpoints[2],
+			"collapseToStart() must not change the endContainer of the selection's original range");
+		assert_equals(addedRange.endOffset, endpoints[3],
+			"collapseToStart() must not change the endOffset of the selection's original range");
+	}, "Range " + i + " " + testRanges[i] + " collapseToStart()");
+
+	// Copy-paste of above
+	test(function() {
+		selection.removeAllRanges();
+		var endpoints = eval(testRanges[i]);
+		if (!endpoints.length) {
+			assert_throws("INVALID_STATE_ERR", function() {
+				selection.collapseToEnd();
+			}, "Must throw InvalidStateErr if the selection's range is null");
+			return;
+		}
+
+		var addedRange = ownerDocument(endpoints[0]).createRange();
+		addedRange.setStart(endpoints[0], endpoints[1]);
+		addedRange.setEnd(endpoints[2], endpoints[3]);
+		selection.addRange(addedRange);
+
+		// We don't penalize browsers here for mishandling addRange() and
+		// adding a different range than we specified.  They fail addRange()
+		// tests for that, and don't have to fail collapseToStart/End() tests
+		// too.  They do fail if they throw unexpectedly, though.  I also fail
+		// them if there's no range at all, because otherwise they could pass
+		// all tests if addRange() always does nothing and collapseToStart()
+		// always throws.
+		assert_equals(selection.rangeCount, 1,
+			"Sanity check: rangeCount must equal 1 after addRange()");
+
+		var expectedEndpoint = [
+			selection.getRangeAt(0).endContainer,
+			selection.getRangeAt(0).endOffset
+		];
+
+		selection.collapseToEnd();
+
+		assert_equals(selection.rangeCount, 1,
+			"selection.rangeCount must equal 1");
+		assert_equals(selection.focusNode, expectedEndpoint[0],
+			"focusNode must equal the original end node");
+		assert_equals(selection.focusOffset, expectedEndpoint[1],
+			"focusOffset must equal the original end offset");
+		assert_equals(selection.anchorNode, expectedEndpoint[0],
+			"anchorNode must equal the original end node");
+		assert_equals(selection.anchorOffset, expectedEndpoint[1],
+			"anchorOffset must equal the original end offset");
+		assert_equals(addedRange.startContainer, endpoints[0],
+			"collapseToEnd() must not change the startContainer of the selection's original range");
+		assert_equals(addedRange.startOffset, endpoints[1],
+			"collapseToEnd() must not change the startOffset of the selection's original range");
+		assert_equals(addedRange.endContainer, endpoints[2],
+			"collapseToEnd() must not change the endContainer of the selection's original range");
+		assert_equals(addedRange.endOffset, endpoints[3],
+			"collapseToEnd() must not change the endOffset of the selection's original range");
+	}, "Range " + i + " " + testRanges[i] + " collapseToEnd()");
+}
+
+testDiv.style.display = "none";
+</script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/dir.html	Tue Oct 11 15:35:33 2011 -0600
@@ -0,0 +1,105 @@
+<!doctype html>
+<title>Selection direction tests</title>
+<meta charset=utf-8>
+<div id=test>
+	<p>This is a manual test, since there's no way to synthesize keyboard or
+	mouse input.  Click after the letter "c" in the following paragraph and
+	drag backwards so that both the "b" and the "c" are highlighted, then click
+	the "Test" button:
+
+	<p>abcd <button onclick=testDirection()>Test</button>
+
+	<p>efghi
+</div>
+<div id=log></div>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script>
+setup({explicit_done: true});
+
+function testDirection() {
+	var testDiv = document.getElementById("test");
+	var p = testDiv.getElementsByTagName("p")[1].firstChild;
+	var selection = getSelection();
+	var range = selection.getRangeAt(0);
+	test(function() {
+		assert_equals(range.toString(), "bc");
+	}, "The expected range is selected");
+	test(function() {
+		assert_equals(selection.anchorNode, p);
+		assert_equals(selection.focusNode, p);
+	}, "Expected node is initially selected");
+	test(function() {
+		assert_array_equals([selection.anchorOffset, selection.focusOffset].sort(), [1, 3]);
+	}, "Expected offsets are initially selected (maybe not in order)");
+	test(function() {
+		assert_equals(selection.anchorOffset, 3);
+		assert_equals(selection.focusOffset, 1);
+	}, "Offsets are backwards for initial selection"),
+	test(function() {
+		assert_equals(selection.anchorNode, range.endContainer);
+		assert_equals(selection.anchorOffset, range.endOffset);
+		assert_equals(selection.focusNode, range.startContainer);
+		assert_equals(selection.focusOffset, range.startOffset);
+	}, "Offsets match the range for initial selection");
+
+	// Per spec, the direction of the selection remains even if you zap a range
+	// and add a new one.
+	test(function() {
+		selection.removeRange(range);
+		range = document.createRange();
+		p = testDiv.getElementsByTagName("p")[0].firstChild;
+		range.setStart(p, 0);
+		range.setEnd(p, 4);
+		assert_equals(range.toString(), "This");
+		selection.addRange(range);
+	}, "removeRange()/addRange() successful");
+	test(function() {
+		assert_equals(selection.anchorNode, p);
+		assert_equals(selection.focusNode, p);
+	}, "Expected node is selected after remove/addRange()");
+	test(function() {
+		assert_array_equals([selection.anchorOffset, selection.focusOffset].sort(), [0, 4]);
+	}, "Expected offsets are selected after remove/addRange() (maybe not in order)");
+	test(function() {
+		assert_equals(selection.anchorOffset, 4);
+		assert_equals(selection.focusOffset, 0);
+	}, "Offsets are backwards after remove/addRange()"),
+	test(function() {
+		assert_equals(selection.anchorNode, range.endContainer);
+		assert_equals(selection.anchorOffset, range.endOffset);
+		assert_equals(selection.focusNode, range.startContainer);
+		assert_equals(selection.focusOffset, range.startOffset);
+	}, "Offsets match the range after remove/addRange()");
+
+	// But if you call removeAllRanges(), the direction should reset to
+	// forwards.
+	test(function() {
+		selection.removeAllRanges();
+		range = document.createRange();
+		p = testDiv.getElementsByTagName("p")[2].firstChild;
+		range.setStart(p, 2);
+		range.setEnd(p, 5);
+		assert_equals(range.toString(), "ghi");
+		selection.addRange(range);
+	}, "removeAllRanges() successful");
+	test(function() {
+		assert_equals(selection.anchorNode, p);
+		assert_equals(selection.focusNode, p);
+	}, "Expected node is selected after removeAllRanges()");
+	test(function() {
+		assert_array_equals([selection.anchorOffset, selection.focusOffset].sort(), [2, 5]);
+	}, "Expected offsets are selected after removeAllRanges() (maybe not in order)");
+	test(function() {
+		assert_equals(selection.anchorOffset, 2);
+		assert_equals(selection.focusOffset, 5);
+	}, "Offsets are forwards after removeAllRanges()");
+	test(function() {
+		assert_equals(selection.anchorNode, range.startContainer);
+		assert_equals(selection.anchorOffset, range.startOffset);
+		assert_equals(selection.focusNode, range.endContainer);
+		assert_equals(selection.focusOffset, range.endOffset);
+	}, "Offsets match the range after removeAllRanges()");
+
+	done();
+}
+</script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/extend.html	Tue Oct 11 15:35:33 2011 -0600
@@ -0,0 +1,245 @@
+<!doctype html>
+<title>Selection extend() tests</title>
+<meta charset=utf-8>
+<body>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script src=common.js></script>
+<div id=log></div>
+<script>
+/**
+ * Returns "forwards" if the selection direction is forwards, "backwards" if
+ * it's backwards.  This appears not to work in WebKit at all, because there
+ * seems to be no way of adding a range or replacing the current range without
+ * calling removeAllRanges(), which resets the direction.  So we're nice and
+ * look at the current range if possible; otherwise we do some stuff that
+ * involves calling removeRange(), which doesn't exist in WebKit, so it will
+ * fail the test.
+ */
+function getSelectionDirection() {
+	if (selection.anchorNode != selection.focusNode
+	|| selection.anchorOffset != selection.focusOffset) {
+		var range = selection.getRangeAt(selection.rangeCount - 1);
+		// We can determine the direction without mangling anything.
+		if (selection.anchorNode == range.startContainer
+		&& selection.anchorOffset == range.startOffset) {
+			return "forwards";
+		}
+		if (selection.anchorNode == range.endContainer
+		&& selection.anchorOffset == range.endOffset) {
+			return "backwards";
+		}
+		throw "Something buggy with directions";
+	}
+
+	var range = document.createRange();
+	range.setStart(paras[0].firstChild, 0);
+	range.setEnd(paras[0].firstChild, 1);
+	selection.addRange(range);
+	if (selection.anchorOffset == range.startOffset) {
+		selection.removeRange(range);
+		return "forwards";
+	}
+	if (selection.anchorOffset == range.endOffset) {
+		selection.removeRange(range);
+		return "backwards";
+	}
+}
+
+/**
+ * We test Selections that go both forwards and backwards here.  In the latter
+ * case we need to use extend() to force it to go backwards, which is fair
+ * enough, since that's what we're testing.
+ */
+
+var originalSelectionDirection;
+
+function testExtendForwards(initialRanges, extendTarget) {
+	originalSelectionDirection = "forwards";
+	selection.removeAllRanges();
+
+	for (var i = 0; i < initialRanges.length; i += 4) {
+		var range = ownerDocument(initialRanges[i]).createRange();
+		range.setStart(initialRanges[i], initialRanges[i + 1]);
+		range.setEnd(initialRanges[i + 2], initialRanges[i + 3]);
+		selection.addRange(range);
+	}
+
+	testExtend(extendTarget, initialRanges.length/4);
+}
+
+function testExtendBackwards(initialRanges, extendTarget) {
+	originalSelectionDirection = "backwards";
+	selection.removeAllRanges();
+
+	for (var i = 0; i < initialRanges.length; i += 4) {
+		// To get a backwards selection, we add ranges by appending a
+		// zero-length range at the end, then extend()ing backwards to the
+		// start.  This fails in Opera, since Opera ignores addRange() on a
+		// collapsed range.  FIXME: This doesn't actually make the initial
+		// selection backwards, if the range we're given is collapsed.
+		var range = ownerDocument(initialRanges[i]).createRange();
+		range.setStart(initialRanges[i + 2], initialRanges[i + 3]);
+		range.setEnd(initialRanges[i + 2], initialRanges[i + 3]);
+		selection.addRange(range);
+		selection.extend(initialRanges[i], initialRanges[i + 1]);
+	}
+
+	testExtend(extendTarget, initialRanges.length/4);
+}
+
+function testExtend(extendTarget, numRanges) {
+	assert_equals(selection.rangeCount, numRanges,
+		"Failed sanity check: selection.rangeCount is wrong.  Perhaps addRange() failed.");
+
+	var node = extendTarget[0];
+	var offset = extendTarget[1];
+
+	if (node === null) {
+		assert_throws("TYPE_MISMATCH_ERR", function() {
+			selection.extend(node, offset);
+		}, "extend(null, foo) must throw TYPE_MISMATCH_ERR");
+		return;
+	}
+
+	if (selection.rangeCount == 0) {
+		assert_throws("INVALID_STATE_ERR", function() {
+			selection.extend(node, offset);
+		}, "extend() when rangeCount is 0 must throw INVALID_STATE_ERR");
+		return;
+	}
+
+	if (node.nodeType == Node.DOCUMENT_TYPE_NODE
+	|| node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
+		assert_throws("INVALID_NODE_TYPE_ERR", function() {
+			selection.extend(node, offset);
+		}, "extend() to a doctype or PI must throw INVALID_NODE_TYPE_ERR");
+		return;
+	}
+
+	if (offset < 0 || offset > nodeLength(node)) {
+		assert_throws("INDEX_SIZE_ERR", function() {
+			selection.extend(node, offset);
+		}, "extend() to an offset that's negative or greater than node length (" + nodeLength(node) + ") must throw INDEX_SIZE_ERR");
+		return;
+	}
+
+	var range = selection.getRangeAt(selection.rangeCount - 1);
+	var rangeRoot = furthestAncestor(range.startContainer);
+	var nodeRoot = furthestAncestor(node);
+
+	assert_equals(rangeRoot, furthestAncestor(range.endContainer),
+		"The furthest ancestor of a Range's start and end must always be the same (I think)");
+
+	if (rangeRoot != nodeRoot) {
+		selection.extend(node, offset);
+		assert_equals(selection.anchorNode, node,
+			"If the furthest ancestors of the range and extend() target differ, anchorNode must be set to the target node");
+		assert_equals(selection.anchorOffset, offset,
+			"If the furthest ancestors of the range and extend() target differ, anchorOffset must be set to the target offset");
+		assert_equals(selection.focusNode, node,
+			"If the furthest ancestors of the range and extend() target differ, focusNode must be set to the target node");
+		assert_equals(selection.focusOffset, offset,
+			"If the furthest ancestors of the range and extend() target differ, focusOffset must be set to the target offset");
+		assert_equals(getSelectionDirection(), "backwards",
+			"If the furthest ancestors of the range and extent() target differ, the new selection must be backwards");
+		return;
+	}
+
+	if (selection.focusNode == node && selection.focusOffset == offset) {
+		// extend() must do nothing.
+		var oldFocusNode = selection.focusNode;
+		var oldFocusOffset = selection.focusOffset;
+		var oldAnchorNode = selection.anchorNode;
+		var oldAnchorOffset = selection.anchorOffset;
+		var oldRanges = [];
+		for (var i = 0; i < selection.rangeCount; i++) {
+			oldRanges.push(selection.getRangeAt(i));
+		}
+		selection.extend(node, offset);
+		assert_equals(selection.focusNode, oldFocusNode,
+			"extend() to the current focus must not change focusNode");
+		assert_equals(selection.focusOffset, oldFocusOffset,
+			"extend() to the current focus must not change focusOffset");
+		assert_equals(selection.anchorNode, oldAnchorNode,
+			"extend() to the current focus must not change anchorNode");
+		assert_equals(selection.anchorOffset, oldAnchorOffset,
+			"extend() to the current focus must not change anchorOffset");
+		assert_equals(selection.rangeCount, oldRanges.length,
+			"extend() to the current focus must not change rangeCount");
+		for (var i = 0; i < oldRanges.length; i++) {
+			assert_equals(selection.getRangeAt(i), oldRanges[i],
+				"extend() to the current focus must not change any Ranges");
+		}
+		assert_equals(getSelectionDirection(), originalSelectionDirection,
+			"extend() of a selection to the current focus must not change direction");
+		return;
+	}
+
+	var oldAnchorNode = selection.anchorNode;
+	var oldAnchorOffset = selection.anchorOffset;
+	var oldFocusNode = selection.focusNode;
+	var oldFocusOffset = selection.focusOffset;
+	var oldRanges = [];
+	for (var i = 0; i < selection.rangeCount; i++) {
+		oldRanges.push(selection.getRangeAt(i));
+	}
+	selection.extend(node, offset);
+	assert_equals(selection.anchorNode, oldAnchorNode,
+		"extend() must not change anchorNode in the usual case");
+	assert_equals(selection.anchorOffset, oldAnchorOffset,
+		"extend() must not change anchorOffset in the usual case");
+	assert_equals(selection.rangeCount, oldRanges.length,
+		"extend() must not change rangeCount in the usual case");
+	for (var i = 0; i < oldRanges.length - 1; i++) {
+		assert_equals(selection.getRangeAt(i), oldRanges[i],
+			"extend() must not change any Range but the last in the usual case");
+	}
+	assert_equals(selection.focusNode, node,
+		"extend() must update focusNode to the target node in the usual case");
+	assert_equals(selection.focusOffset, offset,
+		"extend() must update focusOffset to the target offset in the usual case");
+
+	var expectedDirection;
+	var range = document.createRange();
+	range.setStart(oldAnchorNode, oldAnchorOffset);
+	range.setEnd(oldAnchorNode, oldAnchorOffset);
+	if (range.comparePoint(node, offset) >= 0) {
+		expectedDirection = "forwards";
+	} else {
+		expectedDirection = "backwards";
+	}
+	assert_equals(getSelectionDirection(), expectedDirection,
+		"extend() must set direction appropriately in the usual case");
+}
+
+// Also test a selection with no ranges
+testRanges.unshift("[]");
+
+var tests = [];
+for (var i = 0; i < testRanges.length; i++) {
+	for (var j = 0; j < testPoints.length; j++) {
+		tests.push([
+			"extend() forwards with range " + i + " " + testRanges[i] + " and point " + j + " " + testPoints[j],
+			eval(testRanges[i]),
+			eval(testPoints[j])
+		]);
+	}
+}
+generate_tests(testExtendForwards, tests);
+
+// Copy-pasted with "forwards" changed to "backwards" :/
+var tests = [];
+for (var i = 0; i < testRanges.length; i++) {
+	for (var j = 0; j < testPoints.length; j++) {
+		tests.push([
+			"extend() backwards with range " + i + " " + testRanges[i] + " and point " + j + " " + testPoints[j],
+			eval(testRanges[i]),
+			eval(testPoints[j])
+		]);
+	}
+}
+generate_tests(testExtendBackwards, tests);
+
+// Let's be tidy.
+testDiv.style.display = "none";
+</script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/selecttest/getRangeAt.html	Tue Oct 11 15:35:33 2011 -0600
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>The getRangeAt method</title>
+<div id=log></div>
+<script src=http://w3c-test.org/resources/testharness.js></script>
+<script>
+test(function() {
+  var sel = getSelection();
+  var range = document.createRange();
+  sel.addRange(range);
+  assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(-1); })
+  assert_throws("INDEX_SIZE_ERR", function() { sel.getRangeAt(1); })
+});
+</script>