| Index: test/mjsunit/harmony/typedarrays-reduce.js
|
| diff --git a/test/mjsunit/harmony/typedarrays-reduce.js b/test/mjsunit/harmony/typedarrays-reduce.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b13aaea31ef4ba055ad6f058b0afbdd41f858a86
|
| --- /dev/null
|
| +++ b/test/mjsunit/harmony/typedarrays-reduce.js
|
| @@ -0,0 +1,341 @@
|
| +// Copyright 2014 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Flags: --harmony-arrays --allow-natives-syntax
|
| +
|
| +var typedArrayConstructors = [
|
| + Uint8Array,
|
| + Int8Array,
|
| + Uint16Array,
|
| + Int16Array,
|
| + Uint32Array,
|
| + Int32Array,
|
| + Uint8ClampedArray,
|
| + Float32Array,
|
| + Float64Array];
|
| +
|
| +function CheckTypedArrayIsNeutered(array) {
|
| + assertEquals(0, array.byteLength);
|
| + assertEquals(0, array.byteOffset);
|
| + assertEquals(0, array.length);
|
| +}
|
| +
|
| +function CheckSuperficialFunctionFeatures(obj, funcname) {
|
| + assertEquals(1, obj[funcname].length);
|
| + var desc = Object.getOwnPropertyDescriptor(obj, funcname);
|
| + assertEquals(false, desc.configurable);
|
| + assertEquals(false, desc.enumerable);
|
| + assertEquals(false, desc.writable);
|
| +}
|
| +
|
| +// The following helpe functions are taken from mjsunit/array-reduce.js
|
| +
|
| +function clone(v) {
|
| + // Shallow-copies arrays, returns everything else verbatim.
|
| + if (v instanceof Array) {
|
| + // Shallow-copy an array.
|
| + var newArray = new Array(v.length);
|
| + for (var i in v) {
|
| + newArray[i] = v[i];
|
| + }
|
| + return newArray;
|
| + }
|
| + return v;
|
| +}
|
| +
|
| +// Creates a callback function for reduce/reduceRight that tests the number
|
| +// of arguments and otherwise behaves as "func", but which also
|
| +// records all calls in an array on the function (as arrays of arguments
|
| +// followed by result).
|
| +function makeRecorder(func, testName) {
|
| + var record = [];
|
| + var f = function recorder(a, b, i, s) {
|
| + assertEquals(4, arguments.length, testName + "(number of arguments: " + arguments.length + ")");
|
| + assertEquals("number", typeof(i), testName + "(index must be number)");
|
| + assertEquals(s[i], b, testName + "(current argument is at index)");
|
| + if (record.length > 0) {
|
| + var prevRecord = record[record.length - 1];
|
| + var prevResult = prevRecord[prevRecord.length - 1];
|
| + assertEquals(prevResult, a, testName + "(prev result -> current input)");
|
| + }
|
| + var args = [clone(a), clone(b), i, clone(s)];
|
| + var result = func.apply(this, arguments);
|
| + args.push(clone(result));
|
| + record.push(args);
|
| + return result;
|
| + };
|
| + f.record = record;
|
| + return f;
|
| +}
|
| +
|
| +function testReduce(type,
|
| + testName,
|
| + expectedResult,
|
| + expectedCalls,
|
| + array,
|
| + combine,
|
| + init)
|
| +{
|
| + var rec = makeRecorder(combine, testName);
|
| + var result;
|
| + var performsCall;
|
| + if (arguments.length > 6) {
|
| + result = array[type](rec, init);
|
| + } else {
|
| + result = array[type](rec);
|
| + }
|
| + var calls = rec.record;
|
| + assertEquals(expectedCalls.length, calls.length,
|
| + testName + " (number of calls)");
|
| + for (var i = 0; i < expectedCalls.length; i++) {
|
| + assertEquals(expectedCalls[i], calls[i],
|
| + testName + " (call " + (i + 1) + ")");
|
| + }
|
| + assertEquals(expectedResult, result, testName + " (result)");
|
| +}
|
| +
|
| +function sum(a, b) { return a + b; }
|
| +function prod(a, b) { return a * b; }
|
| +function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); }
|
| +function accumulate(acc, elem, i) { acc[i] = elem; return acc; }
|
| +
|
| +
|
| +function TestTypedArrayReduce(constructor) {
|
| + CheckSuperficialFunctionFeatures(constructor.prototype, "reduce");
|
| + CheckSuperficialFunctionFeatures(constructor.prototype, "reduceRight");
|
| +
|
| + var a = constructor.of(2, 4, 6);
|
| +
|
| + // .reduce()
|
| + testReduce("reduce", "SimpleReduceSum", 12,
|
| + [[0, 2, 0, a, 2],
|
| + [2, 4, 1, a, 6],
|
| + [6, 6, 2, a, 12]],
|
| + a, sum, 0);
|
| +
|
| + testReduce("reduce", "SimpleReduceProd", 48,
|
| + [[1, 2, 0, a, 2],
|
| + [2, 4, 1, a, 8],
|
| + [8, 6, 2, a, 48]],
|
| + a, prod, 1);
|
| +
|
| + testReduce("reduce", "SimpleReduceDec", 246,
|
| + [[0, 2, 0, a, 200],
|
| + [200, 4, 1, a, 240],
|
| + [240, 6, 2, a, 246]],
|
| + a, dec, 0);
|
| +
|
| + testReduce("reduce", "SimpleReduceAccumulate", [2,4,6],
|
| + [[[], 2, 0, a, [2]],
|
| + [[2], 4, 1, a, [2,4]],
|
| + [[2,4], 6, 2, a, [2,4,6]]],
|
| + a, accumulate, []);
|
| +
|
| + testReduce("reduce", "EmptyReduceSum", 0, [], [], sum, 0);
|
| + testReduce("reduce", "EmptyReduceProd", 1, [], [], prod, 1);
|
| + testReduce("reduce", "EmptyReduceDec", 0, [], [], dec, 0);
|
| + testReduce("reduce", "EmptyReduceAccumulate", [], [], [], accumulate, []);
|
| +
|
| + testReduce("reduce", "EmptyReduceSumNoInit", 0, [], [0], sum);
|
| + testReduce("reduce", "EmptyReduceProdNoInit", 1, [], [1], prod);
|
| + testReduce("reduce", "EmptyReduceDecNoInit", 0, [], [0], dec);
|
| + testReduce("reduce", "EmptyReduceAccumulateNoInit", [], [], [[]], accumulate);
|
| +
|
| + // .reduceRight()
|
| + testReduce("reduceRight", "SimpleReduceRightSum", 12,
|
| + [[0, 6, 2, a, 6],
|
| + [6, 4, 1, a, 10],
|
| + [10, 2, 0, a, 12]],
|
| + a, sum, 0);
|
| +
|
| + testReduce("reduceRight", "SimpleReduceRightProd", 48,
|
| + [[1, 6, 2, a, 6],
|
| + [6, 4, 1, a, 24],
|
| + [24, 2, 0, a, 48]],
|
| + a, prod, 1);
|
| +
|
| + testReduce("reduceRight", "SimpleReduceRightDec", 246,
|
| + [[0, 6, 2, a, 6],
|
| + [6, 4, 1, a, 46],
|
| + [46, 2, 0, a, 246]],
|
| + a, dec, 0);
|
| +
|
| + testReduce("reduceRight", "SimpleReduceRightAccumulate", [2, 4, 6],
|
| + [[[], 6, 2, a, [,,6]],
|
| + [[,,6], 4, 1, a, [,4,6]],
|
| + [[,4,6], 2, 0, a, [2,4,6]]],
|
| + a, accumulate, []);
|
| +
|
| +
|
| + testReduce("reduceRight", "EmptyReduceRightSum", 0, [], [], sum, 0);
|
| + testReduce("reduceRight", "EmptyReduceRightProd", 1, [], [], prod, 1);
|
| + testReduce("reduceRight", "EmptyReduceRightDec", 0, [], [], dec, 0);
|
| + testReduce("reduceRight", "EmptyReduceRightAccumulate", [],
|
| + [], [], accumulate, []);
|
| +
|
| + testReduce("reduceRight", "EmptyReduceRightSumNoInit", 0, [], [0], sum);
|
| + testReduce("reduceRight", "EmptyReduceRightProdNoInit", 1, [], [1], prod);
|
| + testReduce("reduceRight", "EmptyReduceRightDecNoInit", 0, [], [0], dec);
|
| + testReduce("reduceRight", "EmptyReduceRightAccumulateNoInit", [], [], [[]], accumulate);
|
| +
|
| +
|
| + // Test error conditions.
|
| + assertThrows(function () { a.reduce("not a function"); }, TypeError);
|
| + assertThrows(function () { a.reduceRight("not a function"); }, TypeError);
|
| +
|
| + var emptyArray = constructor.of();
|
| + assertThrows(function () { emptyArray.reduce(sum); }, TypeError);
|
| + assertThrows(function () { emptyArray.reduceRight(sum); }, TypeError);
|
| +
|
| + // Modify the original array inside .reduce().
|
| + count = 0;
|
| + assertEquals(2 + 4 + 6, a.reduce(function (prev, current, index, array) {
|
| + count++;
|
| + array[index] = current + 1;
|
| + return prev + current;
|
| + }, 0));
|
| + assertEquals(a.length, count);
|
| + assertArrayEquals([3, 5, 7], a);
|
| +
|
| + // Ditto for .reduceRight().
|
| + count = 0;
|
| + assertEquals(3 + 5 + 7, a.reduceRight(function (prev, current, index, array) {
|
| + count++;
|
| + array[index] = current - 2;
|
| + return prev + current;
|
| + }, 0));
|
| + assertEquals(a.length, count);
|
| + assertArrayEquals([1, 3, 5], a);
|
| +
|
| + // Throw before completing iteration, only the first element
|
| + // should be modified when throwing mid-way for .reduce().
|
| + count = 0;
|
| + var result;
|
| + a = constructor.of(2, 4, 6);
|
| + try {
|
| + result = a.reduce(function (prev, current, index, array) {
|
| + if (count > 0) throw "meh";
|
| + array[index] = current + 1;
|
| + count++;
|
| + return prev + current;
|
| + }, 0);
|
| + } catch (e) {
|
| + }
|
| + assertEquals(undefined, result);
|
| + assertEquals(1, count);
|
| + assertArrayEquals([3, 4, 6], a);
|
| +
|
| + // Ditto for .reduceRight().
|
| + count = 0;
|
| + try {
|
| + result = a.reduceRight(function (prev, current, index, array) {
|
| + if (count > 0) throw "meh";
|
| + array[index] = current + 1;
|
| + count++;
|
| + return prev + count;
|
| + }, 0);
|
| + } catch (e) {
|
| + }
|
| + assertEquals(undefined, result);
|
| + assertEquals(1, count);
|
| + assertArrayEquals([3, 4, 7], a);
|
| +
|
| + // Neutering the buffer backing the typed array mid-way should
|
| + // still make .reduce() finish, and the array should keep being
|
| + // empty after neutering it.
|
| + count = 0;
|
| + a.reduce(function (prev, current, index, array) {
|
| + if (count > 0) %ArrayBufferNeuter(array.buffer);
|
| + array[index] = current + 1;
|
| + count++;
|
| + return prev + current;
|
| + }, 0);
|
| + assertEquals(3, count);
|
| + CheckTypedArrayIsNeutered(a);
|
| + assertEquals(undefined, a[0]);
|
| +
|
| + // Ditto for .reduceRight()
|
| + count = 0;
|
| + a = constructor.of(2, 4, 6);
|
| + a.reduceRight(function (prev, current, index, array) {
|
| + if (count > 0) %ArrayBufferNeuter(array.buffer);
|
| + array[index] = current + 1;
|
| + count++;
|
| + return prev + count;
|
| + }, 0);
|
| + assertEquals(3, count);
|
| + CheckTypedArrayIsNeutered(a);
|
| + assertEquals(undefined, a[0]);
|
| +
|
| + // The method must work for typed arrays created from ArrayBuffer.
|
| + // The length of the ArrayBuffer is chosen so it is a multiple of
|
| + // all lengths of the typed array items.
|
| + a = new constructor(new ArrayBuffer(64));
|
| +
|
| + count = 0;
|
| + a.reduce(function (a, b) { return count++; }, 0);
|
| + assertEquals(a.length, count);
|
| +
|
| + count = 0;
|
| + a.reduceRight(function (a, b) { return count++; }, 0);
|
| + assertEquals(a.length, count);
|
| +
|
| + // Externalizing the array mid-way accessing the .buffer property
|
| + // should work for .reduce().
|
| + a = new constructor(2);
|
| + count = 0;
|
| + var buffer = undefined;
|
| + a.reduce(function (prev, current, index, array) {
|
| + if (count++ > 0)
|
| + buffer = array.buffer;
|
| + return 0;
|
| + }, 0);
|
| + assertEquals(2, count);
|
| + assertTrue(!!buffer);
|
| + assertEquals("ArrayBuffer", %_ClassOf(buffer));
|
| + assertSame(buffer, a.buffer);
|
| +
|
| + // Ditto for .reduceRight().
|
| + count = 0;
|
| + buffer = undefined;
|
| + a.reduceRight(function (prev, current, index, array) {
|
| + if (count++ > 0)
|
| + buffer = array.buffer;
|
| + return 0;
|
| + }, 0);
|
| + assertEquals(2, count);
|
| + assertTrue(!!buffer);
|
| + assertEquals("ArrayBuffer", %_ClassOf(buffer));
|
| + assertSame(buffer, a.buffer);
|
| +
|
| + // The .reduce() and .reduceRight() methods should not work
|
| + // when transplanted to objects that are not typed arrays.
|
| + assertThrows(function () { constructor.prototype.reduce.call([1, 2, 3], sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduce.call("abc", sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduce.call({}, sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduce.call(0, sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduceRight.call([1, 2, 3], sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduceRight.call("abc", sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduceRight.call({}, sum); }, TypeError);
|
| + assertThrows(function () { constructor.prototype.reduceRight.call(0, sum); }, TypeError);
|
| +
|
| + // Method must be useable on instances of other typed arrays.
|
| + for (var otherConstructor of typedArrayConstructors) {
|
| + a = otherConstructor.of(2, 4, 6, 8);
|
| + count = 0;
|
| + result = constructor.prototype.reduce.call(a,
|
| + function (prev, current) { count++; return prev + current; }, 0);
|
| + assertEquals(a.length, count);
|
| + assertEquals(20, result);
|
| + count = 0;
|
| + result = constructor.prototype.reduceRight.call(a,
|
| + function (prev, current) { count++; return prev + current; }, 0);
|
| + assertEquals(a.length, count);
|
| + assertEquals(20, result);
|
| + }
|
| +}
|
| +
|
| +for (var constructor of typedArrayConstructors) {
|
| + TestTypedArrayReduce(constructor);
|
| +}
|
|
|