<!DocType HTML>
<script>
if (window.testRunner)
    testRunner.dumpAsText();

var iframe, iframeDoc;

function log(msg)
{
    document.getElementById('logger').innerHTML += msg + '\n';
}

var i = 0;

function runTest(test, opt_expectedErrorName)
{
    var errorName;
    try {
        test();
    } catch(error) {
        errorName = error.name;
    } finally {
        i++;
        var hasExpectedErrorName = opt_expectedErrorName;
        if (hasExpectedErrorName && navigator.userAgent.indexOf('Firefox') != -1)
            opt_expectedErrorName = 'NS_ERROR_DOM_' + opt_expectedErrorName;

        if (!errorName && !opt_expectedErrorName || opt_expectedErrorName == errorName)
            log(i + '. PASS');
        else
            log(i + '. FAIL: expected ' + opt_expectedErrorName + ' got ' + (errorName || 'no error'));
    }
}

function elementInCurrentDocument(html)
{
    var node = document.createElement('div');
    node.innerHTML = html || 'lorem ipsum';
    document.body.appendChild(node);
    return node;
}

function rangeInIframe()
{
    var range = iframeDoc.createRange();
    range.setStart(iframeDoc.body, 0);
    range.setEnd(iframeDoc.body, 1);
    return range;
}

function rangeInCurrentDocument()
{
    var range = document.createRange();
    range.setStart(document.body, 0);
    range.setEnd(document.body, 1);
    return range;
}

function run()
{
    iframe = document.querySelector('iframe');
    iframeDoc = iframe.contentDocument;

    runTest(function() {
        iframeDoc.body.appendChild(document.createElement('div'));
        iframeDoc.body.appendChild(elementInCurrentDocument('appendChild'));
    });

    runTest(function() {
        var dummy = document.createElement('span');
        iframeDoc.body.appendChild(dummy);
        iframeDoc.body.replaceChild(document.createElement('div'), dummy);

        var dummy = document.createElement('span');
        iframeDoc.body.appendChild(dummy);
        iframeDoc.body.replaceChild(elementInCurrentDocument('replaceChild'), dummy);
    });
    runTest(function() {
        iframeDoc.body.insertBefore(document.createElement('div'), iframeDoc.body.firstChild);
        iframeDoc.body.insertBefore(elementInCurrentDocument('insertBefore'), iframeDoc.body.firstChild);
    });
    runTest(function() {
        rangeInIframe().insertNode(document.createElement('div'));
        rangeInIframe().insertNode(elementInCurrentDocument('insertNode'));
    });
    runTest(function() {
        rangeInIframe().surroundContents(document.createElement('div'));
        rangeInIframe().surroundContents(elementInCurrentDocument('surroundContents'));
    });

    runTest(function() {
        iframeDoc.body.appendChild(document.createElement('div'));
        var element = elementInCurrentDocument('insertBefore');
        // Make sure we don't crash if the element is moved back to the original document during the insertBefore call.
        var mutationHandler = function() {
            document.body.removeEventListener('DOMSubtreeModified', mutationHandler, true);
            document.body.appendChild(element);
            // Access something on the element to see if it's in a valid state.
            element.offsetLeft;
        };
        document.body.addEventListener('DOMSubtreeModified', mutationHandler, true);
        try {
            iframeDoc.body.insertBefore(element, null);
        } catch (e) {
          throw e;
        } finally {
          // Clear the event handler to avoid affecting the following tests.
        }
    });
    
    runTest(function() {
        iframeDoc.body.appendChild(document.createElement('div'));
        var element = elementInCurrentDocument('appendChild');
        // Make sure we don't crash if the element is moved back to the original document during the insertBefore call.
        var mutationHandler = function() {
            document.body.removeEventListener('DOMSubtreeModified', mutationHandler, true);
            document.body.appendChild(element);
            // Access something on the element to see if it's in a valid state.
            element.offsetLeft;
        };
        document.body.addEventListener('DOMSubtreeModified', mutationHandler, true);
        try {
            iframeDoc.body.appendChild(element);
        } catch (e) {
          throw e;
        } finally {
          // Clear the event handler to avoid affecting the following tests.
        }
    });

    runTest(function() {
        iframeDoc.body.appendChild(document.createElement('div'));
        var element = elementInCurrentDocument('replaceChild');
        // Make sure we don't crash if the element is moved back to the original document during the insertBefore call.
        var mutationHandler = function() {
            document.body.removeEventListener('DOMSubtreeModified', mutationHandler, true);
            document.body.appendChild(element);
            // Access something on the element to see if it's in a valid state.
            element.offsetLeft;
        };
        document.body.addEventListener('DOMSubtreeModified', mutationHandler, true);
        try {
            iframeDoc.body.replaceChild(element, iframeDoc.body.firstChild);
        } catch (e) {
          throw e;
        } finally {
          // Clear the event handler to avoid affecting the following tests.
        }
    });

    runTest(function() {
        var attribute = document.createAttribute('asdf');
        iframeDoc.body.attributes.setNamedItem(attribute);
    });
    runTest(function() {
        var attribute = document.createAttribute('asdf');
        document.body.attributes.setNamedItem(attribute);
        iframeDoc.body.attributes.setNamedItem(attribute);
    }, 'InUseAttributeError');

    runTest(function() {
        var doctype = document.implementation.createDocumentType(
            'html',
            '-//W3C//DTD XHTML 1.0 Strict//EN',
            'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
        );
        iframeDoc.implementation.createDocument('', 'html', doctype); 
    });
    runTest(function() {
        iframeDoc.implementation.createDocument('', 'html', document.doctype); 
    });
    runTest(function() {
        rangeInIframe().compareBoundaryPoints(Range.END_TO_END, rangeInCurrentDocument());
    }, 'WrongDocumentError');
    runTest(function() {
        rangeInIframe().comparePoint(elementInCurrentDocument('comparePoint'), 0);
    }, 'WrongDocumentError');

    runTest(function() {
        iframeDoc.appendChild(document.doctype);
        console.log(document.doctype);
    }, 'TypeError');

    // When setting a boundary of the range in a different
    // document, the call should succeed and the range should be collapsed.
    runTest(function() {
        rangeInIframe().setStart(elementInCurrentDocument('setStart'), 0);
    });
    runTest(function() {
        rangeInIframe().setEnd(elementInCurrentDocument('setEnd'), 0);
    });
    runTest(function() {
        rangeInIframe().setStartBefore(elementInCurrentDocument('setStartBefore'), 0);
    });
    runTest(function() {
        rangeInIframe().setStartAfter(elementInCurrentDocument('setStartAfter'), 0);
    });
    runTest(function() {
        rangeInIframe().setEndBefore(elementInCurrentDocument('setEndBefore'), 0);
    });
    runTest(function() {
        rangeInIframe().setEndAfter(elementInCurrentDocument('setEndAfter'), 0);
    });
    runTest(function() {
        rangeInIframe().isPointInRange(elementInCurrentDocument('isPointInRange'), 0);
    });

}
</script> 
<pre id='logger'></pre>
<iframe onload='run()'></iframe>
