Home | History | Annotate | Download | only in es6
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 var typedArrayConstructors = [
      6   Uint8Array,
      7   Int8Array,
      8   Uint16Array,
      9   Int16Array,
     10   Uint32Array,
     11   Int32Array,
     12   Uint8ClampedArray,
     13   Float32Array,
     14   Float64Array
     15 ];
     16 
     17 function clone(v) {
     18   // Shallow-copies arrays, returns everything else verbatim.
     19   if (v instanceof Array) {
     20     // Shallow-copy an array.
     21     var newArray = new Array(v.length);
     22     for (var i in v) {
     23       newArray[i] = v[i];
     24     }
     25     return newArray;
     26   }
     27   return v;
     28 }
     29 
     30 
     31 // Creates a callback function for reduce/reduceRight that tests the number
     32 // of arguments and otherwise behaves as "func", but which also
     33 // records all calls in an array on the function (as arrays of arguments
     34 // followed by result).
     35 function makeRecorder(func, testName) {
     36   var record = [];
     37   var f = function recorder(a, b, i, s) {
     38     assertEquals(4, arguments.length,
     39                  testName + "(number of arguments: " + arguments.length + ")");
     40     assertEquals("number", typeof(i), testName + "(index must be number)");
     41     assertEquals(s[i], b, testName + "(current argument is at index)");
     42     if (record.length > 0) {
     43       var prevRecord = record[record.length - 1];
     44       var prevResult = prevRecord[prevRecord.length - 1];
     45       assertEquals(prevResult, a,
     46                    testName + "(prev result -> current input)");
     47     }
     48     var args = [clone(a), clone(b), i, clone(s)];
     49     var result = func.apply(this, arguments);
     50     args.push(clone(result));
     51     record.push(args);
     52     return result;
     53   };
     54   f.record = record;
     55   return f;
     56 }
     57 
     58 
     59 function testReduce(type,
     60                     testName,
     61                     expectedResult,
     62                     expectedCalls,
     63                     array,
     64                     combine,
     65                     init) {
     66   var rec = makeRecorder(combine);
     67   var result;
     68   var performsCall;
     69   if (arguments.length > 6) {
     70     result = array[type](rec, init);
     71   } else {
     72     result = array[type](rec);
     73   }
     74   var calls = rec.record;
     75   assertEquals(expectedCalls.length, calls.length,
     76                testName + " (number of calls)");
     77   for (var i = 0; i < expectedCalls.length; i++) {
     78     assertEquals(expectedCalls[i], calls[i],
     79                  testName + " (call " + (i + 1) + ")");
     80   }
     81   assertEquals(expectedResult, result, testName + " (result)");
     82 }
     83 
     84 
     85 function sum(a, b) { return a + b; }
     86 function prod(a, b) { return a * b; }
     87 function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); }
     88 function accumulate(acc, elem, i) { acc[i] = elem; return acc; }
     89 
     90 for (var constructor of typedArrayConstructors) {
     91   // ---- Test Reduce[Left]
     92 
     93   var simpleArray = new constructor([2,4,6])
     94 
     95   testReduce("reduce", "SimpleReduceSum", 12,
     96              [[0, 2, 0, simpleArray, 2],
     97               [2, 4, 1, simpleArray, 6],
     98               [6, 6, 2, simpleArray, 12]],
     99              simpleArray, sum, 0);
    100 
    101   testReduce("reduce", "SimpleReduceProd", 48,
    102              [[1, 2, 0, simpleArray, 2],
    103               [2, 4, 1, simpleArray, 8],
    104               [8, 6, 2, simpleArray, 48]],
    105              simpleArray, prod, 1);
    106 
    107   testReduce("reduce", "SimpleReduceDec", 246,
    108              [[0, 2, 0, simpleArray, 200],
    109               [200, 4, 1, simpleArray, 240],
    110               [240, 6, 2, simpleArray, 246]],
    111              simpleArray, dec, 0);
    112 
    113   testReduce("reduce", "SimpleReduceAccumulate", [2, 4, 6],
    114              [[[], 2, 0, simpleArray, [2]],
    115               [[2], 4, 1, simpleArray, [2, 4]],
    116               [[2,4], 6, 2, simpleArray, [2, 4, 6]]],
    117              simpleArray, accumulate, []);
    118 
    119 
    120   testReduce("reduce", "EmptyReduceSum", 0, [], new constructor([]), sum, 0);
    121   testReduce("reduce", "EmptyReduceProd", 1, [], new constructor([]), prod, 1);
    122   testReduce("reduce", "EmptyReduceDec", 0, [], new constructor([]), dec, 0);
    123   testReduce("reduce", "EmptyReduceAccumulate", [], [], new constructor([]), accumulate, []);
    124 
    125   testReduce("reduce", "EmptyReduceSumNoInit", 0, [], new constructor([0]), sum);
    126   testReduce("reduce", "EmptyReduceProdNoInit", 1, [], new constructor([1]), prod);
    127   testReduce("reduce", "EmptyReduceDecNoInit", 0, [], new constructor([0]), dec);
    128 
    129   // ---- Test ReduceRight
    130 
    131   testReduce("reduceRight", "SimpleReduceRightSum", 12,
    132              [[0, 6, 2, simpleArray, 6],
    133               [6, 4, 1, simpleArray, 10],
    134               [10, 2, 0, simpleArray, 12]],
    135              simpleArray, sum, 0);
    136 
    137   testReduce("reduceRight", "SimpleReduceRightProd", 48,
    138              [[1, 6, 2, simpleArray, 6],
    139               [6, 4, 1, simpleArray, 24],
    140               [24, 2, 0, simpleArray, 48]],
    141              simpleArray, prod, 1);
    142 
    143   testReduce("reduceRight", "SimpleReduceRightDec", 246,
    144              [[0, 6, 2, simpleArray, 6],
    145               [6, 4, 1, simpleArray, 46],
    146               [46, 2, 0, simpleArray, 246]],
    147              simpleArray, dec, 0);
    148 
    149 
    150   testReduce("reduceRight", "EmptyReduceRightSum", 0, [], new constructor([]), sum, 0);
    151   testReduce("reduceRight", "EmptyReduceRightProd", 1, [], new constructor([]), prod, 1);
    152   testReduce("reduceRight", "EmptyReduceRightDec", 0, [], new constructor([]), dec, 0);
    153   testReduce("reduceRight", "EmptyReduceRightAccumulate", [],
    154              [], new constructor([]), accumulate, []);
    155 
    156   testReduce("reduceRight", "EmptyReduceRightSumNoInit", 0, [], new constructor([0]), sum);
    157   testReduce("reduceRight", "EmptyReduceRightProdNoInit", 1, [], new constructor([1]), prod);
    158   testReduce("reduceRight", "EmptyReduceRightDecNoInit", 0, [], new constructor([0]), dec);
    159 
    160   // Ignore non-array properties:
    161 
    162   var arrayPlus = new constructor([1,2,3]);
    163   arrayPlus[-1] = NaN;
    164   arrayPlus["00"] = NaN;
    165   arrayPlus["02"] = NaN;
    166   arrayPlus["-0"] = NaN;
    167   arrayPlus.x = NaN;
    168 
    169   testReduce("reduce", "ArrayWithNonElementPropertiesReduce", 6,
    170              [[0, 1, 0, arrayPlus, 1],
    171               [1, 2, 1, arrayPlus, 3],
    172               [3, 3, 2, arrayPlus, 6],
    173              ], arrayPlus, sum, 0);
    174 
    175   testReduce("reduceRight", "ArrayWithNonElementPropertiesReduceRight", 6,
    176              [[0, 3, 2, arrayPlus, 3],
    177               [3, 2, 1, arrayPlus, 5],
    178               [5, 1, 0, arrayPlus, 6],
    179              ], arrayPlus, sum, 0);
    180 
    181 
    182   // Test error conditions:
    183 
    184   var exception = false;
    185   try {
    186     new constructor([1]).reduce("not a function");
    187   } catch (e) {
    188     exception = true;
    189     assertTrue(e instanceof TypeError,
    190                "reduce callback not a function not throwing TypeError");
    191     assertTrue(e.message.indexOf(" is not a function") >= 0,
    192                "reduce non function TypeError type");
    193   }
    194   assertTrue(exception);
    195 
    196   exception = false;
    197   try {
    198     new constructor([1]).reduceRight("not a function");
    199   } catch (e) {
    200     exception = true;
    201     assertTrue(e instanceof TypeError,
    202                "reduceRight callback not a function not throwing TypeError");
    203     assertTrue(e.message.indexOf(" is not a function") >= 0,
    204                "reduceRight non function TypeError type");
    205   }
    206   assertTrue(exception);
    207 
    208   exception = false;
    209   try {
    210     new constructor([]).reduce(sum);
    211   } catch (e) {
    212     exception = true;
    213     assertTrue(e instanceof TypeError,
    214                "reduce no initial value not throwing TypeError");
    215     assertEquals("Reduce of empty array with no initial value", e.message,
    216                  "reduce no initial TypeError type");
    217   }
    218   assertTrue(exception);
    219 
    220   exception = false;
    221   try {
    222     new constructor([]).reduceRight(sum);
    223   } catch (e) {
    224     exception = true;
    225     assertTrue(e instanceof TypeError,
    226                "reduceRight no initial value not throwing TypeError");
    227     assertEquals("Reduce of empty array with no initial value", e.message,
    228                  "reduceRight no initial TypeError type");
    229   }
    230   assertTrue(exception);
    231 
    232   // Reduce fails when called on non-TypedArrays
    233   assertThrows(function() {
    234     constructor.prototype.reduce.call([], function() {}, null);
    235   }, TypeError);
    236   assertThrows(function() {
    237     constructor.prototype.reduceRight.call([], function() {}, null);
    238   }, TypeError);
    239 
    240   // Shadowing length doesn't affect every, unlike Array.prototype.every
    241   var a = new constructor([1, 2]);
    242   Object.defineProperty(a, 'length', {value: 1});
    243   assertEquals(a.reduce(sum, 0), 3);
    244   assertEquals(Array.prototype.reduce.call(a, sum, 0), 1);
    245   assertEquals(a.reduceRight(sum, 0), 3);
    246   assertEquals(Array.prototype.reduceRight.call(a, sum, 0), 1);
    247 
    248   assertEquals(1, constructor.prototype.reduce.length);
    249   assertEquals(1, constructor.prototype.reduceRight.length);
    250 }
    251