blob: 1fddeca0bc749973a8f1ef68b4c6716cb0ad50b0 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
5var typedArrayConstructors = [
6 Uint8Array,
7 Int8Array,
8 Uint16Array,
9 Int16Array,
10 Uint32Array,
11 Int32Array,
12 Uint8ClampedArray,
13 Float32Array,
14 Float64Array
15];
16
17function 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).
35function 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
59function 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
85function sum(a, b) { return a + b; }
86function prod(a, b) { return a * b; }
87function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); }
88function accumulate(acc, elem, i) { acc[i] = elem; return acc; }
89
90for (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}