diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance/typedarrays')
8 files changed, 2004 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/00_test_list.txt new file mode 100644 index 0000000000..732aad646c --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/00_test_list.txt @@ -0,0 +1,7 @@ +array-buffer-crash.html +array-buffer-view-crash.html +array-unit-tests.html +data-view-crash.html +data-view-test.html +--min-version 1.0.2 typed-arrays-in-workers.html +--min-version 1.0.3 array-large-array-tests.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-buffer-crash.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-buffer-crash.html new file mode 100644 index 0000000000..59348727e1 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-buffer-crash.html @@ -0,0 +1,40 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +description('Test ArrayBuffer.byteLength'); + +// The following used to cause a crash in Chrome. + +// Note that because the argument to ArrayBuffer's constructor is not +// optional, an implementation might throw an exception on the expression +// below rather than implicitly passing undefined. Either way is acceptable +// from the point of view of this test, but implementations must not crash. +try { + new ArrayBuffer().byteLength; +} catch (e) { +} + +testPassed("new ArrayBuffer().byteLength did not crash"); +var successfullyParsed = true; + +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-buffer-view-crash.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-buffer-view-crash.html new file mode 100644 index 0000000000..cecb8138c5 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-buffer-view-crash.html @@ -0,0 +1,41 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +description('Verify that constructing a typed array view with no arguments and fetching its length does not crash'); + + +// The following used to cause a crash in both Safari and Chrome. + +// Note that because the argument to ArrayBuffer's constructor is not +// optional, an implementation might throw an exception on the expression +// below rather than implicitly passing undefined. Either way is acceptable +// from the point of view of this test, but implementations must not crash. +try { + new Uint32Array().length; +} catch (e) { +} + +testPassed("new Uint32Array().length did not crash"); +var successfullyParsed = true; + +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-large-array-tests.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-large-array-tests.html new file mode 100644 index 0000000000..8af76136aa --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-large-array-tests.html @@ -0,0 +1,102 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/tests/typed-array-test-cases.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +description("Verifies allocation of large array buffers"); + +var currentlyRunning = ''; +var allPassed = true; +function running(str) { + currentlyRunning = str; +} + +function output(str) { + debug(str); +} + +function pass() { + testPassed(currentlyRunning); +} + +function fail(str) { + allPassed = false; + var exc; + if (str) + exc = currentlyRunning + ': ' + str; + else + exc = currentlyRunning; + testFailed(exc); +} + +function assertEq(prefix, expected, val) { + if (expected != val) { + var str = prefix + ': expected ' + expected + ', got ' + val; + throw str; + } +} + +function assert(prefix, expected) { + if (!expected) { + var str = prefix + ': expected value / true'; + throw str; + } +} + +function printSummary() { + if (allPassed) { + debug("Test passed."); + } else { + debug("TEST FAILED"); + } +} + + +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"); + } +} + +function runTests() { + allPassed = true; + + for (var i = 0; i < testCases.length; i++) { + var testCase = testCases[i]; + running(testCase.name); + if (!(testCase.name in window)) { + fail("does not exist"); + continue; + } + var type = window[testCase.name]; + var name = testCase.name; + testConstructionOfHugeArray(type, name, testCase.elementSizeInBytes); + } +} + +runTests(); +var successfullyParsed = true; + +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> + diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-unit-tests.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-unit-tests.html new file mode 100644 index 0000000000..22f0e452ed --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/array-unit-tests.html @@ -0,0 +1,1103 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/test-eval.js"></script> +<script src="../../js/tests/typed-array-test-cases.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +description("Verifies the functionality of the new array-like objects in the TypedArray spec"); + +var currentlyRunning = ''; +var allPassed = true; +function running(str) { + currentlyRunning = str; +} + +function output(str) { + debug(str); +} + +function pass() { + testPassed(currentlyRunning); +} + +function fail(str) { + allPassed = false; + var exc; + if (str) + exc = currentlyRunning + ': ' + str; + else + exc = currentlyRunning; + testFailed(exc); +} + +function assertEq(prefix, expected, val) { + if (expected != val) { + var str = prefix + ': expected ' + expected + ', got ' + val; + throw str; + } +} + +function assert(prefix, expected) { + if (!expected) { + var str = prefix + ': expected value / true'; + throw str; + } +} + +function printSummary() { + if (allPassed) { + debug("Test passed."); + } else { + debug("TEST FAILED"); + } +} + +var buffer; +var byteLength; +var subBuffer; +var subArray; +function testSlice() { + function test(subBuf, starts, size) { + byteLength = size; + subBuffer = TestEval(subBuf); + subArray = new Int8Array(subBuffer); + assertEq(subBuf, subBuffer.byteLength, byteLength); + for (var i = 0; i < size; ++i) + assertEq('Element ' + i, starts + i, subArray[i]); + } + + try { + running('testSlice'); + buffer = new ArrayBuffer(32); + var array = new Int8Array(buffer); + for (var i = 0; i < 32; ++i) + array[i] = i; + + test("buffer.slice(0)", 0, 32); + test("buffer.slice(16)", 16, 16); + test("buffer.slice(24)", 24, 8); + test("buffer.slice(32)", 32, 0); + test("buffer.slice(40)", 32, 0); + test("buffer.slice(80)", 32, 0); + + test("buffer.slice(-8)", 24, 8); + test("buffer.slice(-16)", 16, 16); + test("buffer.slice(-24)", 8, 24); + test("buffer.slice(-32)", 0, 32); + test("buffer.slice(-40)", 0, 32); + test("buffer.slice(-80)", 0, 32); + + test("buffer.slice(0, 32)", 0, 32); + test("buffer.slice(0, 16)", 0, 16); + test("buffer.slice(8, 24)", 8, 16); + test("buffer.slice(16, 32)", 16, 16); + test("buffer.slice(24, 16)", 24, 0); + + test("buffer.slice(16, -8)", 16, 8); + test("buffer.slice(-20, 30)", 12, 18); + + test("buffer.slice(-8, -20)", 24, 0); + test("buffer.slice(-20, -8)", 12, 12); + test("buffer.slice(-40, 16)", 0, 16); + test("buffer.slice(-40, 40)", 0, 32); + pass(); + } catch (e) { + fail(e); + } +} + +function testArrayBufferIsViewMethod() { + debug('test ArrayBuffer.isView() with various values'); + + try { + if (!ArrayBuffer.isView) { + testFailed('ArrayBuffer.isView() method does not exist'); + } else { + testPassed('ArrayBuffer.isView() method exists'); + + shouldBe('ArrayBuffer.isView(new Int8Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Uint8Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Uint8ClampedArray(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Int16Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Uint16Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Int32Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Uint32Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Float32Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new Float64Array(1))', 'true'); + shouldBe('ArrayBuffer.isView(new DataView(new ArrayBuffer(8)))', 'true'); + + shouldBe('ArrayBuffer.isView(undefined)', 'false'); + shouldBe('ArrayBuffer.isView(null)', 'false'); + shouldBe('ArrayBuffer.isView(true)', 'false'); + shouldBe('ArrayBuffer.isView(false)', 'false'); + shouldBe('ArrayBuffer.isView(0)', 'false'); + shouldBe('ArrayBuffer.isView(1)', 'false'); + shouldBe('ArrayBuffer.isView(1.0)', 'false'); + shouldBe('ArrayBuffer.isView("hello")', 'false'); + shouldBe('ArrayBuffer.isView({})', 'false'); + shouldBe('ArrayBuffer.isView(function() {})', 'false'); + shouldBe('ArrayBuffer.isView(new Array(1))', 'false'); + } + } catch (e) { + testFailed('Exception thrown while testing ArrayBuffer.isView method: ' + e); + } +} + +function testInheritanceHierarchy() { + debug('test inheritance hierarchy of typed array views'); + + try { + var foo = ArrayBufferView; + testFailed('ArrayBufferView is a typedef and should not be defined'); + } catch (e) { + testPassed('ArrayBufferView is a typedef and was (correctly) not defined'); + } + + // Uint8ClampedArray inherited from Uint8Array in earlier versions + // of the typed array specification. Since this is no longer the + // case, assert the new behavior. + shouldBe('new Uint8ClampedArray(1) instanceof Uint8Array', 'false'); + + if (Object.getPrototypeOf(Int8Array.prototype) == Object.prototype) { + // ES5 behavior. + shouldBe('Object.getPrototypeOf(Int8Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Uint8Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Uint8ClampedArray.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Int16Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Uint16Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Int32Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Uint32Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Float32Array.prototype)', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Float64Array.prototype)', 'Object.prototype'); + } else { + // As of ES6, the prototypes for typed array constructors point to an intrinsic object whose internal + // prototype is Object.prototype. Relevant spec section is 22.2.5.2: TypedArray.prototype. + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Int8Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Uint8Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Uint8ClampedArray.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Int16Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Uint16Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Int32Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Uint32Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Float32Array.prototype))', 'Object.prototype'); + shouldBe('Object.getPrototypeOf(Object.getPrototypeOf(Float64Array.prototype))', 'Object.prototype'); + } + + shouldBe('Object.getPrototypeOf(DataView.prototype)', 'Object.prototype'); +} + +// +// Tests for unsigned array variants +// + +function testSetAndGet10To1(type, name) { + running('test ' + name + ' SetAndGet10To1'); + try { + var array = new type(10); + for (var i = 0; i < 10; i++) { + array[i] = 10 - i; + } + for (var i = 0; i < 10; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function testConstructWithArrayOfUnsignedValues(type, name) { + running('test ' + name + ' ConstructWithArrayOfUnsignedValues'); + try { + var array = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); + assertEq('Array length', 10, array.length); + for (var i = 0; i < 10; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function testConstructWithTypedArrayOfUnsignedValues(type, name) { + running('test ' + name + ' ConstructWithTypedArrayOfUnsignedValues'); + try { + var tmp = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); + var array = new type(tmp); + assertEq('Array length', 10, array.length); + for (var i = 0; i < 10; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +// +// Tests for signed array variants +// + +function testSetAndGetPos10ToNeg10(type, name) { + running('test ' + name + ' SetAndGetPos10ToNeg10'); + try { + var array = new type(21); + for (var i = 0; i < 21; i++) { + array[i] = 10 - i; + } + for (var i = 0; i < 21; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function testConstructWithArrayOfSignedValues(type, name) { + running('test ' + name + ' ConstructWithArrayOfSignedValues'); + try { + var array = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]); + assertEq('Array length', 21, array.length); + for (var i = 0; i < 21; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function testConstructWithTypedArrayOfSignedValues(type, name) { + running('test ' + name + ' ConstructWithTypedArrayOfSignedValues'); + try { + var tmp = new type([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]); + var array = new type(tmp); + assertEq('Array length', 21, array.length); + for (var i = 0; i < 21; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +// +// Test cases for integral types. +// Some JavaScript engines need separate copies of this code in order +// to exercise all of their optimized code paths. +// + +function testIntegralArrayTruncationBehavior(type, name, unsigned) { + running('test integral array truncation behavior for ' + name); + + var sourceData; + var expectedResults; + + if (unsigned) { + sourceData = [0.6, 10.6, 0.2, 10.2, 10.5, 11.5]; + if (type === Uint8ClampedArray) { + expectedResults = [1, 11, 0, 10, 10, 12]; + } else { + expectedResults = [0, 10, 0, 10, 10, 11]; + } + } else { + sourceData = [0.6, 10.6, -0.6, -10.6]; + expectedResults = [0, 10, 0, -10]; + } + + var numIterations = 10; + var array = new type(numIterations); + + // The code block in each of the case statements below is identical, but some + // JavaScript engines need separate copies in order to exercise all of + // their optimized code paths. + + try { + switch (type) { + case Int8Array: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + case Int16Array: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + case Int32Array: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + case Uint8Array: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + case Uint8ClampedArray: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + case Uint16Array: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + case Uint32Array: + for (var ii = 0; ii < sourceData.length; ++ii) { + for (var jj = 0; jj < numIterations; ++jj) { + array[jj] = sourceData[ii]; + assertEq('Storing ' + sourceData[ii], expectedResults[ii], array[jj]); + } + } + break; + default: + fail("Unhandled type"); + break; + } + + pass(); + } catch (e) { + fail(e); + } +} + + +// +// Test cases for both signed and unsigned types +// + +function testGetWithOutOfRangeIndices(type, name) { + debug('Testing ' + name + ' GetWithOutOfRangeIndices'); + // See below for declaration of this global variable + array = new type([2, 3]); + shouldBeUndefined("array[2]"); + shouldBeUndefined("array[-1]"); + shouldBeUndefined("array[0x20000000]"); +} + +function testOffsetsAndSizes(type, name, elementSizeInBytes) { + running('test ' + name + ' OffsetsAndSizes'); + try { + var len = 10; + assertEq('type.BYTES_PER_ELEMENT', elementSizeInBytes, type.BYTES_PER_ELEMENT); + var array = new type(len); + assert('array.buffer', array.buffer); + assertEq('array.byteOffset', 0, array.byteOffset); + assertEq('array.length', len, array.length); + assertEq('array.byteLength', len * elementSizeInBytes, array.byteLength); + array = new type(array.buffer, elementSizeInBytes, len - 1); + assert('array.buffer', array.buffer); + assertEq('array.byteOffset', elementSizeInBytes, array.byteOffset); + assertEq('array.length', len - 1, array.length); + assertEq('array.byteLength', (len - 1) * elementSizeInBytes, array.byteLength); + pass(); + } catch (e) { + fail(e); + } +} + +function testSetFromTypedArray(type, name) { + running('test ' + name + ' SetFromTypedArray'); + try { + var array = new type(10); + var array2 = new type(5); + for (var i = 0; i < 10; i++) { + assertEq('Element ' + i, 0, array[i]); + } + for (var i = 0; i < array2.length; i++) { + array2[i] = i; + } + array.set(array2); + for (var i = 0; i < array2.length; i++) { + assertEq('Element ' + i, i, array[i]); + } + array.set(array2, 5); + for (var i = 0; i < array2.length; i++) { + assertEq('Element ' + i, i, array[5 + i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function negativeTestSetFromTypedArray(type, name) { + running('negativeTest ' + name + ' SetFromTypedArray'); + try { + var array = new type(5); + var array2 = new type(6); + for (var i = 0; i < 5; i++) { + assertEq('Element ' + i, 0, array[i]); + } + for (var i = 0; i < array2.length; i++) { + array2[i] = i; + } + try { + array.set(array2); + fail('Expected exception from array.set(array2)'); + return; + } catch (e) { + } + try { + array2.set(array, 2); + fail('Expected exception from array2.set(array, 2)'); + return; + } catch (e) { + } + pass(); + } catch (e) { + fail(e); + } +} + +function testSetFromArray(type, name) { + running('test ' + name + ' SetFromArray'); + try { + var array = new type(10); + var array2 = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + for (var i = 0; i < 10; i++) { + assertEq('Element ' + i, 0, array[i]); + } + array.set(array2, 0); + for (var i = 0; i < array2.length; i++) { + assertEq('Element ' + i, 10 - i, array[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function negativeTestSetFromArray(type, name) { + running('negativeTest ' + name + ' SetFromArray'); + try { + var array = new type([2, 3]); + try { + array.set([4, 5], 1); + fail(); + return; + } catch (e) { + } + try { + array.set([4, 5, 6]); + fail(); + return; + } catch (e) { + } + pass(); + } catch (e) { + fail(e); + } +} + +var subarray; +function testSubarray(type, name) { + running('test ' + name + ' Subarray'); + try { + var array = new type([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + var subarray = array.subarray(0, 5); + assertEq('subarray.length', 5, subarray.length); + for (var i = 0; i < 5; i++) { + assertEq('Element ' + i, i, subarray[i]); + } + subarray = array.subarray(4, 10); + assertEq('subarray.length', 6, subarray.length); + for (var i = 0; i < 6; i++) { + assertEq('Element ' + i, 4 + i, subarray[i]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function testSubarrayOffsetAndLengthClamping(type, name) { + running('test ' + name + ' Subarray offset and length clamping'); + try { + var array = new type([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + var subarray1 = array.subarray(0, 5); + var subarray2 = subarray1.subarray(-2, 10); + assertEq('subarray2.length', 2, subarray2.length); + assertEq('Element ' + 0, 3, subarray2[0]); + assertEq('Element ' + 1, 4, subarray2[1]); + pass(); + } catch (e) { + fail(e); + } +} + +function negativeTestSubarray(type, name) { + running('negativeTest ' + name + ' Subarray'); + try { + var array = new type([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + subarray = array.subarray(5, 11); + if (subarray.length != 5) { + fail(); + return; + } + subarray = array.subarray(10, 10); + if (subarray.length != 0) { + fail(); + return; + } + pass(); + } catch (e) { + fail(e); + } +} + +function testSetBoundaryConditions(type, name, testValues, expectedValues) { + running('test ' + name + ' SetBoundaryConditions'); + try { + var array = new type(1); + assertEq('Array length', 1, array.length); + for (var ii = 0; ii < testValues.length; ++ii) { + for (var jj = 0; jj < 10; ++jj) { + array[0] = testValues[ii]; + assertEq('Element 0', expectedValues[ii], array[0]); + } + } + pass(); + } catch (e) { + fail(e); + } +} + +function testConstructionBoundaryConditions(type, name, testValues, expectedValues) { + running('test ' + name + ' ConstructionBoundaryConditions'); + try { + var array = new type(testValues); + assertEq('Array length', testValues.length, array.length); + for (var ii = 0; ii < testValues.length; ++ii) { + assertEq('Element ' + ii, expectedValues[ii], array[ii]); + } + pass(); + } catch (e) { + fail(e); + } +} + +function testConstructionWithNullBuffer(type, name) { + var array; + try { + array = new type(null); + assertEq("Length of " + name + " constructed with null", 0, array.length); + testPassed("Construction of " + name + " with null produced a " + name + " of length 0"); + } catch (e) { + // This used to be correct, but TC39 has changed the behavior of these constructors. + testPassed("Construction of " + name + " with null threw exception"); + } + try { + array = new type(null, 0); + assertEq("Length of " + name + " constructed with null", 0, array.length); + testPassed("Construction of " + name + " with null produced a " + name + " of length 0"); + } catch (e) { + // This used to be correct, but TC39 has changed the behavior of these constructors. + testPassed("Construction of " + name + " with (null, 0) threw exception"); + } + try { + array = new type(null, 0, 0); + assertEq("Length of " + name + " constructed with null", 0, array.length); + testPassed("Construction of " + name + " with null produced a " + name + " of length 0"); + } catch (e) { + // This used to be correct, but TC39 has changed the behavior of these constructors. + testPassed("Construction of " + name + " with (null, 0, 0) threw exception"); + } +} + +function testConstructionWithExceptionThrowingObject(type, name) { + var o = {}; + Object.defineProperty(o, "length", { get: function() { throw "bail;" }}); + try { + var array = new type(o); + } catch (e) { + } + testPassed("Construction of " + name + " with exception-throwing array-like object didn't crash unexpectedly"); +} + +function shouldThrowIndexSizeErr(func, text) { + var errorText = text + " should throw an exception"; + try { + func(); + testFailed(errorText); + } catch (e) { + testPassed(text + " threw an exception"); + } +} + +function shouldThrowTypeError(func, text) { + var ok = false; + try { + func(); + } catch (e) { + if (e instanceof TypeError) { + ok = true; + } + } + if (ok) { + testPassed(text + " threw TypeError"); + } else { + testFailed(text + " should throw TypeError"); + } +} + +function testConstructionWithOutOfRangeValues(type, name) { + shouldThrowIndexSizeErr(function() { + var buffer = new ArrayBuffer(4); + var array = new type(buffer, 4, 0x3FFFFFFF); + }, "Construction of " + name + " with out-of-range number of elements"); + shouldThrowIndexSizeErr(function() { + var buffer = new ArrayBuffer(4); + var array = new type(buffer, 8); + }, "Construction of " + name + " with out-of-range offset"); +} + +function testConstructionWithNegativeOutOfRangeValues(type, name) { + try { + var buffer = new ArrayBuffer(-1); + testFailed("Construction of ArrayBuffer with negative size should throw exception"); + } catch (e) { + testPassed("Construction of ArrayBuffer with negative size threw exception"); + } + try { + var array = new type(-1); + testFailed("Construction of " + name + " with negative size should throw exception"); + } catch (e) { + testPassed("Construction of " + name + " with negative size threw exception"); + } + shouldThrowIndexSizeErr(function() { + var buffer = new ArrayBuffer(4); + var array = new type(buffer, 4, -2147483648); + }, "Construction of " + name + " with negative out-of-range values"); +} + +function testConstructionWithUnalignedOffset(type, name, elementSizeInBytes) { + if (elementSizeInBytes > 1) { + shouldThrowIndexSizeErr(function() { + var buffer = new ArrayBuffer(32); + var array = new type(buffer, 1, elementSizeInBytes); + }, "Construction of " + name + " with unaligned offset"); + } +} + +function testConstructionWithUnalignedLength(type, name, elementSizeInBytes) { + if (elementSizeInBytes > 1) { + shouldThrowIndexSizeErr(function() { + var buffer = new ArrayBuffer(elementSizeInBytes + 1); + var array = new type(buffer, 0); + }, "Construction of " + name + " with unaligned length"); + } +} + +function testConstructionWithBothArrayBufferAndLength(type, name, elementSizeInBytes) { + var bufByteLength = 1000 * elementSizeInBytes; + var buf = new ArrayBuffer(bufByteLength); + var array1 = new type(buf); + var array2 = new type(bufByteLength / elementSizeInBytes); + if (array1.length == array2.length) { + testPassed("Array lengths matched with explicit and implicit creation of ArrayBuffer"); + } else { + testFailed("Array lengths DID NOT MATCH with explicit and implicit creation of ArrayBuffer"); + } +} + +function testConstructionWithSubPortionOfArrayBuffer(type, name, elementSizeInBytes) { + if (elementSizeInBytes > 1) { + // Test construction with a valid sub-portion of an array buffer + // (whose size is not an integral multiple of the element size). + var size = 4 * elementSizeInBytes + (elementSizeInBytes / 2); + var buf = new ArrayBuffer(size); + try { + var array = new type(buf, 0, 2); + testPassed("new " + name + "(new ArrayBuffer(" + size + "), 0, 2) succeeded"); + } catch (e) { + testFailed("new " + name + "(new ArrayBuffer(" + size + "), 0, 2) failed: " + e); + } + } +} + +// 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"); + // Test subarray() against overflows. + array = array.subarray(2); + if (sz > 1) { + // Full byte offset is +1 larger than the maximum unsigned long int. + // Make sure subarray() still handles it correctly. Otherwise overflow would happen and + // offset would be 0, and array.length array.length would incorrectly be 1. + var start = 4294967296 / sz - 2; + array = array.subarray(start, start + 1); + shouldBe("array.length", "0"); + } + } catch (e) { + testFailed("Subarray of " + name + " threw exception"); + } + } catch (e) { + testFailed("Exception: " + e); + } +} + +function testSubarrayWithDefaultValues(type, name, sz) { + debug("Testing subarray with default inputs of " + name); + try { + var buffer = new ArrayBuffer(32); + array = new type(buffer); + typeSize = sz; + shouldBe("array.length", "32 / typeSize"); + try { + shouldBe("array.subarray(0).length", "(32 / typeSize)"); + shouldBe("array.subarray(2).length", "(32 / typeSize) - 2"); + shouldBe("array.subarray(-2).length", "2"); + shouldBe("array.subarray(-2147483648).length", "(32 / typeSize)"); + } catch (e) { + testFailed("Subarray of " + name + " threw exception"); + } + } catch (e) { + testFailed("Exception: " + e); + } +} + +function setWithInvalidOffset(type, name, length, + sourceType, sourceName, sourceLength, + offset, offsetDescription) { + var webglArray = new type(length); + var sourceArray = new sourceType(sourceLength); + for (var i = 0; i < sourceLength; i++) + sourceArray[i] = 42 + i; + try { + webglArray.set(sourceArray, offset); + testFailed("Setting " + name + " from " + sourceName + " with " + + offsetDescription + " offset was not caught"); + } catch (e) { + testPassed("Setting " + name + " from " + sourceName + " with " + + offsetDescription + " offset was caught"); + } +} + +function setWithValidOffset(type, name, length, + sourceType, sourceName, sourceLength, + offset, offsetDescription) { + running("Setting " + name + " from " + sourceName + " with " + + offsetDescription + " offset"); + var webglArray = new type(length); + var sourceArray = new sourceType(sourceLength); + for (var i = 0; i < sourceLength; i++) + sourceArray[i] = 42 + i; + try { + webglArray.set(sourceArray, offset); + offset = Math.floor(offset); + for (var i = 0; i < sourceLength; i++) { + assertEq("Element " + i + offset, sourceArray[i], webglArray[i + offset]); + } + pass(); + } catch (e) { + fail(e); + } +} + + +function testSettingFromArrayWithOutOfRangeOffset(type, name) { + setWithInvalidOffset(type, name, 32, Array, "array", 16, + 0x7FFFFFF8, "out-of-range"); +} + +function testSettingFromTypedArrayWithOutOfRangeOffset(type, name) { + setWithInvalidOffset(type, name, 32, type, name, 16, + 0x7FFFFFF8, "out-of-range"); +} + +function testSettingFromArrayWithNegativeOffset(type, name) { + setWithInvalidOffset(type, name, 32, Array, "array", 16, + -1, "negative"); +} + +function testSettingFromTypedArrayWithNegativeOffset(type, name) { + setWithInvalidOffset(type, name, 32, type, name, 16, + -1, "negative"); +} + +function testSettingFromArrayWithMinusZeroOffset(type, name) { + setWithValidOffset(type, name, 32, Array, "array", 16, + -0, "-0"); +} + +function testSettingFromTypedArrayWithMinusZeroOffset(type, name) { + setWithValidOffset(type, name, 32, type, name, 16, + -0, "-0"); +} + +function testSettingFromArrayWithBoundaryOffset(type, name) { + setWithValidOffset(type, name, 32, Array, "array", 16, + 16, "boundary"); +} + +function testSettingFromTypedArrayWithBoundaryOffset(type, name) { + setWithValidOffset(type, name, 32, type, name, 16, + 16, "boundary"); +} + +function testSettingFromArrayWithNonIntegerOffset(type, name) { + setWithValidOffset(type, name, 32, Array, "array", 16, + 16.999, "non-integer"); +} + +function testSettingFromTypedArrayWithNonIntegerOffset(type, name) { + setWithValidOffset(type, name, 32, type, name, 16, + 16.999, "non-integer"); +} + +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 negativeTestGetAndSetMethods(type, name) { + array = new type([2, 3]); + shouldBeUndefined("array.get"); + var exceptionThrown = false; + // We deliberately check for an exception here rather than using + // shouldThrow here because the precise contents of the syntax + // error are not specified. + try { + webGLArray.set(0, 1); + } catch (e) { + exceptionThrown = true; + } + var output = "array.set(0, 1) "; + if (exceptionThrown) { + testPassed(output + "threw exception."); + } else { + testFailed(output + "did not throw exception."); + } +} + +function testNaNConversion(type, name) { + running('test storing NaN in ' + name); + + var array = new type([1, 1]); + var results = []; + + // The code block in each of the case statements below is identical, but some + // JavaScript engines need separate copies in order to exercise all of + // their optimized code paths. + try { + switch (type) { + case Float32Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Float64Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Int8Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Int16Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Int32Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Uint8Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Uint8ClampedArray: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Uint16Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + case Uint32Array: + for (var i = 0; i < array.length; ++i) { + array[i] = NaN; + results[i] = array[i]; + } + break; + default: + fail("Unhandled type"); + break; + } + + // Some types preserve NaN values; all other types convert NaN to zero. + if (type === Float32Array || type === Float64Array) { + assert('initial NaN preserved', isNaN(new type([NaN])[0])); + for (var i = 0; i < array.length; ++i) + assert('NaN preserved via setter', isNaN(results[i])); + } else { + assertEq('initial NaN converted to zero', 0, new type([NaN])[0]); + for (var i = 0; i < array.length; ++i) + assertEq('NaN converted to zero by setter', 0, results[i]); + } + + pass(); + } catch (e) { + fail(e); + } +} + +// +// Test driver +// + +function runTests() { + allPassed = true; + + testSlice(); + testArrayBufferIsViewMethod(); + testInheritanceHierarchy(); + + for (var i = 0; i < testCases.length; i++) { + var testCase = testCases[i]; + running(testCase.name); + if (!(testCase.name in window)) { + fail("does not exist"); + continue; + } + var type = window[testCase.name]; + var name = testCase.name; + if (testCase.unsigned) { + testSetAndGet10To1(type, name); + testConstructWithArrayOfUnsignedValues(type, name); + testConstructWithTypedArrayOfUnsignedValues(type, name); + } else { + testSetAndGetPos10ToNeg10(type, name); + testConstructWithArrayOfSignedValues(type, name); + testConstructWithTypedArrayOfSignedValues(type, name); + } + if (testCase.integral) { + testIntegralArrayTruncationBehavior(type, name, testCase.unsigned); + } + testGetWithOutOfRangeIndices(type, name); + testOffsetsAndSizes(type, name, testCase.elementSizeInBytes); + testSetFromTypedArray(type, name); + negativeTestSetFromTypedArray(type, name); + testSetFromArray(type, name); + negativeTestSetFromArray(type, name); + testSubarray(type, name); + testSubarrayOffsetAndLengthClamping(type, name); + negativeTestSubarray(type, name); + testSetBoundaryConditions(type, + name, + testCase.testValues, + testCase.expectedValues); + testConstructionBoundaryConditions(type, + name, + testCase.testValues, + testCase.expectedValues); + testConstructionWithNullBuffer(type, name); + testConstructionWithExceptionThrowingObject(type, name); + testConstructionWithOutOfRangeValues(type, name); + testConstructionWithNegativeOutOfRangeValues(type, name); + testConstructionWithUnalignedOffset(type, name, testCase.elementSizeInBytes); + testConstructionWithUnalignedLength(type, name, testCase.elementSizeInBytes); + testConstructionWithBothArrayBufferAndLength(type, name, testCase.elementSizeInBytes); + testConstructionWithSubPortionOfArrayBuffer(type, name, testCase.elementSizeInBytes); + testSubarrayWithOutOfRangeValues(type, name, testCase.elementSizeInBytes); + testSubarrayWithDefaultValues(type, name, testCase.elementSizeInBytes); + testSettingFromArrayWithOutOfRangeOffset(type, name); + testSettingFromTypedArrayWithOutOfRangeOffset(type, name); + testSettingFromArrayWithNegativeOffset(type, name); + testSettingFromTypedArrayWithNegativeOffset(type, name); + testSettingFromArrayWithMinusZeroOffset(type, name); + testSettingFromTypedArrayWithMinusZeroOffset(type, name); + testSettingFromArrayWithBoundaryOffset(type, name); + testSettingFromTypedArrayWithBoundaryOffset(type, name); + testSettingFromArrayWithNonIntegerOffset(type, name); + testSettingFromTypedArrayWithNonIntegerOffset(type, name); + testSettingFromFakeArrayWithOutOfRangeLength(type, name); + negativeTestGetAndSetMethods(type, name); + testNaNConversion(type, name); + } + + printSummary(); +} + +runTests(); +var successfullyParsed = true; + +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/data-view-crash.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/data-view-crash.html new file mode 100644 index 0000000000..f634660181 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/data-view-crash.html @@ -0,0 +1,33 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; +description("Test that DataView does not crash with bad offset or length."); + +var array = new Uint8Array([164, 112, 157, 63]); +var view; +shouldThrow("view = new DataView(array.buffer, -4500000000)"); +shouldThrow("view = new DataView(array.buffer, -4500000000, 4500000000)"); +var value = view ? view.getFloat32(0, true) : 0; + +var successfullyParsed = true; +</script> + +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/data-view-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/data-view-test.html new file mode 100644 index 0000000000..1413227578 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/data-view-test.html @@ -0,0 +1,421 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/test-eval.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; +description("Test DataView."); + +var intArray1 = [0, 1, 2, 3, 100, 101, 102, 103, 128, 129, 130, 131, 252, 253, 254, 255]; +var intArray2 = [31, 32, 33, 0, 1, 2, 3, 100, 101, 102, 103, 128, 129, 130, 131, 252, 253, 254, 255]; +var emptyArray = [204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204]; + +var arrayBuffer = null; +var view = null; +var viewStart = 0; +var viewLength = 0; + +function getElementSize(func) +{ + switch (func) { + case "Int8": + case "Uint8": + return 1; + case "Int16": + case "Uint16": + return 2; + case "Int32": + case "Uint32": + case "Float32": + return 4; + case "Float64": + return 8; + default: + debug("Should not reached"); + } +} + +function checkGet(func, index, expected, littleEndian) +{ + var expr = "view.get" + func + "(" + index; + if (littleEndian != undefined) { + expr += ", "; + expr += littleEndian ? "true" : "false"; + } + expr += ")"; + if (index >= 0 && index + getElementSize(func) - 1 < view.byteLength) + shouldBe(expr, expected); + else + shouldThrow(expr); +} + +function checkSet(func, index, value, littleEndian) +{ + var expr = "view.set" + func + "(" + index + ", " + value; + if (littleEndian != undefined) { + expr += ", "; + expr += littleEndian ? "true" : "false"; + } + expr += ")"; + if (index >= 0 && index + getElementSize(func) - 1 < view.byteLength) { + shouldBeUndefined(expr); + checkGet(func, index, value, littleEndian); + } else + shouldThrow(expr); +} + +function checkGetWithoutArgument(func, expected) +{ + var threw = false; + var value; + try { + value = view["get" + func](); + } catch (e) { + threw = true; + } + + if (threw) { + // This used to be correct, but TC39 has changed the behavior of these methods. + testPassed("view.get" + func + " with no arguments throws."); + } else { + if (value === expected) { + testPassed("view.get" + func + " treats missing argument as 0."); + } else { + testFailed("view.get" + func + " accepts a missing argument but does not cast it to 0."); + } + } +} + +function checkSetWithoutSecondArgument(func, index, isFloat) +{ + var expected = isFloat ? NaN : 0; + var threw = false; + var value; + try { + value = view["set" + func](index); + } catch (e) { + threw = true; + } + + if (threw) { + // This used to be correct, but TC39 has changed the behavior of these methods. + testPassed("view.set" + func + " with missing second argument throws."); + } else { + var stored = view["get" + func](index); + if (value === undefined && isFloat ? isNaN(stored) : stored === expected) { + testPassed("view.set" + func + " treats missing second argument as " + expected + "."); + } else { + testFailed("view.set" + func + " accepts a missing second argument but does not cast it to " + expected + "."); + } + } +} + +function checkSetWithoutArguments(func, isFloat) +{ + var expected = isFloat ? NaN : 0; + var threw = false; + var value; + try { + value = view["set" + func](); + } catch (e) { + threw = true; + } + + if (threw) { + // This used to be correct, but TC39 has changed the behavior of these methods. + testPassed("view.set" + func + " with no arguments throws."); + } else { + var stored = view["get" + func](0); + if (value === undefined && isFloat ? isNaN(stored) : stored === expected) { + testPassed("view.set" + func + " treats missing first argument as 0."); + } else { + testFailed("view.set" + func + " accepts a missing first argument but does not cast it to 0."); + } + } +} + +function testMissingArguments(func, constructor, isFloat) +{ + view = new DataView((new constructor(3)).buffer); + view["set" + func](0, 1); + view["set" + func](getElementSize(func), 2); + checkGetWithoutArgument(func, 1); + checkSetWithoutSecondArgument(func, getElementSize(func), isFloat); + view = new DataView((new constructor(3)).buffer); + view["set" + func](0, 1); + checkSetWithoutArguments(func, isFloat); +} + +function test(isTestingGet, func, index, value, littleEndian) +{ + if (isTestingGet) + checkGet(func, index, value, littleEndian); + else + checkSet(func, index, value, littleEndian); +} + +function createDataView(array, frontPaddingNum, littleEndian, start, length) +{ + if (!littleEndian) + array.reverse(); + var paddingArray = new Array(frontPaddingNum); + arrayBuffer = (new Uint8Array(paddingArray.concat(array))).buffer; + viewStart = (start != undefined) ? start : 0; + viewLength = (length != undefined) ? length : arrayBuffer.byteLength - viewStart; + view = new DataView(arrayBuffer, viewStart, viewLength); + if (!littleEndian) + array.reverse(); // restore the array. +} + +function runIntegerTestCases(isTestingGet, array, start, length) +{ + createDataView(array, 0, true, start, length); + + test(isTestingGet, "Int8", 0, "0"); + test(isTestingGet, "Int8", 8, "-128"); + test(isTestingGet, "Int8", 15, "-1"); + + test(isTestingGet, "Uint8", 0, "0"); + test(isTestingGet, "Uint8", 8, "128"); + test(isTestingGet, "Uint8", 15, "255"); + + // Little endian. + test(isTestingGet, "Int16", 0, "256", true); + test(isTestingGet, "Int16", 5, "26213", true); + test(isTestingGet, "Int16", 9, "-32127", true); + test(isTestingGet, "Int16", 14, "-2", true); + + // Big endian. + test(isTestingGet, "Int16", 0, "1"); + test(isTestingGet, "Int16", 5, "25958"); + test(isTestingGet, "Int16", 9, "-32382"); + test(isTestingGet, "Int16", 14, "-257"); + + // Little endian. + test(isTestingGet, "Uint16", 0, "256", true); + test(isTestingGet, "Uint16", 5, "26213", true); + test(isTestingGet, "Uint16", 9, "33409", true); + test(isTestingGet, "Uint16", 14, "65534", true); + + // Big endian. + test(isTestingGet, "Uint16", 0, "1"); + test(isTestingGet, "Uint16", 5, "25958"); + test(isTestingGet, "Uint16", 9, "33154"); + test(isTestingGet, "Uint16", 14, "65279"); + + // Little endian. + test(isTestingGet, "Int32", 0, "50462976", true); + test(isTestingGet, "Int32", 3, "1717920771", true); + test(isTestingGet, "Int32", 6, "-2122291354", true); + test(isTestingGet, "Int32", 9, "-58490239", true); + test(isTestingGet, "Int32", 12, "-66052", true); + + // Big endian. + test(isTestingGet, "Int32", 0, "66051"); + test(isTestingGet, "Int32", 3, "56911206"); + test(isTestingGet, "Int32", 6, "1718059137"); + test(isTestingGet, "Int32", 9, "-2122152964"); + test(isTestingGet, "Int32", 12, "-50462977"); + + // Little endian. + test(isTestingGet, "Uint32", 0, "50462976", true); + test(isTestingGet, "Uint32", 3, "1717920771", true); + test(isTestingGet, "Uint32", 6, "2172675942", true); + test(isTestingGet, "Uint32", 9, "4236477057", true); + test(isTestingGet, "Uint32", 12, "4294901244", true); + + // Big endian. + test(isTestingGet, "Uint32", 0, "66051"); + test(isTestingGet, "Uint32", 3, "56911206"); + test(isTestingGet, "Uint32", 6, "1718059137"); + test(isTestingGet, "Uint32", 9, "2172814332"); + test(isTestingGet, "Uint32", 12, "4244504319"); +} + +function testFloat(isTestingGet, func, array, start, expected) +{ + // Little endian. + createDataView(array, 0, true, start); + test(isTestingGet, func, 0, expected, true); + createDataView(array, 3, true, start); + test(isTestingGet, func, 3, expected, true); + createDataView(array, 7, true, start); + test(isTestingGet, func, 7, expected, true); + createDataView(array, 10, true, start); + test(isTestingGet, func, 10, expected, true); + + // Big endian. + createDataView(array, 0, false); + test(isTestingGet, func, 0, expected, false); + createDataView(array, 3, false); + test(isTestingGet, func, 3, expected, false); + createDataView(array, 7, false); + test(isTestingGet, func, 7, expected, false); + createDataView(array, 10, false); + test(isTestingGet, func, 10, expected, false); +} + +function runFloatTestCases(isTestingGet, start) +{ + testFloat(isTestingGet, "Float32", isTestingGet ? [0, 0, 32, 65] : emptyArray, start, "10"); + testFloat(isTestingGet, "Float32", isTestingGet ? [164, 112, 157, 63] : emptyArray, start, "1.2300000190734863"); + testFloat(isTestingGet, "Float32", isTestingGet ? [95, 53, 50, 199] : emptyArray, start, "-45621.37109375"); + testFloat(isTestingGet, "Float32", isTestingGet ? [255, 255, 255, 127] : emptyArray, start, "NaN"); + testFloat(isTestingGet, "Float32", isTestingGet ? [255, 255, 255, 255] : emptyArray, start, "-NaN"); + + testFloat(isTestingGet, "Float64", isTestingGet ? [0, 0, 0, 0, 0, 0, 36, 64] : emptyArray, start, "10"); + testFloat(isTestingGet, "Float64", isTestingGet ? [174, 71, 225, 122, 20, 174, 243, 63] : emptyArray, start, "1.23"); + testFloat(isTestingGet, "Float64", isTestingGet ? [181, 55, 248, 30, 242, 179, 87, 193] : emptyArray, start, "-6213576.4839"); + testFloat(isTestingGet, "Float64", isTestingGet ? [255, 255, 255, 255, 255, 255, 255, 127] : emptyArray, start, "NaN"); + testFloat(isTestingGet, "Float64", isTestingGet ? [255, 255, 255, 255, 255, 255, 255, 255] : emptyArray, start, "-NaN"); +} + +function runNegativeIndexTests(isTestingGet) +{ + createDataView(intArray1, 0, true, 0, 16); + + test(isTestingGet, "Int8", -1, "0"); + test(isTestingGet, "Int8", -2, "0"); + + test(isTestingGet, "Uint8", -1, "0"); + test(isTestingGet, "Uint8", -2, "0"); + + test(isTestingGet, "Int16", -1, "0"); + test(isTestingGet, "Int16", -2, "0"); + test(isTestingGet, "Int16", -3, "0"); + + test(isTestingGet, "Uint16", -1, "0"); + test(isTestingGet, "Uint16", -2, "0"); + test(isTestingGet, "Uint16", -3, "0"); + + test(isTestingGet, "Int32", -1, "0"); + test(isTestingGet, "Int32", -3, "0"); + test(isTestingGet, "Int32", -5, "0"); + + test(isTestingGet, "Uint32", -1, "0"); + test(isTestingGet, "Uint32", -3, "0"); + test(isTestingGet, "Uint32", -5, "0"); + + createDataView([0, 0, 0, 0, 0, 0, 36, 64], 0, true, 0, 8); + + test(isTestingGet, "Float32", -1, "0"); + test(isTestingGet, "Float32", -3, "0"); + test(isTestingGet, "Float32", -5, "0"); + + test(isTestingGet, "Float64", -1, "0"); + test(isTestingGet, "Float64", -5, "0"); + test(isTestingGet, "Float64", -9, "0"); +} + +function runConstructorTests() +{ + arrayBuffer = (new Uint8Array([1, 2])).buffer; + + debug(""); + debug("Test for constructor taking 1 argument"); + shouldBeDefined("view = new DataView(arrayBuffer)"); + shouldBe("view.byteOffset", "0"); + shouldBe("view.byteLength", "2"); + + debug(""); + debug("Test for constructor taking 2 arguments"); + shouldBeDefined("view = new DataView(arrayBuffer, 1)"); + shouldBe("view.byteOffset", "1"); + shouldBe("view.byteLength", "1"); + + debug(""); + debug("Test for constructor taking 3 arguments"); + shouldBeDefined("view = new DataView(arrayBuffer, 0, 1)"); + shouldBe("view.byteOffset", "0"); + shouldBe("view.byteLength", "1"); + + debug(""); + debug("Test for constructor throwing exception"); + shouldThrow("view = new DataView(arrayBuffer, 0, 3)"); + shouldThrow("view = new DataView(arrayBuffer, 1, 2)"); + shouldThrow("view = new DataView(arrayBuffer, 2, 1)"); +} + +function runGetTests() +{ + debug(""); + debug("Test for get methods that work"); + runIntegerTestCases(true, intArray1, 0, 16); + runFloatTestCases(true, 0); + + debug(""); + debug("Test for get methods that might read beyond range"); + runIntegerTestCases(true, intArray2, 3, 2); + runFloatTestCases(true, 3); + + debug(""); + debug("Test for get methods that read from negative index"); + runNegativeIndexTests(true); +} + +function runSetTests() +{ + debug(""); + debug("Test for set methods that work"); + runIntegerTestCases(false, emptyArray, 0, 16); + runFloatTestCases(false); + + debug(""); + debug("Test for set methods that might write beyond the range"); + runIntegerTestCases(false, emptyArray, 3, 2); + runFloatTestCases(false, 7); + + debug(""); + debug("Test for set methods that write to negative index"); + runNegativeIndexTests(false); +} + +function runMissingArgumentTests() +{ + debug(""); + debug("Test for get and set methods missing arguments"); + testMissingArguments("Int8", Int8Array); + testMissingArguments("Uint8", Uint8Array); + testMissingArguments("Int16", Int16Array); + testMissingArguments("Uint16", Uint16Array); + testMissingArguments("Int32", Int32Array); + testMissingArguments("Uint32", Uint32Array); + testMissingArguments("Float32", Float32Array, true); + testMissingArguments("Float64", Float64Array, true); +} + +function runIndexingTests() +{ + debug(""); + debug("Test for indexing that should not work"); + view = new DataView((new Uint8Array([1, 2])).buffer); + shouldBeUndefined("view[0]"); + shouldBeDefined("view[0] = 3"); + shouldBe("view.getUint8(0)", "1"); +} + +runConstructorTests(); +runGetTests(); +runSetTests(); +runMissingArgumentTests(); +runIndexingTests(); +var successfullyParsed = true; +</script> + +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/typed-arrays-in-workers.html b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/typed-arrays-in-workers.html new file mode 100644 index 0000000000..69eb057589 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/typedarrays/typed-arrays-in-workers.html @@ -0,0 +1,257 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/test-eval.js"></script> +<script src="../../js/tests/typed-array-test-cases.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> + +<script> +"use strict"; + +var testQueue = []; +var transferSupported = true; + +function nextTest() { + if (testQueue[0].subTests.length > 0) { + testQueue[0].subTests.shift(); + } + + while (testQueue.length > 0 && testQueue[0].subTests.length == 0) { + testQueue.shift(); + } + + if (testQueue.length == 0) { + finishTest(); + return; + } + + testQueue[0].subTests[0].runner(); +} + +function handleMessage(event) { + if (testQueue.length == 0) + return; + + if (testQueue[0].subTests.length == 0) + return; + + testQueue[0].subTests[0].checker(event); + nextTest(); +} + +function setupTest(testCase, runner, checker) { + testCase.subTests.push({ runner: runner.bind(null, testCase), checker: checker.bind(null, testCase) }); +} + +function arrayToString(arr) { + var result = "[ "; + for (var ii = 0; ii < arr.length; ++ii) { + if (ii > 0) + result += ", "; + result += arr[ii]; + } + return result + " ]"; +} + +function constructTypedArray(type, data) { + if (type == 'Int8Array') { + return new Int8Array(data); + } else if (type == 'Uint8Array') { + return new Uint8Array(data); + } else if (type == 'Uint8ClampedArray') { + return new Uint8ClampedArray(data); + } else if (type == 'Int16Array') { + return new Int16Array(data); + } else if (type == 'Uint16Array') { + return new Uint16Array(data); + } else if (type == 'Int32Array') { + return new Int32Array(data); + } else if (type == 'Uint32Array') { + return new Uint32Array(data); + } else if (type == 'Float32Array') { + return new Float32Array(data); + } else if (type == 'Float64Array') { + return new Float64Array(data); + } +} + +// Test runner / checker pairs +function runTestWithData(command, testCase) { + worker.postMessage({command: command, type: testCase.name, subType: testCase.subType, elementSizeInBytes: testCase.elementSizeInBytes, data: testCase.testValues}); +} + +function checkArraysEqual(testKind, testCase, event) { + var array = event.data; + var testName = testKind + " " + testCase.name + " from worker to main thread"; + if (areArraysEqual(array, testCase.expectedValues)) { + testPassed(testName); + } else { + testFailed(testName + ": expected " + arrayToString(testCase.expectedValues) + ", received " + arrayToString(array)); + } +} + +function checkBufferContentsEqual(testKind, testCase, event) { + var array = constructTypedArray(testCase.name, event.data); + var testName = testKind + " containing " + testCase.name + " values from worker to main thread"; + if (areArraysEqual(array, testCase.expectedValues)) { + testPassed(testName); + } else { + testFailed(testName + ": expected " + arrayToString(testCase.expectedValues) + ", received " + arrayToString(array)); + } +} + +function checkDataViewContents(testKind, testCase, event) { + var dataView = event.data; + var testName = testKind + " " + testCase.name + " containing " + testCase.subType + " from worker to main thread"; + var byteOffset = 0; + var allPassed = true; + for (var ii = 0; ii < testCase.expectedValues.length; ++ii) { + var expected = testCase.expectedValues[ii]; + var received = dataView['get' + testCase.subType](byteOffset); + if (received != expected) { + allPassed = false; + testFailed(testName + ": at byte offset " + byteOffset + ": expected " + expected + ", received " + received); + } + byteOffset += testCase.elementSizeInBytes; + } + if (allPassed) { + testPassed(testName); + } +} + +// Missing test: copy or transfer ArrayBuffer, wrap in DataView on this end, verify contents. + +function noop() { +} + +function checkArraysEqualAndPingPong(testKind, transfer, testCase, event) { + checkArraysEqual(testKind, testCase, event); + var transferables = []; + if (transfer) { + transferables.push(event.data.buffer); + } + try { + worker.postMessage({ command: 'pong', data: event.data, transferables: transferables }, transferables); + } catch (e) { + testFailed("unexpected exception: " + e); + } +} + +function checkBufferContentsEqualAndPingPong(testKind, transfer, testCase, event) { + checkBufferContentsEqual(testKind, testCase, event); + var transferables = []; + if (transfer) { + transferables.push(event.data); + } + try { + worker.postMessage({ command: 'pong', data: event.data, transferables: transferables }, transferables); + } catch (e) { + testFailed("unexpected exception: " + e); + } +} + +function checkDataViewContentsAndPingPong(testKind, transfer, testCase, event) { + checkDataViewContents(testKind, testCase, event); + var transferables = []; + if (transfer) { + transferables.push(event.data.buffer); + } + try { + worker.postMessage({ command: 'pong', data: event.data, transferables: transferables }, transferables); + } catch (e) { + testFailed("unexpected exception: " + e); + } +} + +description("Tests copying and transferring typed arrays and ArrayBuffers to and from workers"); + +// See whether workers are supported at all +if (window.Worker) { + // Start up the worker + var worker = new Worker('../../js/tests/typed-array-worker.js'); + worker.onmessage = handleMessage; + + // See whether transferables are supported + var buffer = new ArrayBuffer(16); + try { + worker.postMessage({ command: 'ignore', data: buffer }, [buffer]); + if (buffer.byteLength > 0) + transferSupported = false; + } catch (e) { + transferSupported = false; + } + + // Iterate down the tests, queueing them up + for (var ii = 0; ii < testCases.length; ++ii) { + var testCase = testCases[ii]; + testCase.subTests = []; + setupTest(testCase, runTestWithData.bind(null, 'copy'), checkArraysEqual.bind(null, 'copy')); + setupTest(testCase, runTestWithData.bind(null, 'copyBuffer'), checkBufferContentsEqual.bind(null, 'copy ArrayBuffer')); + setupTest(testCase, runTestWithData.bind(null, 'transfer'), checkArraysEqual.bind(null, 'transfer')); + setupTest(testCase, runTestWithData.bind(null, 'transferBuffer'), checkBufferContentsEqual.bind(null, 'transfer ArrayBuffer')); + + // These two must run back-to-back + setupTest(testCase, runTestWithData.bind(null, 'copy'), checkArraysEqualAndPingPong.bind(null, 'copy', false)); + setupTest(testCase, noop, checkArraysEqual.bind(null, 'ping-pong with copy')); + + // These two must run back-to-back + setupTest(testCase, runTestWithData.bind(null, 'copyBuffer'), checkBufferContentsEqualAndPingPong.bind(null, 'copy ArrayBuffer', false)); + setupTest(testCase, noop, checkBufferContentsEqual.bind(null, 'ping-pong with copy')); + + // These two must run back-to-back + setupTest(testCase, runTestWithData.bind(null, 'transfer'), checkArraysEqualAndPingPong.bind(null, 'transfer', true)); + setupTest(testCase, noop, checkArraysEqual.bind(null, 'ping-pong with transfer')); + + // These two must run back-to-back + setupTest(testCase, runTestWithData.bind(null, 'transferBuffer'), checkBufferContentsEqualAndPingPong.bind(null, 'transfer ArrayBuffer', false)); + setupTest(testCase, noop, checkBufferContentsEqual.bind(null, 'ping-pong with transfer')); + + testQueue.push(testCase); + + // Add just a couple of DataView tests; the behavior of that view type is thoroughly tested elsewhere + if (testCase.name == "Float32Array" || testCase.name == "Int32Array") { + var subTypeName = (testCase.name == "Float32Array" ? "Float32" : "Int32"); + var dataViewTestCase = { name: "DataView", + subType: subTypeName, + elementSizeInBytes: testCase.elementSizeInBytes, + testValues: testCase.testValues, + expectedValues: testCase.expectedValues, + subTests: [] }; + setupTest(dataViewTestCase, runTestWithData.bind(null, 'copy'), checkDataViewContents.bind(null, 'copy')); + setupTest(dataViewTestCase, runTestWithData.bind(null, 'transfer'), checkDataViewContents.bind(null, 'transfer')); + + // These two must run back-to-back + setupTest(dataViewTestCase, runTestWithData.bind(null, 'copy'), checkDataViewContentsAndPingPong.bind(null, 'copy', false)); + setupTest(dataViewTestCase, noop, checkDataViewContents.bind(null, 'ping-pong with copy')); + + // These two must run back-to-back + setupTest(dataViewTestCase, runTestWithData.bind(null, 'transfer'), checkDataViewContentsAndPingPong.bind(null, 'transfer', false)); + setupTest(dataViewTestCase, noop, checkDataViewContents.bind(null, 'ping-pong with transfer')); + + testQueue.push(dataViewTestCase); + } + } + + // Kick things off + testQueue[0].subTests[0].runner(); +} else { + debug("Workers not supported -- skipping test"); + finishTest(); +} + +var successfullyParsed = true; +</script> +</body> +</html> |