// // typedArraysunitTest.js // examples // // Created by Clément Brisset on 7/7/14 // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // Script.include("Test.js"); // e.g. extractbits([0xff, 0x80, 0x00, 0x00], 23, 30); inclusive function extractbits(bytes, lo, hi) { var out = 0; bytes = bytes.slice(); // make a copy var lsb = bytes.pop(), sc = 0, sh = 0; for (; lo > 0; lo--, hi--) { lsb >>= 1; if (++sc === 8) { sc = 0; lsb = bytes.pop(); } } for (; hi >= 0; hi--) { out = out | (lsb & 0x01) << sh++; lsb >>= 1; if (++sc === 8) { sc = 0; lsb = bytes.pop(); } } return out; } test('ArrayBuffer', function(finished) { this.assertEquals(new ArrayBuffer(0).byteLength, 0, 'no length'); this.assertEquals(typeof(new ArrayBuffer(0)), 'object', 'creation'); this.assertEquals(typeof(new ArrayBuffer(1)), 'object', 'creation'); this.assertEquals(typeof(new ArrayBuffer(123)), 'object', 'creation'); this.assertEquals(new ArrayBuffer(123).byteLength, 123, 'length'); this.raises(function () { return new ArrayBuffer(-1); }, 'negative length'); this.raises(function () { return new ArrayBuffer(0x80000000); }, 'absurd length'); }); test('DataView constructors', function (finished) { var d = new DataView(new ArrayBuffer(8)); d.setUint32(0, 0x12345678); this.assertEquals(d.getUint32(0), 0x12345678, 'big endian/big endian'); d.setUint32(0, 0x12345678, true); this.assertEquals(d.getUint32(0, true), 0x12345678, 'little endian/little endian'); d.setUint32(0, 0x12345678, true); this.assertEquals(d.getUint32(0), 0x78563412, 'little endian/big endian'); d.setUint32(0, 0x12345678); this.assertEquals(d.getUint32(0, true), 0x78563412, 'big endian/little endian'); this.raises(function () { return new DataView({}); }, 'non-ArrayBuffer argument'); this.raises(function () { return new DataView("bogus"); }, 'non-ArrayBuffer argument'); }); test('ArrayBufferView', function () { var ab = new ArrayBuffer(48); var i32 = new Int32Array(ab, 16); i32.set([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(i32.buffer, ab, 'ArrayBuffers equal'); this.assertEquals(i32.byteOffset, 16, 'byteOffset'); this.assertEquals(i32.byteLength, 32, 'byteLength'); var da = new DataView(i32.buffer, 8); this.assertEquals(da.buffer, ab, 'DataView: ArrayBuffers equal'); this.assertEquals(da.byteOffset, 8, 'DataView: byteOffset'); this.assertEquals(da.byteLength, 40, 'DataView: byteLength'); }); test('TypedArrays', function () { var a; this.assertEquals(Int8Array.BYTES_PER_ELEMENT, 1, 'Int8Array.BYTES_PER_ELEMENT'); a = new Int8Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 1, 'int8Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'int8Array.byteOffset'); this.assertEquals(a.byteLength, 8, 'int8Array.byteLength'); this.assertEquals(Uint8Array.BYTES_PER_ELEMENT, 1, 'Uint8Array.BYTES_PER_ELEMENT'); a = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 1, 'uint8Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'uint8Array.byteOffset'); this.assertEquals(a.byteLength, 8, 'uint8Array.byteLength'); this.assertEquals(Int16Array.BYTES_PER_ELEMENT, 2, 'Int16Array.BYTES_PER_ELEMENT'); a = new Int16Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 2, 'int16Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'int16Array.byteOffset'); this.assertEquals(a.byteLength, 16, 'int16Array.byteLength'); this.assertEquals(Uint16Array.BYTES_PER_ELEMENT, 2, 'Uint16Array.BYTES_PER_ELEMENT'); a = new Uint16Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 2, 'uint16Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'uint16Array.byteOffset'); this.assertEquals(a.byteLength, 16, 'uint16Array.byteLength'); this.assertEquals(Int32Array.BYTES_PER_ELEMENT, 4, 'Int32Array.BYTES_PER_ELEMENT'); a = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 4, 'int32Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'int32Array.byteOffset'); this.assertEquals(a.byteLength, 32, 'int32Array.byteLength'); this.assertEquals(Uint32Array.BYTES_PER_ELEMENT, 4, 'Uint32Array.BYTES_PER_ELEMENT'); a = new Uint32Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 4, 'uint32Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'uint32Array.byteOffset'); this.assertEquals(a.byteLength, 32, 'uint32Array.byteLength'); this.assertEquals(Float32Array.BYTES_PER_ELEMENT, 4, 'Float32Array.BYTES_PER_ELEMENT'); a = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 4, 'float32Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'float32Array.byteOffset'); this.assertEquals(a.byteLength, 32, 'float32Array.byteLength'); this.assertEquals(Float64Array.BYTES_PER_ELEMENT, 8, 'Float64Array.BYTES_PER_ELEMENT'); a = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8]); this.assertEquals(a.BYTES_PER_ELEMENT, 8, 'float64Array.BYTES_PER_ELEMENT'); this.assertEquals(a.byteOffset, 0, 'float64Array.byteOffset'); this.assertEquals(a.byteLength, 64, 'float64Array.byteLength'); }); test('typed array constructors', function () { this.arrayEqual(new Int8Array({ length: 3 }), [0, 0, 0], 'array equal -1'); var rawbuf = (new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7])).buffer; var int8 = new Int8Array(); this.assertEquals(int8.length, 0, 'no args 0'); this.raises(function () { return new Int8Array(-1); }, 'bogus length'); this.raises(function () { return new Int8Array(0x80000000); }, 'bogus length'); int8 = new Int8Array(4); this.assertEquals(int8.BYTES_PER_ELEMENT, 1); this.assertEquals(int8.length, 4, 'length 1'); this.assertEquals(int8.byteLength, 4, 'length 2'); this.assertEquals(int8.byteOffset, 0, 'length 3'); this.assertEquals(int8.get(-1), undefined, 'length, out of bounds 4'); this.assertEquals(int8.get(4), undefined, 'length, out of bounds 5'); int8 = new Int8Array([1, 2, 3, 4, 5, 6]); this.assertEquals(int8.length, 6, 'array 6'); this.assertEquals(int8.byteLength, 6, 'array 7'); this.assertEquals(int8.byteOffset, 0, 'array 8'); this.assertEquals(int8.get(3), 4, 'array 9'); this.assertEquals(int8.get(-1), undefined, 'array, out of bounds 10'); this.assertEquals(int8.get(6), undefined, 'array, out of bounds 11'); int8 = new Int8Array(rawbuf); this.assertEquals(int8.length, 8, 'buffer 12'); this.assertEquals(int8.byteLength, 8, 'buffer 13'); this.assertEquals(int8.byteOffset, 0, 'buffer 14'); this.assertEquals(int8.get(7), 7, 'buffer 15'); int8.set([111]); this.assertEquals(int8.get(0), 111, 'buffer 16'); this.assertEquals(int8.get(-1), undefined, 'buffer, out of bounds 17'); this.assertEquals(int8.get(8), undefined, 'buffer, out of bounds 18'); int8 = new Int8Array(rawbuf, 2); this.assertEquals(int8.length, 6, 'buffer, byteOffset 19'); this.assertEquals(int8.byteLength, 6, 'buffer, byteOffset 20'); this.assertEquals(int8.byteOffset, 2, 'buffer, byteOffset 21'); this.assertEquals(int8.get(5), 7, 'buffer, byteOffset 22'); int8.set([112]); this.assertEquals(int8.get(0), 112, 'buffer 23'); this.assertEquals(int8.get(-1), undefined, 'buffer, byteOffset, out of bounds 24'); this.assertEquals(int8.get(6), undefined, 'buffer, byteOffset, out of bounds 25'); int8 = new Int8Array(rawbuf, 8); this.assertEquals(int8.length, 0, 'buffer, byteOffset 26'); this.raises(function () { return new Int8Array(rawbuf, -1); }, 'invalid byteOffset 27'); this.raises(function () { return new Int8Array(rawbuf, 9); }, 'invalid byteOffset 28'); this.raises(function () { return new Int32Array(rawbuf, -1); }, 'invalid byteOffset 29'); this.raises(function () { return new Int32Array(rawbuf, 5); }, 'invalid byteOffset 30'); int8 = new Int8Array(rawbuf, 2, 4); this.assertEquals(int8.length, 4, 'buffer, byteOffset, length 31'); this.assertEquals(int8.byteLength, 4, 'buffer, byteOffset, length 32'); this.assertEquals(int8.byteOffset, 2, 'buffer, byteOffset, length 33'); this.assertEquals(int8.get(3), 5, 'buffer, byteOffset, length 34'); int8.set([113]); this.assertEquals(int8.get(0), 113, 'buffer, byteOffset, length 35'); this.assertEquals(int8.get(-1), undefined, 'buffer, byteOffset, length, out of bounds 36'); this.assertEquals(int8.get(4), undefined, 'buffer, byteOffset, length, out of bounds 37'); this.raises(function () { return new Int8Array(rawbuf, 0, 9); }, 'invalid byteOffset+length'); this.raises(function () { return new Int8Array(rawbuf, 8, 1); }, 'invalid byteOffset+length'); this.raises(function () { return new Int8Array(rawbuf, 9, -1); }, 'invalid byteOffset+length'); }); test('TypedArray clone constructor', function () { var src = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8]); var dst = new Int32Array(src); this.arrayEqual(dst, [1, 2, 3, 4, 5, 6, 7, 8], '1'); src.set([99]); this.arrayEqual(src, [99, 2, 3, 4, 5, 6, 7, 8], '2'); this.arrayEqual(dst, [1, 2, 3, 4, 5, 6, 7, 8], '3'); }); test('conversions', function () { var uint8 = new Uint8Array([1, 2, 3, 4]), uint16 = new Uint16Array(uint8.buffer), uint32 = new Uint32Array(uint8.buffer); // Note: can't probe individual bytes without endianness awareness this.arrayEqual(uint8, [1, 2, 3, 4]); uint16.set([0xffff]); this.arrayEqual(uint8, [0xff, 0xff, 3, 4]); uint16.set([0xeeee], 1); this.arrayEqual(uint8, [0xff, 0xff, 0xee, 0xee]); uint32.set([0x11111111]); this.assertEquals(uint16.get(0), 0x1111); this.assertEquals(uint16.get(1), 0x1111); this.arrayEqual(uint8, [0x11, 0x11, 0x11, 0x11]); }); test('signed/unsigned conversions', function () { var int8 = new Int8Array(1), uint8 = new Uint8Array(int8.buffer); uint8.set([123]); this.assertEquals(int8.get(0), 123, 'int8/uint8'); uint8.set([161]); this.assertEquals(int8.get(0), -95, 'int8/uint8'); int8.set([-120]); this.assertEquals(uint8.get(0), 136, 'uint8/int8'); int8.set([-1]); this.assertEquals(uint8.get(0), 0xff, 'uint8/int8'); var int16 = new Int16Array(1), uint16 = new Uint16Array(int16.buffer); uint16.set([3210]); this.assertEquals(int16.get(0), 3210, 'int16/uint16'); uint16.set([49232]); this.assertEquals(int16.get(0), -16304, 'int16/uint16'); int16.set([-16384]); this.assertEquals(uint16.get(0), 49152, 'uint16/int16'); int16.set([-1]); this.assertEquals(uint16.get(0), 0xffff, 'uint16/int16'); var int32 = new Int32Array(1), uint32 = new Uint32Array(int32.buffer); uint32.set([0x80706050]); this.assertEquals(int32.get(0), -2140118960, 'int32/uint32'); int32.set([-2023406815]); this.assertEquals(uint32.get(0), 0x87654321, 'uint32/int32'); int32.set([-1]); this.assertEquals(uint32.get(0), 0xffffffff, 'uint32/int32'); }); test('IEEE754 single precision unpacking', function () { function fromBytes(bytes) { var uint8 = new Uint8Array(bytes), dv = new DataView(uint8.buffer); return dv.getFloat32(0); } this.assertEquals(isNaN(fromBytes([0xff, 0xff, 0xff, 0xff])), true, 'Q-NaN'); this.assertEquals(isNaN(fromBytes([0xff, 0xc0, 0x00, 0x01])), true, 'Q-NaN'); this.assertEquals(isNaN(fromBytes([0xff, 0xc0, 0x00, 0x00])), true, 'Indeterminate'); this.assertEquals(isNaN(fromBytes([0xff, 0xbf, 0xff, 0xff])), true, 'S-NaN'); this.assertEquals(isNaN(fromBytes([0xff, 0x80, 0x00, 0x01])), true, 'S-NaN'); this.assertEquals(fromBytes([0xff, 0x80, 0x00, 0x00]), -Infinity, '-Infinity'); this.assertEquals(fromBytes([0xff, 0x7f, 0xff, 0xff]), -3.4028234663852886E+38, '-Normalized'); this.assertEquals(fromBytes([0x80, 0x80, 0x00, 0x00]), -1.1754943508222875E-38, '-Normalized'); this.assertEquals(fromBytes([0xff, 0x7f, 0xff, 0xff]), -3.4028234663852886E+38, '-Normalized'); this.assertEquals(fromBytes([0x80, 0x80, 0x00, 0x00]), -1.1754943508222875E-38, '-Normalized'); // TODO: Denormalized values fail on Safari on iOS/ARM this.assertEquals(fromBytes([0x80, 0x7f, 0xff, 0xff]), -1.1754942106924411E-38, '-Denormalized'); this.assertEquals(fromBytes([0x80, 0x00, 0x00, 0x01]), -1.4012984643248170E-45, '-Denormalized'); this.assertEquals(fromBytes([0x80, 0x00, 0x00, 0x00]), -0, '-0'); this.assertEquals(fromBytes([0x00, 0x00, 0x00, 0x00]), +0, '+0'); // TODO: Denormalized values fail on Safari on iOS/ARM this.assertEquals(fromBytes([0x00, 0x00, 0x00, 0x01]), 1.4012984643248170E-45, '+Denormalized'); this.assertEquals(fromBytes([0x00, 0x7f, 0xff, 0xff]), 1.1754942106924411E-38, '+Denormalized'); this.assertEquals(fromBytes([0x00, 0x80, 0x00, 0x00]), 1.1754943508222875E-38, '+Normalized'); this.assertEquals(fromBytes([0x7f, 0x7f, 0xff, 0xff]), 3.4028234663852886E+38, '+Normalized'); this.assertEquals(fromBytes([0x7f, 0x80, 0x00, 0x00]), +Infinity, '+Infinity'); this.assertEquals(isNaN(fromBytes([0x7f, 0x80, 0x00, 0x01])), true, 'S+NaN'); this.assertEquals(isNaN(fromBytes([0x7f, 0xbf, 0xff, 0xff])), true, 'S+NaN'); this.assertEquals(isNaN(fromBytes([0x7f, 0xc0, 0x00, 0x00])), true, 'Q+NaN'); this.assertEquals(isNaN(fromBytes([0x7f, 0xff, 0xff, 0xff])), true, 'Q+NaN'); }); test('IEEE754 single precision packing', function () { function toBytes(v) { var uint8 = new Uint8Array(4), dv = new DataView(uint8.buffer); dv.setFloat32(0, v); var bytes = []; for (var i = 0; i < 4; i += 1) { bytes.push(uint8.get(i)); } return bytes; } this.arrayEqual(toBytes(-Infinity), [0xff, 0x80, 0x00, 0x00], '-Infinity'); this.arrayEqual(toBytes(-3.4028235677973366e+38), [0xff, 0x80, 0x00, 0x00], '-Overflow'); this.arrayEqual(toBytes(-3.402824E+38), [0xff, 0x80, 0x00, 0x00], '-Overflow'); this.arrayEqual(toBytes(-3.4028234663852886E+38), [0xff, 0x7f, 0xff, 0xff], '-Normalized'); this.arrayEqual(toBytes(-1.1754943508222875E-38), [0x80, 0x80, 0x00, 0x00], '-Normalized'); // TODO: Denormalized values fail on Safari iOS/ARM this.arrayEqual(toBytes(-1.1754942106924411E-38), [0x80, 0x7f, 0xff, 0xff], '-Denormalized'); this.arrayEqual(toBytes(-1.4012984643248170E-45), [0x80, 0x00, 0x00, 0x01], '-Denormalized'); this.arrayEqual(toBytes(-7.006492321624085e-46), [0x80, 0x00, 0x00, 0x00], '-Underflow'); this.arrayEqual(toBytes(-0), [0x80, 0x00, 0x00, 0x00], '-0'); this.arrayEqual(toBytes(0), [0x00, 0x00, 0x00, 0x00], '+0'); this.arrayEqual(toBytes(7.006492321624085e-46), [0x00, 0x00, 0x00, 0x00], '+Underflow'); // TODO: Denormalized values fail on Safari iOS/ARM this.arrayEqual(toBytes(1.4012984643248170E-45), [0x00, 0x00, 0x00, 0x01], '+Denormalized'); this.arrayEqual(toBytes(1.1754942106924411E-38), [0x00, 0x7f, 0xff, 0xff], '+Denormalized'); this.arrayEqual(toBytes(1.1754943508222875E-38), [0x00, 0x80, 0x00, 0x00], '+Normalized'); this.arrayEqual(toBytes(3.4028234663852886E+38), [0x7f, 0x7f, 0xff, 0xff], '+Normalized'); this.arrayEqual(toBytes(+3.402824E+38), [0x7f, 0x80, 0x00, 0x00], '+Overflow'); this.arrayEqual(toBytes(+3.402824E+38), [0x7f, 0x80, 0x00, 0x00], '+Overflow'); this.arrayEqual(toBytes(+Infinity), [0x7f, 0x80, 0x00, 0x00], '+Infinity'); // Allow any NaN pattern (exponent all 1's, fraction non-zero) var nanbytes = toBytes(NaN), sign = extractbits(nanbytes, 31, 31), exponent = extractbits(nanbytes, 23, 30), fraction = extractbits(nanbytes, 0, 22); this.assertEquals(exponent === 255 && fraction !== 0, true, 'NaN'); }); test('IEEE754 double precision unpacking', function () { function fromBytes(bytes) { var uint8 = new Uint8Array(bytes), dv = new DataView(uint8.buffer); return dv.getFloat64(0); } this.assertEquals(isNaN(fromBytes([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])), true, 'Q-NaN'); this.assertEquals(isNaN(fromBytes([0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])), true, 'Q-NaN'); this.assertEquals(isNaN(fromBytes([0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])), true, 'Indeterminate'); this.assertEquals(isNaN(fromBytes([0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])), true, 'S-NaN'); this.assertEquals(isNaN(fromBytes([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])), true, 'S-NaN'); this.assertEquals(fromBytes([0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), -Infinity, '-Infinity'); this.assertEquals(fromBytes([0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), -1.7976931348623157E+308, '-Normalized'); this.assertEquals(fromBytes([0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), -2.2250738585072014E-308, '-Normalized'); // TODO: Denormalized values fail on Safari iOS/ARM this.assertEquals(fromBytes([0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), -2.2250738585072010E-308, '-Denormalized'); this.assertEquals(fromBytes([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]), -4.9406564584124654E-324, '-Denormalized'); this.assertEquals(fromBytes([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), -0, '-0'); this.assertEquals(fromBytes([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), +0, '+0'); // TODO: Denormalized values fail on Safari iOS/ARM this.assertEquals(fromBytes([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]), 4.9406564584124654E-324, '+Denormalized'); this.assertEquals(fromBytes([0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 2.2250738585072010E-308, '+Denormalized'); this.assertEquals(fromBytes([0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), 2.2250738585072014E-308, '+Normalized'); this.assertEquals(fromBytes([0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), 1.7976931348623157E+308, '+Normalized'); this.assertEquals(fromBytes([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), +Infinity, '+Infinity'); this.assertEquals(isNaN(fromBytes([0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])), true, 'S+NaN'); this.assertEquals(isNaN(fromBytes([0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])), true, 'S+NaN'); this.assertEquals(isNaN(fromBytes([0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])), true, 'Q+NaN'); this.assertEquals(isNaN(fromBytes([0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])), true, 'Q+NaN'); }); test('IEEE754 double precision packing', function () { function toBytes(v) { var uint8 = new Uint8Array(8), dv = new DataView(uint8.buffer); dv.setFloat64(0, v); var bytes = []; for (var i = 0; i < 8; i += 1) { bytes.push(uint8.get(i)); } return bytes; } this.arrayEqual(toBytes(-Infinity), [0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '-Infinity'); this.arrayEqual(toBytes(-1.7976931348623157E+308), [0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], '-Normalized'); this.arrayEqual(toBytes(-2.2250738585072014E-308), [0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '-Normalized'); // TODO: Denormalized values fail on Safari iOS/ARM this.arrayEqual(toBytes(-2.2250738585072010E-308), [0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], '-Denormalized'); this.arrayEqual(toBytes(-4.9406564584124654E-324), [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], '-Denormalized'); this.arrayEqual(toBytes(-0), [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '-0'); this.arrayEqual(toBytes(0), [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '+0'); // TODO: Denormalized values fail on Safari iOS/ARM this.arrayEqual(toBytes(4.9406564584124654E-324), [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], '+Denormalized'); this.arrayEqual(toBytes(2.2250738585072010E-308), [0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], '+Denormalized'); this.arrayEqual(toBytes(2.2250738585072014E-308), [0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '+Normalized'); this.arrayEqual(toBytes(1.7976931348623157E+308), [0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], '+Normalized'); this.arrayEqual(toBytes(+Infinity), [0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], '+Infinity'); // Allow any NaN pattern (exponent all 1's, fraction non-zero) var nanbytes = toBytes(NaN), sign = extractbits(nanbytes, 63, 63), exponent = extractbits(nanbytes, 52, 62), fraction = extractbits(nanbytes, 0, 51); this.assertEquals(exponent === 2047 && fraction !== 0, true, 'NaN'); }); test('Int32Array round trips', function () { var i32 = new Int32Array([0]); var data = [ 0, 1, -1, 123, -456, 0x80000000 >> 0, 0x7fffffff >> 0, 0x12345678 >> 0, 0x87654321 >> 0 ]; for (var i = 0; i < data.length; i += 1) { var datum = data[i]; i32.set([datum]); this.assertEquals(datum, i32.get(0), String(datum)); } }); test('Int16Array round trips', function () { var i16 = new Int16Array([0]); var data = [ 0, 1, -1, 123, -456, 0xffff8000 >> 0, 0x00007fff >> 0, 0x00001234 >> 0, 0xffff8765 >> 0 ]; for (var i = 0; i < data.length; i += 1) { var datum = data[i]; i16.set([datum]); this.assertEquals(datum, i16.get(0), String(datum)); } }); test('Int8Array round trips', function () { var i8 = new Int8Array([0]); var data = [ 0, 1, -1, 123, -45, 0xffffff80 >> 0, 0x0000007f >> 0, 0x00000012 >> 0, 0xffffff87 >> 0 ]; for (var i = 0; i < data.length; i += 1) { var datum = data[i]; i8.set([datum]); this.assertEquals(datum, i8.get(0), String(datum)); } }); test('TypedArray setting', function () { var a = new Int32Array([1, 2, 3, 4, 5]); var b = new Int32Array(5); b.set(a); this.arrayEqual(b, [1, 2, 3, 4, 5], '1'); this.raises(function () { b.set(a, 1); }); b.set(new Int32Array([99, 98]), 2); this.arrayEqual(b, [1, 2, 99, 98, 5], '2'); b.set(new Int32Array([99, 98, 97]), 2); this.arrayEqual(b, [1, 2, 99, 98, 97], '3'); this.raises(function () { b.set(new Int32Array([99, 98, 97, 96]), 2); }); this.raises(function () { b.set([101, 102, 103, 104], 4); }); // ab = [ 0, 1, 2, 3, 4, 5, 6, 7 ] // a1 = [ ^, ^, ^, ^, ^, ^, ^, ^ ] // a2 = [ ^, ^, ^, ^ ] var ab = new ArrayBuffer(8); var a1 = new Uint8Array(ab); for (var i = 0; i < a1.length; i += 1) { a1.set([i], i); } var a2 = new Uint8Array(ab, 4); a1.set(a2, 2); this.arrayEqual(a1, [0, 1, 4, 5, 6, 7, 6, 7]); this.arrayEqual(a2, [6, 7, 6, 7]); }); test('TypedArray.subarray', function () { var a = new Int32Array([1, 2, 3, 4, 5]); this.arrayEqual(a.subarray(3), [4, 5]); this.arrayEqual(a.subarray(1, 3), [2, 3]); this.arrayEqual(a.subarray(-3), [3, 4, 5]); this.arrayEqual(a.subarray(-3, -1), [3, 4]); this.arrayEqual(a.subarray(3, 2), []); this.arrayEqual(a.subarray(-2, -3), []); this.arrayEqual(a.subarray(4, 1), []); this.arrayEqual(a.subarray(-1, -4), []); this.arrayEqual(a.subarray(1).subarray(1), [3, 4, 5]); this.arrayEqual(a.subarray(1, 4).subarray(1, 2), [3]); }); test('DataView constructors', function () { var d = new DataView(new ArrayBuffer(8)); d.setUint32(0, 0x12345678); this.assertEquals(d.getUint32(0), 0x12345678, 'big endian/big endian'); d.setUint32(0, 0x12345678, true); this.assertEquals(d.getUint32(0, true), 0x12345678, 'little endian/little endian'); d.setUint32(0, 0x12345678, true); this.assertEquals(d.getUint32(0), 0x78563412, 'little endian/big endian'); d.setUint32(0, 0x12345678); this.assertEquals(d.getUint32(0, true), 0x78563412, 'big endian/little endian'); // Chrome allows no arguments, throws if non-ArrayBuffer //stricterEqual(new DataView().buffer.byteLength, 0, 'no arguments'); // Safari (iOS 5) does not //raises(function () { return new DataView(); }, TypeError, 'no arguments'); // Chrome raises TypeError, Safari iOS5 raises isDOMException(INDEX_SIZE_ERR) this.raises(function () { return new DataView({}); }, 'non-ArrayBuffer argument'); this.raises(function () { return new DataView("bogus"); }, TypeError, 'non-ArrayBuffer argument'); }); test('DataView accessors', function () { var u = new Uint8Array(8), d = new DataView(u.buffer); this.arrayEqual(u, [0, 0, 0, 0, 0, 0, 0, 0], '1'); d.setUint8(0, 255); this.arrayEqual(u, [0xff, 0, 0, 0, 0, 0, 0, 0], '2'); d.setInt8(1, -1); this.arrayEqual(u, [0xff, 0xff, 0, 0, 0, 0, 0, 0], '3'); d.setUint16(2, 0x1234); this.arrayEqual(u, [0xff, 0xff, 0x12, 0x34, 0, 0, 0, 0]), '4'; d.setInt16(4, -1); this.arrayEqual(u, [0xff, 0xff, 0x12, 0x34, 0xff, 0xff, 0, 0], '5'); d.setUint32(1, 0x12345678); this.arrayEqual(u, [0xff, 0x12, 0x34, 0x56, 0x78, 0xff, 0, 0], '6'); d.setInt32(4, -2023406815); this.arrayEqual(u, [0xff, 0x12, 0x34, 0x56, 0x87, 0x65, 0x43, 0x21], '7'); d.setFloat32(2, 1.2E+38); this.arrayEqual(u, [0xff, 0x12, 0x7e, 0xb4, 0x8e, 0x52, 0x43, 0x21], '8'); d.setFloat64(0, -1.2345678E+301); this.arrayEqual(u, [0xfe, 0x72, 0x6f, 0x51, 0x5f, 0x61, 0x77, 0xe5], '9'); u.set([0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87]); this.assertEquals(d.getUint8(0), 128, '10'); this.assertEquals(d.getInt8(1), -127, '11'); this.assertEquals(d.getUint16(2), 33411, '12'); this.assertEquals(d.getInt16(3), -31868, '13'); this.assertEquals(d.getUint32(4), 2223343239, '14'); this.assertEquals(d.getInt32(2), -2105310075, '15'); this.assertEquals(d.getFloat32(2), -1.932478247535851e-37, '16'); this.assertEquals(d.getFloat64(0), -3.116851295377095e-306, '17'); }); test('DataView endian', function () { var rawbuf = (new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7])).buffer; var d; d = new DataView(rawbuf); this.assertEquals(d.byteLength, 8, 'buffer'); this.assertEquals(d.byteOffset, 0, 'buffer'); this.raises(function () { d.getUint8(-2); }); // Chrome bug for index -, DOMException, 'bounds for buffer'? this.raises(function () { d.getUint8(8); }, 'bounds for buffer'); this.raises(function () { d.setUint8(-2, 0); }, 'bounds for buffer'); this.raises(function () { d.setUint8(8, 0); }, 'bounds for buffer'); d = new DataView(rawbuf, 2); this.assertEquals(d.byteLength, 6, 'buffer, byteOffset'); this.assertEquals(d.byteOffset, 2, 'buffer, byteOffset'); this.assertEquals(d.getUint8(5), 7, 'buffer, byteOffset'); this.raises(function () { d.getUint8(-2); }, 'bounds for buffer, byteOffset'); this.raises(function () { d.getUint8(6); }, 'bounds for buffer, byteOffset'); this.raises(function () { d.setUint8(-2, 0); }, 'bounds for buffer, byteOffset'); this.raises(function () { d.setUint8(6, 0); }, 'bounds for buffer, byteOffset'); d = new DataView(rawbuf, 8); this.assertEquals(d.byteLength, 0, 'buffer, byteOffset'); this.raises(function () { return new DataView(rawbuf, -1); }, 'invalid byteOffset'); this.raises(function () { return new DataView(rawbuf, 9); }, 'invalid byteOffset'); this.raises(function () { return new DataView(rawbuf, -1); }, 'invalid byteOffset'); d = new DataView(rawbuf, 2, 4); this.assertEquals(d.byteLength, 4, 'buffer, byteOffset, length'); this.assertEquals(d.byteOffset, 2, 'buffer, byteOffset, length'); this.assertEquals(d.getUint8(3), 5, 'buffer, byteOffset, length'); this.raises(function () { return d.getUint8(-2); }, 'bounds for buffer, byteOffset, length'); this.raises(function () { d.getUint8(4); }, 'bounds for buffer, byteOffset, length'); this.raises(function () { d.setUint8(-2, 0); }, 'bounds for buffer, byteOffset, length'); this.raises(function () { d.setUint8(4, 0); }, 'bounds for buffer, byteOffset, length'); this.raises(function () { return new DataView(rawbuf, 0, 9); }, 'invalid byteOffset+length'); this.raises(function () { return new DataView(rawbuf, 8, 1); }, 'invalid byteOffset+length'); this.raises(function () { return new DataView(rawbuf, 9, -1); }, 'invalid byteOffset+length'); }); test('Typed Array getters/setters', function () { // Only supported if Object.defineProperty() is fully supported on non-DOM objects. try { var o = {}; Object.defineProperty(o, 'x', { get: function() { return 1; } }); if (o.x !== 1) throw Error(); } catch (_) { ok(true); return; } var bytes = new Uint8Array([1, 2, 3, 4]), uint32s = new Uint32Array(bytes.buffer); this.assertEquals(bytes[1], 2); uint32s[0] = 0xffffffff; this.assertEquals(bytes[1], 0xff); }); test('Uint8ClampedArray', function () { this.assertEquals(Uint8ClampedArray.BYTES_PER_ELEMENT, 1, 'Uint8ClampedArray.BYTES_PER_ELEMENT'); var a = new Uint8ClampedArray([-Infinity, -Number.MAX_VALUE, -1, -Number.MIN_VALUE, -0, 0, Number.MIN_VALUE, 1, 1.1, 1.9, 255, 255.1, 255.9, 256, Number.MAX_VALUE, Infinity, NaN]); this.assertEquals(a.BYTES_PER_ELEMENT, 1); this.assertEquals(a.byteOffset, 0); this.assertEquals(a.byteLength, 17); this.arrayEqual(a, [0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0], "array test"); }); test('Regression Tests', function() { // Bug: https://github.com/inexorabletash/polyfill/issues/16 var minFloat32 = 1.401298464324817e-45; var truncated = new Float32Array([-minFloat32 / 2 - Math.pow(2, -202)]).get(0); this.assertEquals(truncated, -minFloat32, 'smallest 32 bit float should not truncate to zero'); });