<html>
<head>
<script src="../../../resources/js-test.js"></script>
<script src="resources/webgl-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>

<script>

description("Verifies that out-of-range parameters for creation, slicing and setting of WebGL arrays are caught");

function testConstructionWithNullBuffer(type, name) {
    var array;
    try {
        array = new type(null, 0, 0);
        testPassed("Construction of " + name + " with null buffer shouldn't throw exception");
    } catch (e) {
        testFailed("Construction of " + name + " with null buffer threw exception");
    }
}


function testConstructionWithOutOfRangeValues(type, name) {
    var buffer = new ArrayBuffer(4);
    var array;
    try {
        array = new type(buffer, 4, 0x3FFFFFFF);
        testFailed("Construction of " + name + " with out-of-range values should throw exception");
    } catch (e) {
        testPassed("Construction of " + name + " with out-of-range values threw exception");
    }
}

function testConstructionWithNegativeOutOfRangeValues(type, name) {
    var buffer = new ArrayBuffer(4);
    var array;
    try {
        array = new type(buffer, 4, -2147483648);
        testFailed("Construction of " + name + " with negative out-of-range values should throw exception");
    } catch (e) {
        testPassed("Construction of " + name + " with negative out-of-range values threw exception");
    }
}

function testConstructionOfHugeArray(type, name, sz) {
    if (sz == 1)
        return;
    try {
        // Construction of huge arrays must fail because byteLength is
        // an unsigned long
        array = new type(3000000000);
        testFailed("Construction of huge " + name + " should throw exception");
    } catch (e) {
        testPassed("Construction of huge " + name + " threw exception");
    }
}

// These need to be global for shouldBe to see them
var array;
var typeSize;

function testSubarrayWithOutOfRangeValues(type, name, sz) {
    debug("Testing subarray of " + name);
    try {
        var buffer = new ArrayBuffer(32);
        array = new type(buffer);
        typeSize = sz;
        shouldBe("array.length", "32 / typeSize");
        try {
            shouldBe("array.subarray(4, 0x3FFFFFFF).length", "(32 / typeSize) - 4");
            shouldBe("array.subarray(4, -2147483648).length", "0");
        } catch (e) {
            testFailed("Subarray of " + name + " threw exception");
        }
    } catch (e) {
        testFailed("Exception: " + e);
    }
}

function testSettingFromArrayWithOutOfRangeOffset(type, name) {
    var webglArray = new type(32);
    var array = [];
    for (var i = 0; i < 16; i++) {
        array.push(i);
    }
    try {
        webglArray.set(array, 0x7FFFFFF8);
        testFailed("Setting " + name + " from array with out-of-range offset was not caught");
    } catch (e) {
        testPassed("Setting " + name + " from array with out-of-range offset was caught");
    }
}

function testSettingFromFakeArrayWithOutOfRangeLength(type, name) {
    var webglArray = new type(32);
    var array = {};
    array.length = 0x80000000;
    try {
        webglArray.set(array, 8);
        testFailed("Setting " + name + " from fake array with invalid length was not caught");
    } catch (e) {
        testPassed("Setting " + name + " from fake array with invalid length was caught");
    }
}

function testSettingFromWebGLArrayWithOutOfRangeOffset(type, name) {
    var webglArray = new type(32);
    var srcArray = new type(16);
    for (var i = 0; i < 16; i++) {
        srcArray[i] = i;
    }
    try {
        webglArray.set(srcArray, 0x7FFFFFF8);
        testFailed("Setting " + name + " from " + name + " with out-of-range offset was not caught");
    } catch (e) {
        testPassed("Setting " + name + " from " + name + " with out-of-range offset was caught");
    }
}

var typeNames = [ "Int8Array",
                  "Uint8Array",
                  "Int16Array",
                  "Uint16Array",
                  "Int32Array",
                  "Uint32Array",
                  "Float32Array" ];

var typeSizes = [ 1, 1, 2, 2, 4, 4, 4 ];

for (var i = 0; i < typeNames.length; i++) {
    var name = typeNames[i];
    var type = window[name];
    if (!type) {
        testFailed("Could not find array type " + name);
    } else {
        testConstructionWithNullBuffer(type, name);
        testConstructionWithOutOfRangeValues(type, name);
        testConstructionWithNegativeOutOfRangeValues(type, name);
        testConstructionOfHugeArray(type, name, typeSizes[i]);
        testSubarrayWithOutOfRangeValues(type, name, typeSizes[i]);
        testSettingFromArrayWithOutOfRangeOffset(type, name);
        testSettingFromFakeArrayWithOutOfRangeLength(type, name);
        testSettingFromWebGLArrayWithOutOfRangeOffset(type, name);
    }
}

buffer = new ArrayBuffer(40);
ints = new Int32Array(buffer, 0, 10);
floats = new Float32Array(buffer, 0, 10);
// Plant a NaN into the buffer
ints[0]=-0x7ffff;
// Read the NaN out as a float
shouldBeTrue("isNaN(floats[0])");

</script>
</body>
</html>
