function testOption(Constructor, property, type, values, fallback, testOptions) {
    var isOptional = testOptions !== undefined && testOptions.isOptional === true;
    var noReturn = testOptions !== undefined && testOptions.noReturn === true;
    var isILD = testOptions !== undefined && testOptions.isILD === true;
    
    function addExtraOptions(options, value, testOptions) {
        if (testOptions !== undefined && testOptions.extra !== undefined) {
            var extra;
            if (value !== undefined && testOptions.extra[value] !== undefined) {
                extra = testOptions.extra[value];
            } else if (testOptions.extra.any !== undefined) {
                extra = testOptions.extra.any;
            }
            if (extra !== undefined) {
                Object.getOwnPropertyNames(extra).forEach(function (prop) {
                    options[prop] = extra[prop];
                });
            }
        }
    }

    var testValues, options, obj, expected, actual, error;

    // test that the specified values are accepted. Also add values that convert to specified values.
    if (type === "boolean") {
        if (values === undefined) {
            values = [true, false];
        }
        testValues = values.slice(0);
        testValues.push(888);
        testValues.push(0);
    } else if (type === "string") {
        testValues = values.slice(0);
        testValues.push({toString: function () { return values[0]; }});
    }
    testValues.forEach(function (value) {
        options = {};
        options[property] = value;
        addExtraOptions(options, value, testOptions);
        obj = new Constructor(undefined, options);
        if (noReturn) {
            if (obj.resolvedOptions().hasOwnProperty(property)) {
                $ERROR("Option property " + property + " is returned, but shouldn't be.");
            }
        } else {
            actual = obj.resolvedOptions()[property];
            if (isILD) {
                if (actual !== undefined && values.indexOf(actual) === -1) {
                    $ERROR("Invalid value " + actual + " returned for property " + property + ".");
                }
            } else {
                if (type === "boolean") {
                    expected = Boolean(value);
                } else if (type === "string") {
                    expected = String(value);
                }
                if (actual !== expected && !(isOptional && actual === undefined)) {
                    $ERROR("Option value " + value + " for property " + property +
                        " was not accepted; got " + actual + " instead.");
                }
            }
        }
    });

    // test that invalid values are rejected
    if (type === "string") {
        var invalidValues = ["invalidValue", -1, null];
        // assume that we won't have values in caseless scripts
        if (values[0].toUpperCase() !== values[0]) {
            invalidValues.push(values[0].toUpperCase());
        } else {
            invalidValues.push(values[0].toLowerCase());
        }
        invalidValues.forEach(function (value) {
            options = {};
            options[property] = value;
            addExtraOptions(options, value, testOptions);
            error = undefined;
            try {
                obj = new Constructor(undefined, options);
            } catch (e) {
                error = e;
            }
            if (error === undefined) {
                $ERROR("Invalid option value " + value + " for property " + property + " was not rejected.");
            } else if (error.name !== "RangeError") {
                $ERROR("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + ".");
            }
        });
    }

    // test that fallback value or another valid value is used if no options value is provided
    if (!noReturn) {
        options = {};
        addExtraOptions(options, undefined, testOptions);
        obj = new Constructor(undefined, options);
        actual = obj.resolvedOptions()[property];
        if (!(isOptional && actual === undefined)) {
            if (fallback !== undefined) {
                if (actual !== fallback) {
                    $ERROR("Option fallback value " + fallback + " for property " + property +
                        " was not used; got " + actual + " instead.");
                }
            } else {
                if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) {
                    $ERROR("Invalid value " + actual + " returned for property " + property + ".");
                }
            }
        }
    }

    return true;
}
Tests whether the named options property is correctly handled by the given constructor.
@param {object} Constructor the constructor to test.
@param {string} property the name of the options property to test.
@param {string} type the type that values of the property are expected to have
@param {Array} [values] an array of allowed values for the property. Not needed for boolean.
@param {any} fallback the fallback value that the property assumes if not provided.
@param {object} testOptions additional options:
    @param {boolean} isOptional whether support for this property is optional for implementations.
    @param {boolean} noReturn whether the resulting value of the property is not returned.
    @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent.
    @param {object} extra additional option to pass along, properties are value -> {option: value}.
@return {boolean} whether the test succeeded.