Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit 2485bd80008482dee8f2e0657041e31a93474268 0 parents
@stephank authored
2  .gitignore
@@ -0,0 +1,2 @@
+/node_modules
+/build
99 binding.cc
@@ -0,0 +1,99 @@
+#include <string.h>
+#include <v8.h>
+#include <node.h>
+#include <node_buffer.h>
+
+using namespace v8;
+using namespace node;
+
+static Persistent<String> int8_symbol;
+static Persistent<String> uint8_symbol;
+static Persistent<String> int16_symbol;
+static Persistent<String> uint16_symbol;
+static Persistent<String> int32_symbol;
+static Persistent<String> uint32_symbol;
+static Persistent<String> float_symbol;
+static Persistent<String> double_symbol;
+static Persistent<String> pixel_symbol;
+
+Handle<Value> MakeFastBuffer(const Arguments& args) {
+ HandleScope scope;
+
+ if (!Buffer::HasInstance(args[1])) {
+ return ThrowException(Exception::TypeError(String::New(
+ "Argument must be a Buffer")));
+ }
+
+ Local<Object> fast_buffer = args[0]->ToObject();
+ char* data = Buffer::Data(args[1]->ToObject());
+ uint32_t offset = args[2]->Uint32Value();
+ Local<Value> type_arg = args[3];
+ uint32_t length = args[4]->Uint32Value();
+
+ enum ExternalArrayType type = kExternalUnsignedByteArray;
+ if (!type_arg->IsUndefined()) {
+ size_t type_size = 1;
+ if (type_arg->StrictEquals(int8_symbol)) {
+ type = kExternalByteArray;
+ type_size = 1;
+ }
+ else if (type_arg->StrictEquals(uint8_symbol)) {
+ type = kExternalUnsignedByteArray;
+ type_size = 1;
+ }
+ else if (type_arg->StrictEquals(int16_symbol)) {
+ type = kExternalShortArray;
+ type_size = 2;
+ }
+ else if (type_arg->StrictEquals(uint16_symbol)) {
+ type = kExternalUnsignedShortArray;
+ type_size = 2;
+ }
+ else if (type_arg->StrictEquals(int32_symbol)) {
+ type = kExternalIntArray;
+ type_size = 4;
+ }
+ else if (type_arg->StrictEquals(uint32_symbol)) {
+ type = kExternalUnsignedIntArray;
+ type_size = 4;
+ }
+ else if (type_arg->StrictEquals(float_symbol)) {
+ type = kExternalFloatArray;
+ type_size = 4;
+ }
+ else if (type_arg->StrictEquals(double_symbol)) {
+ type = kExternalDoubleArray;
+ type_size = 8;
+ }
+ else if (type_arg->StrictEquals(pixel_symbol)) {
+ type = kExternalPixelArray;
+ type_size = 1;
+ }
+
+ if ((offset & (type_size - 1)) != 0) {
+ return ThrowException(Exception::Error(
+ String::New("Byte offset is not aligned.")));
+ }
+ }
+
+ fast_buffer->SetIndexedPropertiesToExternalArrayData(
+ data + offset, type, length);
+
+ return Undefined();
+}
+
+void Initialize(Handle<Object> target) {
+ int8_symbol = NODE_PSYMBOL("int8");
+ uint8_symbol = NODE_PSYMBOL("uint8");
+ int16_symbol = NODE_PSYMBOL("int16");
+ uint16_symbol = NODE_PSYMBOL("uint16");
+ int32_symbol = NODE_PSYMBOL("int32");
+ uint32_symbol = NODE_PSYMBOL("uint32");
+ float_symbol = NODE_PSYMBOL("float");
+ double_symbol = NODE_PSYMBOL("double");
+ pixel_symbol = NODE_PSYMBOL("pixel");
+
+ NODE_SET_METHOD(target, "makeFastBuffer", MakeFastBuffer);
+}
+
+NODE_MODULE(binding, Initialize);
8 binding.gyp
@@ -0,0 +1,8 @@
+{
+ "targets": [
+ {
+ "target_name": "binding",
+ "sources": [ "binding.cc" ]
+ }
+ ]
+}
410 index.js
@@ -0,0 +1,410 @@
+var util = require('util');
+var binding = require('./build/Release/binding');
+
+
+// Coerce length to a number (possibly NaN), floor
+// in case it's fractional (e.g. 123.456) then do a
+// double negate to coerce a NaN to 0. Easy, right?
+function coerceInt(val) {
+ return ~~Math.floor(+val);
+}
+
+function positiveInt(val, name, def) {
+ if (val === undefined) {
+ if (def !== undefined) {
+ return def;
+ }
+ }
+ else if (typeof val === 'number') {
+ val = coerceInt(val);
+ if (val >= 0) {
+ return val;
+ }
+ }
+ throw new RangeError(name + " must be a positive integer");
+}
+
+// Convert an offset parameter into an absolute offset.
+function absOffset(val, end, def) {
+ if (val === undefined) {
+ return def === undefined ? end : def;
+ }
+
+ val = coerceInt(val);
+ if (val < 0) {
+ val = end + val;
+ }
+
+ if (val > end) {
+ val = end;
+ }
+ else if (val < 0) {
+ val = 0;
+ }
+
+ return val;
+}
+
+// Check if `val` is aligned to `align`.
+function checkAlignment(val, align) {
+ return (val & (align - 1)) === 0;
+}
+
+
+function ArrayBuffer(subject, begin, end) {
+ if (!(this instanceof ArrayBuffer)) {
+ throw new TypeError("Constructor cannot be called as a function.");
+ }
+
+ var length;
+
+ // Internal slice constructor
+ if (subject instanceof ArrayBuffer) {
+ length = this.byteLength = end - begin;
+ this.nodeBuffer = new Buffer(length);
+ subject.nodeBuffer.copy(this.nodeBuffer, 0, begin, end);
+ }
+
+ // Buffer constructor
+ else if (subject instanceof Buffer) {
+ this.nodeBuffer = subject;
+ this.byteLength = subject.length;
+ }
+
+ // Length constructor, per the spec
+ else {
+ length = this.byteLength = positiveInt(subject, "Length", 0);
+ this.nodeBuffer = new Buffer(length);
+ this.nodeBuffer.fill(0);
+ }
+}
+
+ArrayBuffer.prototype.slice = function(begin, end) {
+ begin = absOffset(begin, this.byteLength, 0);
+ end = absOffset(end, this.byteLength);
+
+ if (begin >= end) {
+ return new ArrayBuffer();
+ }
+ else {
+ return new ArrayBuffer(this, begin, end);
+ }
+};
+
+
+// Dummy, useful for instanceof checks
+function ArrayBufferView() {
+ throw new TypeError("ArrayBufferView cannot be constructed.");
+}
+
+// Common constructor part when creating an ArrayBufferView subclass from an
+// ArrayBuffer or Buffer. This function looks at the parameters and determines
+// if the constructor call was indeed of that kind, and sets attributes if so.
+function makeViewFromBuffer(view, args, typeSize) {
+ var buffer = args[0];
+ if (buffer instanceof Buffer) {
+ buffer = new ArrayBuffer(buffer);
+ }
+ else if (!(buffer instanceof ArrayBuffer)) {
+ return false;
+ }
+
+ var byteOffset = positiveInt(args[1], "Offset", 0);
+
+ var byteLength;
+ if (args[2] === undefined) {
+ byteLength = buffer.byteLength - byteOffset;
+ }
+ else {
+ byteLength = positiveInt(args[2], "Length") * typeSize;
+ }
+
+ if (byteOffset + byteLength > buffer.byteLength) {
+ throw new RangeError("Byte offset / length out of range.");
+ }
+
+ view.buffer = buffer;
+ view.byteOffset = byteOffset;
+ view.byteLength = byteLength;
+
+ var end = byteOffset + byteLength;
+ view.nodeBuffer = buffer.nodeBuffer.slice(byteOffset, end);
+
+ // SlowBuffer and Buffer pool allocations are already aligned.
+ // This is here to protect from badly aligned slicing.
+ if (!checkAlignment(view.nodeBuffer.offset, typeSize) ||
+ !checkAlignment(view.nodeBuffer.length, typeSize)) {
+ throw new RangeError("Byte offset / length is not aligned.");
+ }
+
+ return true;
+}
+
+
+// Uses `typeName` and `typeSize` attributes, defined by `makeTypedArray`
+function TypedArray(subject) {
+ if (!(this instanceof TypedArray)) {
+ throw new TypeError("Constructor cannot be called as a function.");
+ }
+ else if (!this.typeName) {
+ throw new TypeError("TypedArray cannot be constructed.");
+ }
+
+ var source = null;
+
+ // Is it a view over ArrayBuffer or Buffer?
+ if (!makeViewFromBuffer(this, arguments, this.typeSize)) {
+ // Nope, transparently create a new ArrayBuffer
+ this.byteOffset = 0;
+
+ // Find the length, and also allow no arguments at all
+ if (subject === undefined || typeof subject === 'number') {
+ this.byteLength = positiveInt(subject, "Length", 0) * this.typeSize;
+ }
+ else if (subject && typeof subject === 'object') {
+ // Assume object is a TypedArray or Array.
+ this.byteLength = subject.length * this.typeSize;
+ source = subject; // Copy contents later
+ }
+ else {
+ throw new TypeError("Expected a TypedArray, array or number");
+ }
+
+ this.buffer = new ArrayBuffer(this.byteLength);
+ this.nodeBuffer = this.buffer.nodeBuffer;
+ }
+
+ this.length = this.byteLength / this.typeSize;
+ binding.makeFastBuffer(this, this.nodeBuffer.parent,
+ this.nodeBuffer.offset, this.typeName, this.length);
+
+ if (source) {
+ this.set(source);
+ }
+}
+util.inherits(TypedArray, ArrayBufferView);
+
+TypedArray.prototype.set = function(source, offset) {
+ var length = source.length;
+ offset = positiveInt(offset, "Offset", 0);
+
+ if (offset + length > this.length) {
+ throw new RangeError("Offset / length out of range.");
+ }
+
+ // FIXME: Handle different kinds of TypedArrays, backed by the same
+ // ArrayBuffer? Even Chrome seems to handle this incorrectly.
+ if (source instanceof this.constructor) {
+ source.nodeBuffer.copy(this.nodeBuffer, offset * this.typeSize);
+ }
+ else {
+ // Assume object is an Array.
+ for (var i = 0; i < length; i++) {
+ this[offset + i] = source[i];
+ }
+ }
+};
+
+TypedArray.prototype.subarray = function(begin, end) {
+ begin = absOffset(begin, this.length, 0);
+ end = absOffset(end, this.length);
+
+ if (begin >= end) {
+ return new this.constructor();
+ }
+ else {
+ var byteOffset = this.byteOffset + begin * this.typeSize;
+ var length = end - begin;
+ return new this.constructor(this.buffer, byteOffset, length);
+ }
+};
+
+
+function makeTypedArray(ctor, name, size) {
+ util.inherits(ctor, TypedArray);
+
+ var proto = ctor.prototype;
+
+ proto.typeName = name;
+ proto.typeSize = size;
+
+ proto.BYTES_PER_ELEMENT = ctor.BYTES_PER_ELEMENT = size;
+}
+
+function Int8Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Int8Array, 'int8', 1);
+
+function Uint8Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Uint8Array, 'uint8', 1);
+
+function Uint8ClampedArray() { TypedArray.apply(this, arguments); }
+makeTypedArray(Uint8ClampedArray, 'pixel', 1);
+
+function Int16Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Int16Array, 'int16', 2);
+
+function Uint16Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Uint16Array, 'uint16', 2);
+
+function Int32Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Int32Array, 'int32', 4);
+
+function Uint32Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Uint32Array, 'uint32', 4);
+
+function Float32Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Float32Array, 'float', 4);
+
+function Float64Array() { TypedArray.apply(this, arguments); }
+makeTypedArray(Float64Array, 'double', 8);
+
+
+function DataView(buffer, offset, length) {
+ if (!(this instanceof DataView)) {
+ throw new TypeError("Constructor cannot be called as a function.");
+ }
+
+ if (!makeViewFromBuffer(this, arguments, 1)) {
+ throw new TypeError("Object must be an ArrayBuffer or Buffer");
+ }
+}
+util.inherits(DataView, ArrayBufferView);
+
+function wrapGetter(size, fn) {
+ return function(byteOffset, littleEndian) {
+ byteOffset = positiveInt(byteOffset, "Offset");
+ if (byteOffset + size > this.byteLength) {
+ throw new RangeError("Offset out of range.");
+ }
+
+ return fn.call(this, byteOffset, littleEndian);
+ };
+}
+
+DataView.prototype.getInt8 = wrapGetter(1, function(byteOffset) {
+ return this.nodeBuffer.readInt8(byteOffset);
+});
+
+DataView.prototype.getUint8 = wrapGetter(1, function(byteOffset) {
+ return this.nodeBuffer.readUInt8(byteOffset);
+});
+
+DataView.prototype.getInt16 = wrapGetter(2, function(byteOffset, littleEndian) {
+ if (littleEndian)
+ return this.nodeBuffer.readInt16LE(byteOffset);
+ else
+ return this.nodeBuffer.readInt16BE(byteOffset);
+});
+
+DataView.prototype.getUint16 = wrapGetter(2, function(byteOffset, littleEndian) {
+ if (littleEndian)
+ return this.nodeBuffer.readUInt16LE(byteOffset);
+ else
+ return this.nodeBuffer.readUInt16BE(byteOffset);
+});
+
+DataView.prototype.getInt32 = wrapGetter(4, function(byteOffset, littleEndian) {
+ if (littleEndian)
+ return this.nodeBuffer.readInt32LE(byteOffset);
+ else
+ return this.nodeBuffer.readInt32BE(byteOffset);
+});
+
+DataView.prototype.getUint32 = wrapGetter(4, function(byteOffset, littleEndian) {
+ if (littleEndian)
+ return this.nodeBuffer.readUInt32LE(byteOffset);
+ else
+ return this.nodeBuffer.readUInt32BE(byteOffset);
+});
+
+DataView.prototype.getFloat32 = wrapGetter(4, function(byteOffset, littleEndian) {
+ if (littleEndian)
+ return this.nodeBuffer.readFloatLE(byteOffset);
+ else
+ return this.nodeBuffer.readFloatBE(byteOffset);
+});
+
+DataView.prototype.getFloat64 = wrapGetter(8, function(byteOffset, littleEndian) {
+ if (littleEndian)
+ return this.nodeBuffer.readDoubleLE(byteOffset);
+ else
+ return this.nodeBuffer.readDoubleBE(byteOffset);
+});
+
+function wrapSetter(size, fn) {
+ return function(byteOffset, value, littleEndian) {
+ byteOffset = positiveInt(byteOffset, "Offset");
+ if (byteOffset + size > this.byteLength) {
+ throw new RangeError("Offset out of range.");
+ }
+
+ fn.call(this, byteOffset, value, littleEndian);
+ };
+}
+
+DataView.prototype.setInt8 = wrapSetter(1, function(byteOffset, value) {
+ this.nodeBuffer.writeInt8(value, byteOffset);
+});
+
+DataView.prototype.setUint8 = wrapSetter(1, function(byteOffset, value) {
+ this.nodeBuffer.writeUInt8(value, byteOffset);
+});
+
+DataView.prototype.setInt16 = wrapSetter(2, function(byteOffset, value, littleEndian) {
+ if (littleEndian)
+ this.nodeBuffer.writeInt16LE(value, byteOffset);
+ else
+ this.nodeBuffer.writeInt16BE(value, byteOffset);
+});
+
+DataView.prototype.setUint16 = wrapSetter(2, function(byteOffset, value, littleEndian) {
+ if (littleEndian)
+ this.nodeBuffer.writeUInt16LE(value, byteOffset);
+ else
+ this.nodeBuffer.writeUInt16BE(value, byteOffset);
+});
+
+DataView.prototype.setInt32 = wrapSetter(4, function(byteOffset, value, littleEndian) {
+ if (littleEndian)
+ this.nodeBuffer.writeInt32LE(value, byteOffset);
+ else
+ this.nodeBuffer.writeInt32BE(value, byteOffset);
+});
+
+DataView.prototype.setUint32 = wrapSetter(4, function(byteOffset, value, littleEndian) {
+ if (littleEndian)
+ this.nodeBuffer.writeUInt32LE(value, byteOffset);
+ else
+ this.nodeBuffer.writeUInt32BE(value, byteOffset);
+});
+
+DataView.prototype.setFloat32 = wrapSetter(4, function(byteOffset, value, littleEndian) {
+ if (littleEndian)
+ this.nodeBuffer.writeFloatLE(value, byteOffset, true);
+ else
+ this.nodeBuffer.writeFloatBE(value, byteOffset, true);
+});
+
+DataView.prototype.setFloat64 = wrapSetter(8, function(byteOffset, value, littleEndian) {
+ if (littleEndian)
+ this.nodeBuffer.writeDoubleLE(value, byteOffset, true);
+ else
+ this.nodeBuffer.writeDoubleBE(value, byteOffset, true);
+});
+
+
+module.exports = {
+ ArrayBuffer: ArrayBuffer,
+ ArrayBufferView: ArrayBufferView,
+ TypedArray: TypedArray,
+ Int8Array: Int8Array,
+ Uint8Array: Uint8Array,
+ Uint8ClampedArray: Uint8ClampedArray,
+ Int16Array: Int16Array,
+ Uint16Array: Uint16Array,
+ Int32Array: Int32Array,
+ Uint32Array: Uint32Array,
+ Float32Array: Float32Array,
+ Float64Array: Float64Array,
+ DataView: DataView
+};
26 package.json
@@ -0,0 +1,26 @@
+{
+ "name": "arrays.js",
+ "version": "0.0.0",
+ "description": "Pure-JS implementation of Typed Arrays",
+
+ "homepage": "http://github.com/stephank/node-arrays",
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/stephank/node-arrays.git"
+ },
+ "author": {
+ "name": "Stéphan Kochen",
+ "email": "stephan@kochen.nl",
+ "url": "http://stephan.kochen.nl/"
+ },
+
+ "engines": {
+ "node": ">=0.7.7"
+ },
+
+ "scripts": {
+ "test": "node ./test/harness.js"
+ },
+
+ "main": "./index.js"
+}
1,022 test/array-unit-tests.js
@@ -0,0 +1,1022 @@
+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 byteLength;
+var subBuffer;
+function testSlice() {
+ function test(subBuf, starts, size) {
+ byteLength = size;
+ subBuffer = eval(subBuf);
+ var 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');
+ var 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);
+ }
+}
+
+//
+// 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];
+ if (type === Uint8ClampedArray) {
+ expectedResults = [1, 11];
+ } else {
+ expectedResults = [0, 10];
+ }
+ } 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);
+ }
+}
+
+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 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);
+ testFailed("Construction of " + name + " with null buffer should throw exception");
+ } catch (e) {
+ testPassed("Construction of " + name + " with null buffer threw exception");
+ }
+ try {
+ array = new type(null, 0, 0);
+ testFailed("Construction of " + name + " with (null buffer, 0) should throw exception");
+ } catch (e) {
+ testPassed("Construction of " + name + " with (null buffer, 0) threw exception");
+ }
+ try {
+ array = new type(null, 0, 0);
+ testFailed("Construction of " + name + " with (null buffer, 0, 0) should throw exception");
+ } catch (e) {
+ testPassed("Construction of " + name + " with (null buffer, 0, 0) threw exception");
+ }
+}
+
+function shouldThrowIndexSizeErr(func, text) {
+ var errorText = text + " should throw an exception";
+ try {
+ func();
+ testFailed(errorText);
+ } catch (e) {
+ testPassed(text + " threw an exception");
+ }
+}
+
+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 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 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();
+
+ // The "name" attribute is a concession to browsers which don't
+ // implement the "name" property on function objects
+ var testCases =
+ [ {name: "Float32Array",
+ unsigned: false,
+ integral: false,
+ elementSizeInBytes: 4,
+ testValues: [ -500.5, 500.5 ],
+ expectedValues: [ -500.5, 500.5 ]
+ },
+ {name: "Float64Array",
+ unsigned: false,
+ integral: false,
+ elementSizeInBytes: 8,
+ testValues: [ -500.5, 500.5 ],
+ expectedValues: [ -500.5, 500.5 ]
+ },
+ {name: "Int8Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ -128, 127, -129, 128 ],
+ expectedValues: [ -128, 127, 127, -128 ]
+ },
+ {name: "Int16Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 2,
+ testValues: [ -32768, 32767, -32769, 32768 ],
+ expectedValues: [ -32768, 32767, 32767, -32768 ]
+ },
+ {name: "Int32Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 4,
+ testValues: [ -2147483648, 2147483647, -2147483649, 2147483648 ],
+ expectedValues: [ -2147483648, 2147483647, 2147483647, -2147483648 ]
+ },
+ {name: "Uint8Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ 0, 255, -1, 256 ],
+ expectedValues: [ 0, 255, 255, 0 ]
+ },
+ {name: "Uint8ClampedArray",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ 0, 255, -1, 256 ],
+ expectedValues: [ 0, 255, 0, 255 ]
+ },
+ {name: "Uint16Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 2,
+ testValues: [ 0, 65535, -1, 65536 ],
+ expectedValues: [ 0, 65535, 65535, 0 ]
+ },
+ {name: "Uint32Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 4,
+ testValues: [ 0, 4294967295, -1, 4294967296 ],
+ expectedValues: [ 0, 4294967295, 4294967295, 0 ]
+ }
+ ];
+ for (var i = 0; i < testCases.length; i++) {
+ var testCase = testCases[i];
+ running(testCase.name);
+ if (!(testCase.name in arraysjs)) {
+ fail("does not exist");
+ continue;
+ }
+ var type = arraysjs[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);
+ negativeTestSubarray(type, name);
+ testSetBoundaryConditions(type,
+ name,
+ testCase.testValues,
+ testCase.expectedValues);
+ testConstructionBoundaryConditions(type,
+ name,
+ testCase.testValues,
+ testCase.expectedValues);
+ testConstructionWithNullBuffer(type, name);
+ testConstructionWithOutOfRangeValues(type, name);
+ testConstructionWithNegativeOutOfRangeValues(type, name);
+ testConstructionWithUnalignedOffset(type, name, testCase.elementSizeInBytes);
+ testConstructionWithUnalignedLength(type, name, testCase.elementSizeInBytes);
+ testConstructionOfHugeArray(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();
+successfullyParsed = true;
342 test/data-view-test.js
@@ -0,0 +1,342 @@
+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 arayBuffer = 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 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()
+{
+ arayBuffer = (new Uint8Array([1, 2])).buffer;
+
+ debug("");
+ debug("Test for constructor not called as a function");
+ var expr = "DataView(new ArrayBuffer)";
+ // Use try/catch instead of calling shouldThrow to avoid different exception message being reported from different platform.
+ try {
+ eval(expr);
+ testFailed(expr + " does not throw exception");
+ } catch (e) {
+ testPassed(expr + " threw exception");
+ }
+
+ debug("");
+ debug("Test for constructor taking 1 argument");
+ shouldBeDefined("view = new DataView(arayBuffer)");
+ shouldBe("view.byteOffset", "0");
+ shouldBe("view.byteLength", "2");
+
+ debug("");
+ debug("Test for constructor taking 2 arguments");
+ shouldBeDefined("view = new DataView(arayBuffer, 1)");
+ shouldBe("view.byteOffset", "1");
+ shouldBe("view.byteLength", "1");
+
+ debug("");
+ debug("Test for constructor taking 3 arguments");
+ shouldBeDefined("view = new DataView(arayBuffer, 0, 1)");
+ shouldBe("view.byteOffset", "0");
+ shouldBe("view.byteLength", "1");
+
+ debug("");
+ debug("Test for constructor throwing exception");
+ shouldThrow("view = new DataView(arayBuffer, 0, 3)");
+ shouldThrow("view = new DataView(arayBuffer, 1, 2)");
+ shouldThrow("view = new DataView(arayBuffer, 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);
+
+ debug("");
+ debug("Test for wrong arguments passed to get methods");
+ view = new DataView((new Uint8Array([1, 2])).buffer);
+ shouldThrow("view.getInt8()");
+ shouldThrow("view.getUint8()");
+ shouldThrow("view.getInt16()");
+ shouldThrow("view.getUint16()");
+ shouldThrow("view.getInt32()");
+ shouldThrow("view.getUint32()");
+ shouldThrow("view.getFloat32()");
+ shouldThrow("view.getFloat64()");
+}
+
+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);
+
+ debug("");
+ debug("Test for wrong arguments passed to set methods");
+ view = new DataView((new Uint8Array([1, 2])).buffer);
+ shouldThrow("view.setInt8()");
+ shouldThrow("view.setUint8()");
+ shouldThrow("view.setInt16()");
+ shouldThrow("view.setUint16()");
+ shouldThrow("view.setInt32()");
+ shouldThrow("view.setUint32()");
+ shouldThrow("view.setFloat32()");
+ shouldThrow("view.setFloat64()");
+ shouldThrow("view.setInt8(1)");
+ shouldThrow("view.setUint8(1)");
+ shouldThrow("view.setInt16(1)");
+ shouldThrow("view.setUint16(1)");
+ shouldThrow("view.setInt32(1)");
+ shouldThrow("view.setUint32(1)");
+ shouldThrow("view.setFloat32(1)");
+ shouldThrow("view.setFloat64(1)");
+}
+
+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();
+runIndexingTests();
+successfullyParsed = true;
332 test/harness.js
@@ -0,0 +1,332 @@
+var fs = require('fs'),
+ path = require('path'),
+ arraysjs = require('../');
+
+var ArrayBuffer = arraysjs.ArrayBuffer,
+ ArrayBufferView = arraysjs.ArrayBufferView,
+ TypedArray = arraysjs.TypedArray,
+ Int8Array = arraysjs.Int8Array,
+ Uint8Array = arraysjs.Uint8Array,
+ Uint8ClampedArray = arraysjs.Uint8ClampedArray,
+ Int16Array = arraysjs.Int16Array,
+ Uint16Array = arraysjs.Uint16Array,
+ Int32Array = arraysjs.Int32Array,
+ Uint32Array = arraysjs.Uint32Array,
+ Float32Array = arraysjs.Float32Array,
+ Float64Array = arraysjs.Float64Array,
+ DataView = arraysjs.DataView;
+
+
+var exitStatus = 0;
+
+function description(msg)
+{
+ process.stdout.write("\n### " + msg + "\n\n");
+}
+
+function testFailed(msg)
+{
+ exitStatus = 1;
+ process.stdout.write("\nFAIL: " + msg + "\n");
+}
+
+function testPassed(msg)
+{
+ process.stdout.write(".");
+}
+
+function debug(msg) {}
+
+
+function areArraysEqual(_a, _b)
+{
+ try {
+ if (_a.length !== _b.length)
+ return false;
+ for (var i = 0; i < _a.length; i++)
+ if (_a[i] !== _b[i])
+ return false;
+ } catch (ex) {
+ return false;
+ }
+ return true;
+}
+
+function isMinusZero(n)
+{
+ // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
+ // -Infinity instead of Infinity
+ return n === 0 && 1/n < 0;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+ if (_expected === 0)
+ return _actual === _expected && (1/_actual) === (1/_expected);
+ if (_actual === _expected)
+ return true;
+ if (typeof(_expected) == "number" && isNaN(_expected))
+ return typeof(_actual) == "number" && isNaN(_actual);
+ if (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([]))
+ return areArraysEqual(_actual, _expected);
+ return false;
+}
+
+function stringify(v)
+{
+ if (v === 0 && 1/v < 0)
+ return "-0";
+ else return "" + v;
+}
+
+function evalAndLog(_a)
+{
+ if (typeof _a != "string")
+ debug("WARN: tryAndLog() expects a string argument");
+
+ // Log first in case things go horribly wrong or this causes a sync event.
+ debug(_a);
+
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ testFailed(_a + " threw exception " + e);
+ }
+ return _av;
+}
+
+function shouldBe(_a, _b, quiet)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBe() expects string arguments");
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
+ else if (isResultCorrect(_av, _bv)) {
+ if (!quiet) {
+ testPassed(_a + " is " + _b);
+ }
+ } else if (typeof(_av) == typeof(_bv))
+ testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
+ else
+ testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+function shouldNotBe(_a, _b, quiet)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldNotBe() expects string arguments");
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should not be " + _bv + ". Threw exception " + exception);
+ else if (!isResultCorrect(_av, _bv)) {
+ if (!quiet) {
+ testPassed(_a + " is not " + _b);
+ }
+ } else
+ testFailed(_a + " should not be " + _bv + ".");
+}
+
+function shouldBeTrue(_a) { shouldBe(_a, "true"); }
+function shouldBeFalse(_a) { shouldBe(_a, "false"); }
+function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
+function shouldBeNull(_a) { shouldBe(_a, "null"); }
+
+function shouldBeEqualToString(a, b)
+{
+ var unevaledString = '"' + b.replace(/"/g, "\"") + '"';
+ shouldBe(a, unevaledString);
+}
+
+function shouldEvaluateTo(actual, expected) {
+ // A general-purpose comparator. 'actual' should be a string to be
+ // evaluated, as for shouldBe(). 'expected' may be any type and will be
+ // used without being eval'ed.
+ if (expected == null) {
+ // Do this before the object test, since null is of type 'object'.
+ shouldBeNull(actual);
+ } else if (typeof expected == "undefined") {
+ shouldBeUndefined(actual);
+ } else if (typeof expected == "function") {
+ // All this fuss is to avoid the string-arg warning from shouldBe().
+ try {
+ actualValue = eval(actual);
+ } catch (e) {
+ testFailed("Evaluating " + actual + ": Threw exception " + e);
+ return;
+ }
+ shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
+ "'" + expected.toString().replace(/\n/g, "") + "'");
+ } else if (typeof expected == "object") {
+ shouldBeTrue(actual + " == '" + expected + "'");
+ } else if (typeof expected == "string") {
+ shouldBe(actual, expected);
+ } else if (typeof expected == "boolean") {
+ shouldBe("typeof " + actual, "'boolean'");
+ if (expected)
+ shouldBeTrue(actual);
+ else
+ shouldBeFalse(actual);
+ } else if (typeof expected == "number") {
+ shouldBe(actual, stringify(expected));
+ } else {
+ debug(expected + " is unknown type " + typeof expected);
+ shouldBeTrue(actual, "'" +expected.toString() + "'");
+ }
+}
+
+function shouldBeNonZero(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be non-zero. Threw exception " + exception);
+ else if (_av != 0)
+ testPassed(_a + " is non-zero.");
+ else
+ testFailed(_a + " should be non-zero. Was " + _av);
+}
+
+function shouldBeNonNull(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be non-null. Threw exception " + exception);
+ else if (_av != null)
+ testPassed(_a + " is non-null.");
+ else
+ testFailed(_a + " should be non-null. Was " + _av);
+}
+
+function shouldBeUndefined(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be undefined. Threw exception " + exception);
+ else if (typeof _av == "undefined")
+ testPassed(_a + " is undefined.");
+ else
+ testFailed(_a + " should be undefined. Was " + _av);
+}
+
+function shouldBeDefined(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be defined. Threw exception " + exception);
+ else if (_av !== undefined)
+ testPassed(_a + " is defined.");
+ else
+ testFailed(_a + " should be defined. Was " + _av);
+}
+
+function shouldBeGreaterThanOrEqual(_a, _b) {
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
+
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be >= " + _b + ". Threw exception " + exception);
+ else if (typeof _av == "undefined" || _av < _bv)
+ testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+ else
+ testPassed(_a + " is >= " + _b);
+}
+
+function shouldThrow(_a, _e)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ var _ev;
+ if (_e)
+ _ev = eval(_e);
+
+ if (exception) {
+ if (typeof _e == "undefined" || exception == _ev)
+ testPassed(_a + " threw exception " + exception + ".");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
+ } else if (typeof _av == "undefined")
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+}
+
+function assertMsg(assertion, msg) {
+ if (assertion) {
+ testPassed(msg);
+ } else {
+ testFailed(msg);
+ }
+}
+
+
+function readTestScript(filename) {
+ return fs.readFileSync(path.join(__dirname, filename), 'utf-8');
+}
+
+eval(readTestScript('array-unit-tests.js'));
+process.stdout.write('\n\n');
+
+eval(readTestScript('data-view-test.js'));
+process.stdout.write('\n\n');
+
+process.exit(exitStatus);
Please sign in to comment.
Something went wrong with that request. Please try again.