OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2009 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 /** | |
29 * @fileoverview Test reduce and reduceRight | |
Christian Plesner Hansen
2009/04/21 09:39:17
This is an excellent test!
| |
30 */ | |
31 | |
32 function clone(v) { | |
33 // Shallow-copies arrays, returns everything else verbatim. | |
34 if (v instanceof Array) { | |
35 // Shallow-copy an array. | |
36 var newArray = new Array(v.length); | |
37 for (var i in v) { | |
38 newArray[i] = v[i]; | |
39 } | |
40 return newArray; | |
41 } | |
42 return v; | |
43 } | |
44 | |
45 | |
46 // Creates a callback function for reduce/reduceRight that tests the number | |
47 // of arguments and otherwise behaves as "func", but which also | |
48 // records all calls in an array on the function (as arrays of arguments | |
49 // followed by result). | |
50 function makeRecorder(func, testName) { | |
51 var record = []; | |
52 var f = function recorder(a, b, i, s) { | |
53 assertEquals(4, arguments.length, | |
54 testName + "(number of arguments: " + arguments.length + ")"); | |
55 assertEquals("number", typeof(i), testName + "(index must be number)"); | |
56 assertEquals(s[i], b, testName + "(current argument is at index)"); | |
57 if (record.length > 0) { | |
58 var prevRecord = record[record.length - 1]; | |
59 var prevResult = prevRecord[prevRecord.length - 1]; | |
60 assertEquals(prevResult, a, | |
61 testName + "(prev result -> current input)"); | |
62 } | |
63 var args = [clone(a), clone(b), i, clone(s)]; | |
64 var result = func.apply(this, arguments); | |
65 args.push(clone(result)); | |
66 record.push(args); | |
67 return result; | |
68 }; | |
69 f.record = record; | |
70 return f; | |
71 } | |
72 | |
73 | |
74 function testReduce(type, | |
75 testName, | |
76 expectedResult, | |
77 expectedCalls, | |
78 array, | |
79 combine, | |
80 init) { | |
81 var rec = makeRecorder(combine); | |
82 var result; | |
83 var performsCall; | |
84 if (arguments.length > 6) { | |
85 result = array[type](rec, init); | |
86 } else { | |
87 result = array[type](rec); | |
88 } | |
89 var calls = rec.record; | |
90 assertEquals(expectedCalls.length, calls.length, | |
91 testName + " (number of calls)"); | |
92 for (var i = 0; i < expectedCalls.length; i++) { | |
93 assertEquals(expectedCalls[i], calls[i], | |
94 testName + " (call " + (i + 1) + ")"); | |
95 } | |
96 assertEquals(expectedResult, result, testName + " (result)"); | |
97 } | |
98 | |
99 | |
100 function sum(a, b) { return a + b; } | |
101 function prod(a, b) { return a * b; } | |
102 function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); } | |
103 function accumulate(acc, elem, i) { acc[i] = elem; return acc; } | |
104 | |
105 // ---- Test Reduce[Left] | |
106 | |
107 var simpleArray = [2,4,6] | |
108 | |
109 testReduce("reduce", "SimpleReduceSum", 12, | |
110 [[0, 2, 0, simpleArray, 2], | |
111 [2, 4, 1, simpleArray, 6], | |
112 [6, 6, 2, simpleArray, 12]], | |
113 simpleArray, sum, 0); | |
114 | |
115 testReduce("reduce", "SimpleReduceProd", 48, | |
116 [[1, 2, 0, simpleArray, 2], | |
117 [2, 4, 1, simpleArray, 8], | |
118 [8, 6, 2, simpleArray, 48]], | |
119 simpleArray, prod, 1); | |
120 | |
121 testReduce("reduce", "SimpleReduceDec", 246, | |
122 [[0, 2, 0, simpleArray, 200], | |
123 [200, 4, 1, simpleArray, 240], | |
124 [240, 6, 2, simpleArray, 246]], | |
125 simpleArray, dec, 0); | |
126 | |
127 testReduce("reduce", "SimpleReduceAccumulate", simpleArray, | |
128 [[[], 2, 0, simpleArray, [2]], | |
129 [[2], 4, 1, simpleArray, [2, 4]], | |
130 [[2,4], 6, 2, simpleArray, simpleArray]], | |
131 simpleArray, accumulate, []); | |
132 | |
133 | |
134 testReduce("reduce", "EmptyReduceSum", 0, [], [], sum, 0); | |
135 testReduce("reduce", "EmptyReduceProd", 1, [], [], prod, 1); | |
136 testReduce("reduce", "EmptyReduceDec", 0, [], [], dec, 0); | |
137 testReduce("reduce", "EmptyReduceAccumulate", [], [], [], accumulate, []); | |
138 | |
139 testReduce("reduce", "EmptyReduceSumNoInit", 0, [], [0], sum); | |
140 testReduce("reduce", "EmptyReduceProdNoInit", 1, [], [1], prod); | |
141 testReduce("reduce", "EmptyReduceDecNoInit", 0, [], [0], dec); | |
142 testReduce("reduce", "EmptyReduceAccumulateNoInit", [], [], [[]], accumulate); | |
143 | |
144 | |
145 var simpleSparseArray = [,,,2,,4,,6,,]; | |
146 testReduce("reduce", "SimpleSparseReduceSum", 12, | |
147 [[0, 2, 3, simpleSparseArray, 2], | |
148 [2, 4, 5, simpleSparseArray, 6], | |
149 [6, 6, 7, simpleSparseArray, 12]], | |
150 simpleSparseArray, sum, 0); | |
151 | |
152 testReduce("reduce", "SimpleSparseReduceProd", 48, | |
153 [[1, 2, 3, simpleSparseArray, 2], | |
154 [2, 4, 5, simpleSparseArray, 8], | |
155 [8, 6, 7, simpleSparseArray, 48]], | |
156 simpleSparseArray, prod, 1); | |
157 | |
158 testReduce("reduce", "SimpleSparseReduceDec", 204060, | |
159 [[0, 2, 3, simpleSparseArray, 200000], | |
160 [200000, 4, 5, simpleSparseArray, 204000], | |
161 [204000, 6, 7, simpleSparseArray, 204060]], | |
162 simpleSparseArray, dec, 0); | |
163 | |
164 testReduce("reduce", "SimpleSparseReduceAccumulate", [,,,2,,4,,6], | |
165 [[[], 2, 3, simpleSparseArray, [,,,2]], | |
166 [[,,,2], 4, 5, simpleSparseArray, [,,,2,,4]], | |
167 [[,,,2,,4], 6, 7, simpleSparseArray, [,,,2,,4,,6]]], | |
168 simpleSparseArray, accumulate, []); | |
169 | |
170 | |
171 testReduce("reduce", "EmptySparseReduceSumNoInit", 0, [], [,,0,,], sum); | |
172 testReduce("reduce", "EmptySparseReduceProdNoInit", 1, [], [,,1,,], prod); | |
173 testReduce("reduce", "EmptySparseReduceDecNoInit", 0, [], [,,0,,], dec); | |
174 testReduce("reduce", "EmptySparseReduceAccumulateNoInit", | |
175 [], [], [,,[],,], accumulate); | |
176 | |
177 | |
178 var verySparseArray = new Array(500000); | |
179 verySparseArray[100000] = 2; | |
180 verySparseArray[250000] = 4; | |
181 verySparseArray[450000] = 6; | |
182 var verySparseSlice2 = verySparseArray.slice(0, 100001); | |
183 var verySparseSlice4 = verySparseArray.slice(0, 250001); | |
184 var verySparseSlice6 = verySparseArray.slice(0, 450001); | |
185 | |
186 testReduce("reduce", "VerySparseReduceSum", 12, | |
187 [[0, 2, 100000, verySparseArray, 2], | |
188 [2, 4, 250000, verySparseArray, 6], | |
189 [6, 6, 450000, verySparseArray, 12]], | |
190 verySparseArray, sum, 0); | |
191 | |
192 testReduce("reduce", "VerySparseReduceProd", 48, | |
193 [[1, 2, 100000, verySparseArray, 2], | |
194 [2, 4, 250000, verySparseArray, 8], | |
195 [8, 6, 450000, verySparseArray, 48]], | |
196 verySparseArray, prod, 1); | |
197 | |
198 testReduce("reduce", "VerySparseReduceDec", Infinity, | |
199 [[0, 2, 100000, verySparseArray, Infinity], | |
200 [Infinity, 4, 250000, verySparseArray, Infinity], | |
201 [Infinity, 6, 450000, verySparseArray, Infinity]], | |
202 verySparseArray, dec, 0); | |
203 | |
204 testReduce("reduce", "SimpleSparseReduceAccumulate", | |
205 verySparseSlice6, | |
206 [[[], 2, 100000, verySparseArray, verySparseSlice2], | |
207 [verySparseSlice2, 4, 250000, verySparseArray, verySparseSlice4], | |
208 [verySparseSlice4, 6, 450000, verySparseArray, verySparseSlice6]], | |
209 verySparseArray, accumulate, []); | |
210 | |
211 | |
212 testReduce("reduce", "VerySparseReduceSumNoInit", 12, | |
213 [[2, 4, 250000, verySparseArray, 6], | |
214 [6, 6, 450000, verySparseArray, 12]], | |
215 verySparseArray, sum); | |
216 | |
217 testReduce("reduce", "VerySparseReduceProdNoInit", 48, | |
218 [[2, 4, 250000, verySparseArray, 8], | |
219 [8, 6, 450000, verySparseArray, 48]], | |
220 verySparseArray, prod); | |
221 | |
222 testReduce("reduce", "VerySparseReduceDecNoInit", Infinity, | |
223 [[2, 4, 250000, verySparseArray, Infinity], | |
224 [Infinity, 6, 450000, verySparseArray, Infinity]], | |
225 verySparseArray, dec); | |
226 | |
227 testReduce("reduce", "SimpleSparseReduceAccumulateNoInit", | |
228 2, | |
229 [[2, 4, 250000, verySparseArray, 2], | |
230 [2, 6, 450000, verySparseArray, 2]], | |
231 verySparseArray, accumulate); | |
232 | |
233 | |
234 // ---- Test ReduceRight | |
235 | |
236 testReduce("reduceRight", "SimpleReduceRightSum", 12, | |
237 [[0, 6, 2, simpleArray, 6], | |
238 [6, 4, 1, simpleArray, 10], | |
239 [10, 2, 0, simpleArray, 12]], | |
240 simpleArray, sum, 0); | |
241 | |
242 testReduce("reduceRight", "SimpleReduceRightProd", 48, | |
243 [[1, 6, 2, simpleArray, 6], | |
244 [6, 4, 1, simpleArray, 24], | |
245 [24, 2, 0, simpleArray, 48]], | |
246 simpleArray, prod, 1); | |
247 | |
248 testReduce("reduceRight", "SimpleReduceRightDec", 246, | |
249 [[0, 6, 2, simpleArray, 6], | |
250 [6, 4, 1, simpleArray, 46], | |
251 [46, 2, 0, simpleArray, 246]], | |
252 simpleArray, dec, 0); | |
253 | |
254 testReduce("reduceRight", "SimpleReduceRightAccumulate", simpleArray, | |
255 [[[], 6, 2, simpleArray, [,,6]], | |
256 [[,,6], 4, 1, simpleArray, [,4,6]], | |
257 [[,4,6], 2, 0, simpleArray, simpleArray]], | |
258 simpleArray, accumulate, []); | |
259 | |
260 | |
261 testReduce("reduceRight", "EmptyReduceRightSum", 0, [], [], sum, 0); | |
262 testReduce("reduceRight", "EmptyReduceRightProd", 1, [], [], prod, 1); | |
263 testReduce("reduceRight", "EmptyReduceRightDec", 0, [], [], dec, 0); | |
264 testReduce("reduceRight", "EmptyReduceRightAccumulate", [], | |
265 [], [], accumulate, []); | |
266 | |
267 testReduce("reduceRight", "EmptyReduceRightSumNoInit", 0, [], [0], sum); | |
268 testReduce("reduceRight", "EmptyReduceRightProdNoInit", 1, [], [1], prod); | |
269 testReduce("reduceRight", "EmptyReduceRightDecNoInit", 0, [], [0], dec); | |
270 testReduce("reduceRight", "EmptyReduceRightAccumulateNoInit", | |
271 [], [], [[]], accumulate); | |
272 | |
273 | |
274 testReduce("reduceRight", "SimpleSparseReduceRightSum", 12, | |
275 [[0, 6, 7, simpleSparseArray, 6], | |
276 [6, 4, 5, simpleSparseArray, 10], | |
277 [10, 2, 3, simpleSparseArray, 12]], | |
278 simpleSparseArray, sum, 0); | |
279 | |
280 testReduce("reduceRight", "SimpleSparseReduceRightProd", 48, | |
281 [[1, 6, 7, simpleSparseArray, 6], | |
282 [6, 4, 5, simpleSparseArray, 24], | |
283 [24, 2, 3, simpleSparseArray, 48]], | |
284 simpleSparseArray, prod, 1); | |
285 | |
286 testReduce("reduceRight", "SimpleSparseReduceRightDec", 204060, | |
287 [[0, 6, 7, simpleSparseArray, 60], | |
288 [60, 4, 5, simpleSparseArray, 4060], | |
289 [4060, 2, 3, simpleSparseArray, 204060]], | |
290 simpleSparseArray, dec, 0); | |
291 | |
292 testReduce("reduceRight", "SimpleSparseReduceRightAccumulate", [,,,2,,4,,6], | |
293 [[[], 6, 7, simpleSparseArray, [,,,,,,,6]], | |
294 [[,,,,,,,6], 4, 5, simpleSparseArray, [,,,,,4,,6]], | |
295 [[,,,,,4,,6], 2, 3, simpleSparseArray, [,,,2,,4,,6]]], | |
296 simpleSparseArray, accumulate, []); | |
297 | |
298 | |
299 testReduce("reduceRight", "EmptySparseReduceRightSumNoInit", | |
300 0, [], [,,0,,], sum); | |
301 testReduce("reduceRight", "EmptySparseReduceRightProdNoInit", | |
302 1, [], [,,1,,], prod); | |
303 testReduce("reduceRight", "EmptySparseReduceRightDecNoInit", | |
304 0, [], [,,0,,], dec); | |
305 testReduce("reduceRight", "EmptySparseReduceRightAccumulateNoInit", | |
306 [], [], [,,[],,], accumulate); | |
307 | |
308 | |
309 var verySparseSuffix6 = new Array(450001); | |
310 verySparseSuffix6[450000] = 6; | |
311 var verySparseSuffix4 = new Array(450001); | |
312 verySparseSuffix4[250000] = 4; | |
313 verySparseSuffix4[450000] = 6; | |
314 var verySparseSuffix2 = verySparseSlice6; | |
315 | |
316 | |
317 testReduce("reduceRight", "VerySparseReduceRightSum", 12, | |
318 [[0, 6, 450000, verySparseArray, 6], | |
319 [6, 4, 250000, verySparseArray, 10], | |
320 [10, 2, 100000, verySparseArray, 12]], | |
321 verySparseArray, sum, 0); | |
322 | |
323 testReduce("reduceRight", "VerySparseReduceRightProd", 48, | |
324 [[1, 6, 450000, verySparseArray, 6], | |
325 [6, 4, 250000, verySparseArray, 24], | |
326 [24, 2, 100000, verySparseArray, 48]], | |
327 verySparseArray, prod, 1); | |
328 | |
329 testReduce("reduceRight", "VerySparseReduceRightDec", Infinity, | |
330 [[0, 6, 450000, verySparseArray, Infinity], | |
331 [Infinity, 4, 250000, verySparseArray, Infinity], | |
332 [Infinity, 2, 100000, verySparseArray, Infinity]], | |
333 verySparseArray, dec, 0); | |
334 | |
335 testReduce("reduceRight", "SimpleSparseReduceRightAccumulate", | |
336 verySparseSuffix2, | |
337 [[[], 6, 450000, verySparseArray, verySparseSuffix6], | |
338 [verySparseSuffix6, 4, 250000, verySparseArray, verySparseSuffix4], | |
339 [verySparseSuffix4, 2, 100000, verySparseArray, verySparseSuffix2]], | |
340 verySparseArray, accumulate, []); | |
341 | |
342 | |
343 testReduce("reduceRight", "VerySparseReduceRightSumNoInit", 12, | |
344 [[6, 4, 250000, verySparseArray, 10], | |
345 [10, 2, 100000, verySparseArray, 12]], | |
346 verySparseArray, sum); | |
347 | |
348 testReduce("reduceRight", "VerySparseReduceRightProdNoInit", 48, | |
349 [[6, 4, 250000, verySparseArray, 24], | |
350 [24, 2, 100000, verySparseArray, 48]], | |
351 verySparseArray, prod); | |
352 | |
353 testReduce("reduceRight", "VerySparseReduceRightDecNoInit", Infinity, | |
354 [[6, 4, 250000, verySparseArray, Infinity], | |
355 [Infinity, 2, 100000, verySparseArray, Infinity]], | |
356 verySparseArray, dec); | |
357 | |
358 testReduce("reduceRight", "SimpleSparseReduceRightAccumulateNoInit", | |
359 6, | |
360 [[6, 4, 250000, verySparseArray, 6], | |
361 [6, 2, 100000, verySparseArray, 6]], | |
362 verySparseArray, accumulate); | |
363 | |
364 | |
365 // undefined is an element | |
366 var undefArray = [,,undefined,,undefined,,]; | |
367 | |
368 testReduce("reduce", "SparseUndefinedReduceAdd", NaN, | |
369 [[0, undefined, 2, undefArray, NaN], | |
370 [NaN, undefined, 4, undefArray, NaN], | |
371 ], | |
372 undefArray, sum, 0); | |
373 | |
374 testReduce("reduceRight", "SparseUndefinedReduceRightAdd", NaN, | |
375 [[0, undefined, 4, undefArray, NaN], | |
376 [NaN, undefined, 2, undefArray, NaN], | |
377 ], undefArray, sum, 0); | |
378 | |
379 testReduce("reduce", "SparseUndefinedReduceAddNoInit", NaN, | |
380 [[undefined, undefined, 4, undefArray, NaN], | |
381 ], undefArray, sum); | |
382 | |
383 testReduce("reduceRight", "SparseUndefinedReduceRightAddNoInit", NaN, | |
384 [[undefined, undefined, 2, undefArray, NaN], | |
385 ], undefArray, sum); | |
386 | |
387 | |
388 // Test error conditions | |
389 | |
390 try { | |
391 [1].reduce("not a function"); | |
392 fail("Reduce callback not a function not throwing"); | |
393 } catch (e) { | |
394 assertTrue(e instanceof TypeError, | |
395 "reduce callback not a function not throwing TypeError"); | |
396 assertEquals("called_non_callable", e.type, | |
397 "reduce non function TypeError type"); | |
398 } | |
399 | |
400 try { | |
401 [1].reduceRight("not a function"); | |
402 fail("ReduceRight callback not a function not throwing"); | |
403 } catch (e) { | |
404 assertTrue(e instanceof TypeError, | |
405 "reduceRight callback not a function not throwing TypeError"); | |
406 assertEquals("called_non_callable", e.type, | |
407 "reduceRight non function TypeError type"); | |
408 } | |
409 | |
410 | |
411 try { | |
412 [].reduce(sum); | |
413 fail("Reduce no initial value not throwing"); | |
414 } catch (e) { | |
415 assertTrue(e instanceof TypeError, | |
416 "reduce no initial value not throwing TypeError"); | |
417 assertEquals("reduce_no_initial", e.type, | |
418 "reduce no initial TypeError type"); | |
419 } | |
420 | |
421 try { | |
422 [].reduceRight(sum); | |
423 fail("ReduceRight no initial value not throwing"); | |
424 } catch (e) { | |
425 assertTrue(e instanceof TypeError, | |
426 "reduceRight no initial value not throwing TypeError"); | |
427 assertEquals("reduce_no_initial", e.type, | |
428 "reduceRight no initial TypeError type"); | |
429 } | |
430 | |
431 try { | |
432 [,,,].reduce(sum); | |
433 fail("Reduce sparse no initial value not throwing"); | |
434 } catch (e) { | |
435 assertTrue(e instanceof TypeError, | |
436 "reduce sparse no initial value not throwing TypeError"); | |
437 assertEquals("reduce_no_initial", e.type, | |
438 "reduce no initial TypeError type"); | |
439 | |
440 } | |
441 | |
442 try { | |
443 [,,,].reduceRight(sum); | |
444 fail("ReduceRight sparse no initial value not throwing"); | |
445 } catch (e) { | |
446 assertTrue(e instanceof TypeError, | |
447 "reduceRight sparse no initial value not throwing TypeError"); | |
448 assertEquals("reduce_no_initial", e.type, | |
449 "reduceRight no initial TypeError type"); | |
450 } | |
451 | |
452 | |
453 // Array changing length | |
454 | |
455 function manipulator(a, b, i, s) { | |
456 if (s.length % 2) { | |
457 s[s.length * 3] = i; | |
458 } else { | |
459 s.length = s.length >> 1; | |
460 } | |
461 return a + b; | |
462 } | |
463 | |
464 var arr = [1, 2, 3, 4]; | |
465 testReduce("reduce", "ArrayManipulationShort", 3, | |
466 [[0, 1, 0, [1, 2, 3, 4], 1], | |
467 [1, 2, 1, [1, 2], 3], | |
468 ], arr, manipulator, 0); | |
469 | |
470 var arr = [1, 2, 3, 4, 5]; | |
471 testReduce("reduce", "ArrayManipulationLonger", 10, | |
472 [[0, 1, 0, [1, 2, 3, 4, 5], 1], | |
473 [1, 2, 1, [1, 2, 3, 4, 5,,,,,,,,,,, 0], 3], | |
474 [3, 3, 2, [1, 2, 3, 4, 5,,,,], 6], | |
475 [6, 4, 3, [1, 2, 3, 4], 10], | |
476 ], arr, manipulator, 0); | |
477 | |
478 function extender(a, b, i, s) { | |
479 s[s.length] = s.length; | |
480 return a + b; | |
481 } | |
482 | |
483 var arr = [1, 2, 3, 4]; | |
484 testReduce("reduce", "ArrayManipulationExtender", 10, | |
485 [[0, 1, 0, [1, 2, 3, 4], 1], | |
486 [1, 2, 1, [1, 2, 3, 4, 4], 3], | |
487 [3, 3, 2, [1, 2, 3, 4, 4, 5], 6], | |
488 [6, 4, 3, [1, 2, 3, 4, 4, 5, 6], 10], | |
489 ], arr, extender, 0); | |
490 | |
OLD | NEW |