<html>
<head>
<title>Pseudo Element Matching in Shadow DOM</title>
<style>
    input[type=range] {
        -webkit-appearance: none;
    }
</style>
<script>

if (window.testRunner)
    testRunner.dumpAsText();

var head;
var input;
var logDiv;
var NAMESPACE_DECLARATION = '@namespace "http://example.com/foo/namespace";\n@namespace html "http://www.w3.org/1999/xhtml";\n';
var SELECTOR_TEST_PROPERTIES = ' { height: 1px; -webkit-appearance: none; border: none; }';
var SELECTORS = [
'::-webkit-slider-thumb',
'*::-webkit-slider-thumb',
'input::-webkit-slider-thumb',
'#foo::-webkit-slider-thumb',
'input#foo::-webkit-slider-thumb',
'input.bar::-webkit-slider-thumb',
'input[type=range]::-webkit-slider-thumb'
];
var DISABLED_SELECTORS = SELECTORS.map(function(selector) { return selector + ':disabled'; });
var HOVER_SELECTORS = SELECTORS.map(function(selector) { return selector + ':hover'; });
var DESCENDANT_ID_SELECTORS = SELECTORS.map(function(selector) { return '#baz ' + selector; });
var DESCENDANT_CLASS_SELECTORS = SELECTORS.map(function(selector) { return '.qux ' + selector; });
var DIRECT_SIBLING_ID_SELECTORS = SELECTORS.map(function(selector) { return '#sib + ' + selector; });
var INDIRECT_SIBLING_ID_SELECTORS = SELECTORS.map(function(selector) { return '#sib ~ ' + selector; });
var DIRECT_SIBLING_CLASS_SELECTORS = SELECTORS.map(function(selector) { return '.ling + ' + selector; });
var INDIRECT_SIBLING_CLASS_SELECTORS = SELECTORS.map(function(selector) { return '.ling ~ ' + selector; });

// convenience constants
var MATCH = true;
var NO_MATCH = false;
var WITH_NAMESPACES = true;

function log(msg, success)
{
    logDiv.appendChild(document.createElement('div')).innerHTML = msg + (arguments.length == 1 ? '' : (': ' + (success ? 'PASS' : 'FAIL')));
}

function hoverOverSliderThumb()
{
    if (!window.eventSender)
        return false;

    var x = input.offsetLeft + input.offsetWidth / 2;
    var y = input.offsetTop + input.offsetHeight / 2;
    eventSender.mouseMoveTo(x, y);
    return true;
}

function runSelectorTest(matchExpected, selector, useNamespaces)
{
    var style = document.createElement('style');
    style.textContent = (useNamespaces ? NAMESPACE_DECLARATION : '') + selector + SELECTOR_TEST_PROPERTIES;
    head.appendChild(style);
    var matched = input.offsetHeight == 1;
    log('<code>' + selector + '</code>' + (useNamespaces ? ', where  HTML is not default namespace' : '') + ' <strong>should' + (matchExpected ? '' : ' not') + '</strong> match', matchExpected ? matched : !matched);
    head.removeChild(style);
}

function runTest()
{
    head = document.getElementsByTagName('head')[0];
    input = document.getElementsByTagName('input')[0];
    testContainer = document.getElementById('baz');
    logDiv = document.getElementById('log');
    log('Basic selector tests:');
    runSelectorTest(MATCH, '::-webkit-slider-thumb');
    runSelectorTest(MATCH, '*::-webkit-slider-thumb');
    runSelectorTest(NO_MATCH, '::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, '*|*::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, 'html|*::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, '#foo::-webkit-slider-thumb');
    runSelectorTest(MATCH, '.bar::-webkit-slider-thumb');
    runSelectorTest(NO_MATCH, '#foo::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(NO_MATCH, '.bar::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, 'input::-webkit-slider-thumb');
    runSelectorTest(MATCH, 'input#foo::-webkit-slider-thumb');
    runSelectorTest(MATCH, 'input.bar::-webkit-slider-thumb');
    runSelectorTest(NO_MATCH, 'input::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(NO_MATCH, 'input#foo::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(NO_MATCH, 'input.bar::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, 'html|input::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, 'html|input#foo::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, 'html|input.bar::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, '*|input#foo::-webkit-slider-thumb', WITH_NAMESPACES);
    runSelectorTest(MATCH, 'input[type=range]::-webkit-slider-thumb');
    runSelectorTest(MATCH, 'input#foo[type=range]::-webkit-slider-thumb');
    runSelectorTest(MATCH, 'input.bar[type=range]::-webkit-slider-thumb');
    log('<br>Shouldn\'t ignore selector after the unknown pseudo element:');
    DISABLED_SELECTORS.forEach(expectNoMatch);
    input.disabled = true;
    log('<br>Should not match disabled input, because the disabled state is on the input, not the thumb:');
    DISABLED_SELECTORS.forEach(expectNoMatch);
    input.disabled = false;
    if (!hoverOverSliderThumb()) {
        log(':hover tests require DRT');
        return;
    }
    log('<br>Should match :hover when the mouse is over the slider thumb:');
    HOVER_SELECTORS.forEach(expectMatch);
    log('<br>Should match when combined with descendant selectors:');
    DESCENDANT_ID_SELECTORS.forEach(expectMatch);
    DESCENDANT_CLASS_SELECTORS.forEach(expectMatch);
    log('<br>Should match when combined with sibling selectors:');
    DIRECT_SIBLING_ID_SELECTORS.forEach(expectMatch);
    INDIRECT_SIBLING_ID_SELECTORS.forEach(expectMatch);
    DIRECT_SIBLING_CLASS_SELECTORS.forEach(expectMatch);
    INDIRECT_SIBLING_CLASS_SELECTORS.forEach(expectMatch);

    testContainer.parentNode.removeChild(testContainer);
}

function expectNoMatch(selector) {
    runSelectorTest(NO_MATCH, selector);
}

function expectMatch(selector) {
    runSelectorTest(MATCH, selector);
}

</script>
</head>
<body onload="runTest()">
    <p>Tests various selector combinations, containing unknown pseudo element selectors.</p>
    <div id="baz" class="qux">
        <span id="sib" class="ling">Sibling</span>
        <input id="foo" class="bar" type="range">
    </div>
    <div id="log"></div>
</body>
</html>
