<!DOCTYPE html>
<html>
<body>
<p>This test ensures WebKit adjusts or clears the selection when either the start or the end container was modified.</p>
<div id="test" contenteditable></div>
<pre>
<script>

var test = document.getElementById('test');
test.focus();

if (window.testRunner)
    testRunner.dumpAsText();

var baseIsFirst = true;

function runSingleTest(actor, isStart, expectedOffset) {
    test.innerHTML = '<span>hello</span> world';

    // Select "llo wo"
    var selection = window.getSelection();
    if (baseIsFirst)
        selection.setBaseAndExtent(test.firstChild.firstChild, 2, test.lastChild, 3);
    else
        selection.setBaseAndExtent(test.lastChild, 3, test.firstChild.firstChild, 2);
    var originalOffset = isStart ? selection.getRangeAt(0).startOffset : selection.getRangeAt(0).endOffset;
    var action = isStart ? actor(test.firstChild.firstChild, 'startContainer') : actor(test.lastChild, 'endContainer');
    var message = null;
    var passed = false;
    if (typeof(expectedOffset) == 'undefined') {
        if (selection.rangeCount)
            message = 'did not clear selection';
        else {
            message = 'cleared selection';
            passed = true;
        }
    } else if (!selection.rangeCount)
        message = 'cleared selection unexpectedly';
    else if ((selection.getRangeAt(0).startContainer == selection.baseNode
        && selection.getRangeAt(0).startOffset == selection.baseOffset) ^ baseIsFirst)
        message = 'exchanged base and extent';
    else {
        var actualOffset = isStart ? selection.getRangeAt(0).startOffset : selection.getRangeAt(0).endOffset;
        message = actualOffset == originalOffset ? 'did not move selection' : 'moved the offset from ' +
            originalOffset + ' to ' + actualOffset;

        if (actualOffset != expectedOffset)
            message += ' but expected ' + expectedOffset;
        else
            passed = true;
    }

    document.write((passed ? 'PASS: ' : 'FAIL: ') + action + ' ' + message + '\n');
}

function runTestPairs(actor, expectedStartOffset, expectedEndOffset, skipEnd) {
    runSingleTest(actor, true, expectedStartOffset);
    if (!skipEnd)
        runSingleTest(actor, false, expectedEndOffset);
}

function runTests() {
    runTestPairs(function() { test.removeChild(test.firstChild); return 'Removing the parent of startContainer'; }, 0, undefined, true);
    runTestPairs(function(node, nodeName) { node.nodeValue = 'a'; return 'Replacing nodeValue of ' + nodeName; }, 0, 0);
    runTestPairs(function(node, nodeName) { node.appendData(' WebKit'); return 'Appending " WebKit" to ' + nodeName; }, 2, 3);

    runTestPairs(function(node, nodeName) { node.insertData(2, 'WebKit ');
        return 'Inserting " WebKit" to ' + nodeName + ' before the end point'; }, 2, 10);
    runTestPairs(function(node, nodeName) { node.insertData(3, 'WebKit ');
        return 'Inserting " WebKit" to ' + nodeName + ' after the end point'; }, 2, 3);

    runTestPairs(function(node, nodeName) { node.deleteData(1, 4);
        return 'Removing text in ' + nodeName + ' containing the end point'; }, 1, 1);
    runTestPairs(function(node, nodeName) { node.deleteData(0, 3);
        return 'Removing text in ' + nodeName + ' containing the start point'; }, 0, 0);
    runTestPairs(function(node, nodeName) { node.deleteData(0, 2);
        return 'Removing 2 characters in ' + nodeName + ' before the end point'; }, 0, 1);
    runTestPairs(function(node, nodeName) { node.deleteData(0, 3);
        return 'Removing 3 characters at the beginning of ' + nodeName; }, 0, 0);
    runTestPairs(function(node, nodeName) { node.deleteData(3, 2);
        return 'Removing text in ' + nodeName + ' after the end point'; }, 2, 3);

    runTestPairs(function(node, nodeName) { node.replaceData(1, 4, '1234');
        return 'Replacing text in ' + nodeName + ' containing the end point'; }, 1, 1);
    runTestPairs(function(node, nodeName) { node.replaceData(0, 2, '12');
        return 'Replacing 2 characters in ' + nodeName + ' by 2 characters before the end point'; }, 0, 3);
    runTestPairs(function(node, nodeName) { node.replaceData(0, 2, '1');
        return 'Replacing 2 characters in ' + nodeName + ' by 1 characters before the end point'; }, 0, 2);
    runTestPairs(function(node, nodeName) { node.replaceData(3, 2, '12');
        return 'Replacing 2 characters in ' + nodeName + ' by 2 characters after the end point'; }, 2, 3);
}

document.write('Base is first:\n');
runTests();

baseIsFirst = false;

document.write('\nExtent is first:\n');
runTests();

test.style.display = 'none';

document.write('\nDONE');
</script>
</pre>
</body>
</html>
