583ea936c81ef64f24e72c4188d1a139560eccc5
[motion.git] / public / bower_components / lodash / test / test-fp.js
1 ;(function() {
2
3   /** Used as a safe reference for `undefined` in pre-ES5 environments. */
4   var undefined;
5
6   /** Used as the size to cover large array optimizations. */
7   var LARGE_ARRAY_SIZE = 200;
8
9   /** Used as a reference to the global object. */
10   var root = (typeof global == 'object' && global) || this;
11
12   /** Used for native method references. */
13   var arrayProto = Array.prototype;
14
15   /** Method and object shortcuts. */
16   var phantom = root.phantom,
17       amd = root.define && define.amd,
18       argv = root.process && process.argv,
19       document = !phantom && root.document,
20       noop = function() {},
21       slice = arrayProto.slice,
22       WeakMap = root.WeakMap;
23
24   /*--------------------------------------------------------------------------*/
25
26   /** Use a single "load" function. */
27   var load = (!amd && typeof require == 'function')
28     ? require
29     : noop;
30
31   /** The unit testing framework. */
32   var QUnit = root.QUnit || (root.QUnit = (
33     QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
34     QUnit = QUnit.QUnit || QUnit
35   ));
36
37   /** Load stable Lodash and QUnit Extras. */
38   var _ = root._ || (root._ = (
39     _ = load('../lodash.js'),
40     _.runInContext(root)
41   ));
42
43   var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js');
44   if (QUnitExtras) {
45     QUnitExtras.runInContext(root);
46   }
47
48   var convert = (function() {
49     var baseConvert = root.fp || load('../fp/_baseConvert.js');
50     if (!root.fp) {
51       return function(name, func, options) {
52         return baseConvert(_, name, func, options);
53       };
54     }
55     return function(name, func, options) {
56       if (typeof name == 'function') {
57         options = func;
58         func = name;
59         name = undefined;
60       }
61       return name === undefined
62         ? baseConvert(func, options)
63         : baseConvert(_.runInContext(), options)[name];
64     };
65   }());
66
67   var fp = root.fp
68     ? (fp = _.noConflict(), _ = root._, fp)
69     : convert(_.runInContext());
70
71   var mapping = root.mapping || load('../fp/_mapping.js');
72
73   /*--------------------------------------------------------------------------*/
74
75   /**
76    * Skips a given number of tests with a passing result.
77    *
78    * @private
79    * @param {Object} assert The QUnit assert object.
80    * @param {number} [count=1] The number of tests to skip.
81    */
82   function skipAssert(assert, count) {
83     count || (count = 1);
84     while (count--) {
85       assert.ok(true, 'test skipped');
86     }
87   }
88
89   /*--------------------------------------------------------------------------*/
90
91   if (argv) {
92     console.log('Running lodash/fp tests.');
93   }
94
95   QUnit.module('convert');
96
97   (function() {
98     var allFalseOptions = {
99       'cap': false,
100       'curry': false,
101       'fixed': false,
102       'immutable': false,
103       'rearg': false
104     };
105
106     QUnit.test('should work when given an object', function(assert) {
107       assert.expect(2);
108
109       if (!document) {
110         var array = [1, 2, 3, 4],
111             lodash = convert({ 'remove': _.remove });
112
113         var actual = lodash.remove(function(n) {
114           return n % 2 == 0;
115         })(array);
116
117         assert.deepEqual(array, [1, 2, 3, 4]);
118         assert.deepEqual(actual, [1, 3]);
119       }
120       else {
121         skipAssert(assert, 2);
122       }
123     });
124
125     QUnit.test('should only add a `placeholder` property if needed', function(assert) {
126       assert.expect(2);
127
128       if (!document) {
129         var methodNames = _.keys(mapping.placeholder),
130             expected = _.map(methodNames, _.constant(true));
131
132         var actual = _.map(methodNames, function(methodName) {
133           var object = {};
134           object[methodName] = _[methodName];
135
136           var lodash = convert(object);
137           return methodName in lodash;
138         });
139
140         assert.deepEqual(actual, expected);
141
142         var lodash = convert({ 'add': _.add });
143         assert.notOk('placeholder' in lodash);
144       }
145       else {
146         skipAssert(assert, 2);
147       }
148     });
149
150     QUnit.test('should accept an `options` argument', function(assert) {
151       assert.expect(3);
152
153       var array = [1, 2, 3, 4],
154           remove = convert('remove', _.remove, allFalseOptions);
155
156       var actual = remove(array, function(n, index) {
157         return index % 2 == 0;
158       });
159
160       assert.deepEqual(array, [2, 4]);
161       assert.deepEqual(actual, [1, 3]);
162       assert.deepEqual(remove(), []);
163     });
164
165     QUnit.test('should accept a variety of options', function(assert) {
166       assert.expect(8);
167
168       var array = [1, 2, 3, 4],
169           predicate = function(n) { return n % 2 == 0; },
170           value = _.clone(array),
171           remove = convert('remove', _.remove, { 'cap': false }),
172           actual = remove(function(n, index) { return index % 2 == 0; })(value);
173
174       assert.deepEqual(value, [1, 2, 3, 4]);
175       assert.deepEqual(actual, [2, 4]);
176
177       remove = convert('remove', _.remove, { 'curry': false });
178       actual = remove(predicate);
179
180       assert.deepEqual(actual, []);
181
182       var trim = convert('trim', _.trim, { 'fixed': false });
183       assert.strictEqual(trim('_-abc-_', '_-'), 'abc');
184
185       value = _.clone(array);
186       remove = convert('remove', _.remove, { 'immutable': false });
187       actual = remove(predicate)(value);
188
189       assert.deepEqual(value, [1, 3]);
190       assert.deepEqual(actual, [2, 4]);
191
192       value = _.clone(array);
193       remove = convert('remove', _.remove, { 'rearg': false });
194       actual = remove(value)(predicate);
195
196       assert.deepEqual(value, [1, 2, 3, 4]);
197       assert.deepEqual(actual, [1, 3]);
198     });
199
200     QUnit.test('should respect the `cap` option', function(assert) {
201       assert.expect(1);
202
203       var iteratee = convert('iteratee', _.iteratee, { 'cap': false });
204
205       var func = iteratee(function(a, b, c) {
206         return [a, b, c];
207       }, 3);
208
209       assert.deepEqual(func(1, 2, 3), [1, 2, 3]);
210     });
211
212     QUnit.test('should respect the `rearg` option', function(assert) {
213       assert.expect(1);
214
215       var add = convert('add', _.add, { 'rearg': true });
216
217       assert.strictEqual(add('2')('1'), '12');
218     });
219
220     QUnit.test('should use `options` in `runInContext`', function(assert) {
221       assert.expect(3);
222
223       var array = [1, 2, 3, 4],
224           runInContext = convert('runInContext', _.runInContext, allFalseOptions),
225           lodash = runInContext();
226
227       var actual = lodash.remove(array, function(n, index) {
228         return index % 2 == 0;
229       });
230
231       assert.deepEqual(array, [2, 4]);
232       assert.deepEqual(actual, [1, 3]);
233       assert.deepEqual(lodash.remove(), []);
234     });
235
236     QUnit.test('should work when given lodash and `options`', function(assert) {
237       assert.expect(3);
238
239       var array = [1, 2, 3, 4],
240           lodash = convert(_.runInContext(), allFalseOptions);
241
242       var actual = lodash.remove(array, function(n, index) {
243         return index % 2 == 0;
244       });
245
246       assert.deepEqual(array, [2, 4]);
247       assert.deepEqual(actual, [1, 3]);
248       assert.deepEqual(lodash.remove(), []);
249     });
250
251     QUnit.test('should work when given an object and `options`', function(assert) {
252       assert.expect(3);
253
254       if (!document) {
255         var array = [1, 2, 3, 4],
256             lodash = convert({ 'remove': _.remove }, allFalseOptions);
257
258         var actual = lodash.remove(array, function(n, index) {
259           return index % 2 == 0;
260         });
261
262         assert.deepEqual(array, [2, 4]);
263         assert.deepEqual(actual, [1, 3]);
264         assert.deepEqual(lodash.remove(), []);
265       }
266       else {
267         skipAssert(assert, 3);
268       }
269     });
270   }());
271
272   /*--------------------------------------------------------------------------*/
273
274   QUnit.module('method arity checks');
275
276   (function() {
277     QUnit.test('should wrap methods with an arity > `1`', function(assert) {
278       assert.expect(1);
279
280       var methodNames = _.filter(_.functions(fp), function(methodName) {
281         return fp[methodName].length > 1;
282       });
283
284       assert.deepEqual(methodNames, []);
285     });
286
287     QUnit.test('should have >= arity of `aryMethod` designation', function(assert) {
288       assert.expect(4);
289
290       _.times(4, function(index) {
291         var aryCap = index + 1;
292
293         var methodNames = _.filter(mapping.aryMethod[aryCap], function(methodName) {
294           var key = _.result(mapping.remap, methodName, methodName),
295               arity = _[key].length;
296
297           return arity != 0 && arity < aryCap;
298         });
299
300         assert.deepEqual(methodNames, [], '`aryMethod[' + aryCap + ']`');
301       });
302     });
303   }());
304
305   /*--------------------------------------------------------------------------*/
306
307   QUnit.module('method aliases');
308
309   (function() {
310     QUnit.test('should have correct aliases', function(assert) {
311       assert.expect(1);
312
313       var actual = _.transform(mapping.aliasToReal, function(result, realName, alias) {
314         result.push([alias, fp[alias] === fp[realName]]);
315       }, []);
316
317       assert.deepEqual(_.reject(actual, 1), []);
318     });
319   }());
320
321   /*--------------------------------------------------------------------------*/
322
323   QUnit.module('method ary caps');
324
325   (function() {
326     QUnit.test('should have a cap of 1', function(assert) {
327       assert.expect(1);
328
329       var funcMethods = [
330         'curry', 'iteratee', 'memoize', 'over', 'overEvery', 'overSome',
331         'method', 'methodOf', 'rest', 'runInContext'
332       ];
333
334       var exceptions = funcMethods.concat('mixin', 'template'),
335           expected = _.map(mapping.aryMethod[1], _.constant(true));
336
337       var actual = _.map(mapping.aryMethod[1], function(methodName) {
338         var arg = _.includes(funcMethods, methodName) ? _.noop : 1,
339             result = _.attempt(function() { return fp[methodName](arg); });
340
341         if (_.includes(exceptions, methodName)
342               ? typeof result == 'function'
343               : typeof result != 'function'
344             ) {
345           return true;
346         }
347         console.log(methodName, result);
348         return false;
349       });
350
351       assert.deepEqual(actual, expected);
352     });
353
354     QUnit.test('should have a cap of 2', function(assert) {
355       assert.expect(1);
356
357       var funcMethods = [
358         'after', 'ary', 'before', 'bind', 'bindKey', 'curryN', 'debounce', 'delay',
359         'overArgs', 'partial', 'partialRight', 'rearg', 'throttle', 'wrap'
360       ];
361
362       var exceptions = _.difference(funcMethods.concat('matchesProperty'), ['cloneDeepWith', 'cloneWith', 'delay']),
363           expected = _.map(mapping.aryMethod[2], _.constant(true));
364
365       var actual = _.map(mapping.aryMethod[2], function(methodName) {
366         var args = _.includes(funcMethods, methodName) ? [methodName == 'curryN' ? 1 : _.noop, _.noop] : [1, []],
367             result = _.attempt(function() { return fp[methodName](args[0])(args[1]); });
368
369         if (_.includes(exceptions, methodName)
370               ? typeof result == 'function'
371               : typeof result != 'function'
372             ) {
373           return true;
374         }
375         console.log(methodName, result);
376         return false;
377       });
378
379       assert.deepEqual(actual, expected);
380     });
381
382     QUnit.test('should have a cap of 3', function(assert) {
383       assert.expect(1);
384
385       var funcMethods = [
386         'assignWith', 'extendWith', 'isEqualWith', 'isMatchWith', 'reduce',
387         'reduceRight', 'transform', 'zipWith'
388       ];
389
390       var expected = _.map(mapping.aryMethod[3], _.constant(true));
391
392       var actual = _.map(mapping.aryMethod[3], function(methodName) {
393         var args = _.includes(funcMethods, methodName) ? [_.noop, 0, 1] : [0, 1, []],
394             result = _.attempt(function() { return fp[methodName](args[0])(args[1])(args[2]); });
395
396         if (typeof result != 'function') {
397           return true;
398         }
399         console.log(methodName, result);
400         return false;
401       });
402
403       assert.deepEqual(actual, expected);
404     });
405   }());
406
407   /*--------------------------------------------------------------------------*/
408
409   QUnit.module('methods that use `indexOf`');
410
411   (function() {
412     QUnit.test('should work with `fp.indexOf`', function(assert) {
413       assert.expect(10);
414
415       var array = ['a', 'b', 'c'],
416           other = ['b', 'b', 'd'],
417           object = { 'a': 1, 'b': 2, 'c': 2 },
418           actual = fp.difference(array)(other);
419
420       assert.deepEqual(actual, ['a', 'c'], 'fp.difference');
421
422       actual = fp.includes('b')(array);
423       assert.strictEqual(actual, true, 'fp.includes');
424
425       actual = fp.intersection(other)(array);
426       assert.deepEqual(actual, ['b'], 'fp.intersection');
427
428       actual = fp.omit(other)(object);
429       assert.deepEqual(actual, { 'a': 1, 'c': 2 }, 'fp.omit');
430
431       actual = fp.union(other)(array);
432       assert.deepEqual(actual, ['a', 'b', 'c', 'd'], 'fp.union');
433
434       actual = fp.uniq(other);
435       assert.deepEqual(actual, ['b', 'd'], 'fp.uniq');
436
437       actual = fp.uniqBy(_.identity, other);
438       assert.deepEqual(actual, ['b', 'd'], 'fp.uniqBy');
439
440       actual = fp.without('b')(array);
441       assert.deepEqual(actual, ['a', 'c'], 'fp.without');
442
443       actual = fp.xor(other)(array);
444       assert.deepEqual(actual, ['a', 'c', 'd'], 'fp.xor');
445
446       actual = fp.pull('b')(array);
447       assert.deepEqual(actual, ['a', 'c'], 'fp.pull');
448     });
449   }());
450
451   /*--------------------------------------------------------------------------*/
452
453   QUnit.module('cherry-picked methods');
454
455   (function() {
456     QUnit.test('should provide the correct `iteratee` arguments', function(assert) {
457       assert.expect(4);
458
459       var args,
460           array = [1, 2, 3],
461           object = { 'a': 1, 'b': 2 },
462           isFIFO = _.keys(object)[0] == 'a',
463           map = convert('map', _.map),
464           reduce = convert('reduce', _.reduce);
465
466       map(function() {
467         args || (args = slice.call(arguments));
468       })(array);
469
470       assert.deepEqual(args, [1]);
471
472       args = undefined;
473       map(function() {
474         args || (args = slice.call(arguments));
475       })(object);
476
477       assert.deepEqual(args, isFIFO ? [1] : [2]);
478
479       args = undefined;
480       reduce(function() {
481         args || (args = slice.call(arguments));
482       })(0)(array);
483
484       assert.deepEqual(args, [0, 1]);
485
486       args = undefined;
487       reduce(function() {
488         args || (args = slice.call(arguments));
489       })(0)(object);
490
491       assert.deepEqual(args, isFIFO ? [0, 1] : [0, 2]);
492     });
493
494     QUnit.test('should not support shortcut fusion', function(assert) {
495       assert.expect(3);
496
497       var array = fp.range(0, LARGE_ARRAY_SIZE),
498           filterCount = 0,
499           mapCount = 0;
500
501       var iteratee = function(value) {
502         mapCount++;
503         return value * value;
504       };
505
506       var predicate = function(value) {
507         filterCount++;
508         return value % 2 == 0;
509       };
510
511       var map1 = convert('map', _.map),
512           filter1 = convert('filter', _.filter),
513           take1 = convert('take', _.take);
514
515       var filter2 = filter1(predicate),
516           map2 = map1(iteratee),
517           take2 = take1(2);
518
519       var combined = fp.flow(map2, filter2, fp.compact, take2);
520
521       assert.deepEqual(combined(array), [4, 16]);
522       assert.strictEqual(filterCount, 200, 'filterCount');
523       assert.strictEqual(mapCount, 200, 'mapCount');
524     });
525   }());
526
527   /*--------------------------------------------------------------------------*/
528
529   QUnit.module('iteratee shorthands');
530
531   (function() {
532     var objects = [{ 'a': 1, 'b': 2 }, { 'a': 3, 'b': 4 }];
533
534     QUnit.test('should work with "_.matches" shorthands', function(assert) {
535       assert.expect(1);
536
537       assert.deepEqual(fp.filter({ 'a': 3 })(objects), [objects[1]]);
538     });
539
540     QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) {
541       assert.expect(1);
542
543       assert.deepEqual(fp.filter(['a', 3])(objects), [objects[1]]);
544     });
545
546     QUnit.test('should work with "_.property" shorthands', function(assert) {
547       assert.expect(1);
548
549       assert.deepEqual(fp.map('a')(objects), [1, 3]);
550     });
551   }());
552
553   /*--------------------------------------------------------------------------*/
554
555   QUnit.module('mutation methods');
556
557   (function() {
558     var array = [1, 2, 3],
559         object = { 'a': 1 },
560         deepObject = { 'a': { 'b': 2, 'c': 3 } };
561
562     QUnit.test('should not mutate values', function(assert) {
563       assert.expect(38);
564
565       function Foo() {}
566       Foo.prototype = { 'b': 2 };
567
568       var value = _.clone(object),
569           actual = fp.assign(value)({ 'b': 2 });
570
571       assert.deepEqual(value, object, 'fp.assign');
572       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assign');
573
574       value = _.clone(object);
575       actual = fp.assignWith(function(objValue, srcValue) {
576         return srcValue;
577       })(value)({ 'b': 2 });
578
579       assert.deepEqual(value, object, 'fp.assignWith');
580       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignWith');
581
582       value = _.clone(object);
583       actual = fp.assignIn(value)(new Foo);
584
585       assert.deepEqual(value, object, 'fp.assignIn');
586       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignIn');
587
588       value = _.clone(object);
589       actual = fp.assignInWith(function(objValue, srcValue) {
590         return srcValue;
591       })(value)(new Foo);
592
593       assert.deepEqual(value, object, 'fp.assignInWith');
594       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignInWith');
595
596       value = _.clone(object);
597       actual = fp.defaults({ 'a': 2, 'b': 2 })(value);
598
599       assert.deepEqual(value, object, 'fp.defaults');
600       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.defaults');
601
602       value = _.cloneDeep(deepObject);
603       actual = fp.defaultsDeep({ 'a': { 'c': 4, 'd': 4 } })(deepObject);
604
605       assert.deepEqual(value, { 'a': { 'b': 2, 'c': 3 } }, 'fp.defaultsDeep');
606       assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3, 'd': 4 } }, 'fp.defaultsDeep');
607
608       value = _.clone(object);
609       actual = fp.extend(value)(new Foo);
610
611       assert.deepEqual(value, object, 'fp.extend');
612       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extend');
613
614       value = _.clone(object);
615       actual = fp.extendWith(function(objValue, srcValue) {
616         return srcValue;
617       })(value)(new Foo);
618
619       assert.deepEqual(value, object, 'fp.extendWith');
620       assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extendWith');
621
622       value = _.clone(array);
623       actual = fp.fill(1)(2)('*')(value);
624
625       assert.deepEqual(value, array, 'fp.fill');
626       assert.deepEqual(actual, [1, '*', 3], 'fp.fill');
627
628       value = _.cloneDeep(deepObject);
629       actual = fp.merge(value)({ 'a': { 'd': 4 } });
630
631       assert.deepEqual(value, { 'a': { 'b': 2, 'c': 3 } }, 'fp.merge');
632       assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3, 'd': 4 } }, 'fp.merge');
633
634       value = _.cloneDeep(deepObject);
635       value.a.b = [1];
636
637       actual = fp.mergeWith(function(objValue, srcValue) {
638         if (_.isArray(objValue)) {
639           return objValue.concat(srcValue);
640         }
641       }, value, { 'a': { 'b': [2, 3] } });
642
643       assert.deepEqual(value, { 'a': { 'b': [1], 'c': 3 } }, 'fp.mergeWith');
644       assert.deepEqual(actual, { 'a': { 'b': [1, 2, 3], 'c': 3 } }, 'fp.mergeWith');
645
646       value = _.clone(array);
647       actual = fp.pull(2)(value);
648
649       assert.deepEqual(value, array, 'fp.pull');
650       assert.deepEqual(actual, [1, 3], 'fp.pull');
651
652       value = _.clone(array);
653       actual = fp.pullAll([1, 3])(value);
654
655       assert.deepEqual(value, array, 'fp.pullAll');
656       assert.deepEqual(actual, [2], 'fp.pullAll');
657
658       value = _.clone(array);
659       actual = fp.pullAt([0, 2])(value);
660
661       assert.deepEqual(value, array, 'fp.pullAt');
662       assert.deepEqual(actual, [2], 'fp.pullAt');
663
664       value = _.clone(array);
665       actual = fp.remove(function(value) {
666         return value === 2;
667       })(value);
668
669       assert.deepEqual(value, array, 'fp.remove');
670       assert.deepEqual(actual, [1, 3], 'fp.remove');
671
672       value = _.clone(array);
673       actual = fp.reverse(value);
674
675       assert.deepEqual(value, array, 'fp.reverse');
676       assert.deepEqual(actual, [3, 2, 1], 'fp.reverse');
677
678       value = _.cloneDeep(deepObject);
679       actual = fp.set('a.b')(3)(value);
680
681       assert.deepEqual(value, deepObject, 'fp.set');
682       assert.deepEqual(actual, { 'a': { 'b': 3, 'c': 3 } }, 'fp.set');
683
684       value = _.cloneDeep(deepObject);
685       actual = fp.setWith(Object)('d.e')(4)(value);
686
687       assert.deepEqual(value, deepObject, 'fp.setWith');
688       assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }, 'fp.setWith');
689
690       value = _.cloneDeep(deepObject);
691       actual = fp.unset('a.b')(value);
692
693       assert.deepEqual(value, deepObject, 'fp.unset');
694       assert.deepEqual(actual, { 'a': { 'c': 3 } }, 'fp.unset');
695     });
696   }());
697
698   /*--------------------------------------------------------------------------*/
699
700   QUnit.module('placeholder methods');
701
702   (function() {
703     QUnit.test('should support placeholders', function(assert) {
704       assert.expect(6);
705
706       _.each([[], fp.__], function(ph) {
707         fp.placeholder = ph;
708
709         var actual = fp.add(ph, 'b')('a');
710         assert.strictEqual(actual, 'ab');
711
712         actual = fp.slice(ph, 2)(1)(['a', 'b', 'c']);
713         assert.deepEqual(actual, ['b']);
714
715         actual = fp.fill(ph, 2)(1, '*')([1, 2, 3]);
716         assert.deepEqual(actual, [1, '*', 3]);
717       });
718     });
719
720     _.forOwn(mapping.placeholder, function(truthy, methodName) {
721       var func = fp[methodName];
722
723       QUnit.test('`_.' + methodName + '` should have a `placeholder` property', function(assert) {
724         assert.expect(2);
725
726         assert.ok(_.isObject(func.placeholder));
727         assert.strictEqual(func.placeholder, fp.__);
728       });
729     });
730   }());
731
732   /*--------------------------------------------------------------------------*/
733
734   QUnit.module('set methods');
735
736   (function() {
737     var array = [1, 2, 3],
738         object = { 'a': 1 },
739         deepObject = { 'a': { 'b': 2, 'c': 3 } };
740
741     QUnit.test('should only clone objects in `path`', function(assert) {
742       assert.expect(8);
743
744       var object = { 'a': { 'b': { 'c': 1 }, 'd': { 'e': 1 } } },
745           value = _.cloneDeep(object),
746           actual = fp.set('a.b.c.d.e', 3, value);
747
748       assert.ok(_.isObject(actual.a.b.c), 'fp.set');
749       assert.ok(_.isNumber(actual.a.b.c), 'fp.set');
750
751       assert.strictEqual(actual.a.b.c.d.e, 3, 'fp.set');
752       assert.strictEqual(actual.d, value.d, 'fp.set');
753
754       value = _.cloneDeep(object);
755       actual = fp.setWith(Object)('a.b.c')(2)(value);
756
757       assert.strictEqual(actual.a.b.c, 2, 'fp.setWith');
758       assert.strictEqual(actual.d, value.d, 'fp.setWith');
759
760       value = _.cloneDeep(object);
761       actual = fp.unset('a.b')(value);
762
763       assert.notOk('b' in actual, 'fp.unset');
764       assert.strictEqual(actual.d, value.d, 'fp.unset');
765     });
766   }());
767
768   /*--------------------------------------------------------------------------*/
769
770   QUnit.module('with methods');
771
772   (function() {
773     var array = [1, 2, 3],
774         object = { 'a': 1 };
775
776     QUnit.test('should provide the correct `customizer` arguments', function(assert) {
777       assert.expect(4);
778
779       var args,
780           value = _.clone(object);
781
782       fp.assignWith(function() {
783         args || (args = _.map(arguments, _.cloneDeep));
784       })(value)({ 'b': 2 });
785
786       assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.assignWith');
787
788       args = undefined;
789       value = _.clone(object);
790
791       fp.extendWith(function() {
792         args || (args = _.map(arguments, _.cloneDeep));
793       })(value)({ 'b': 2 });
794
795       assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.extendWith');
796
797       var stack = { '__data__': { 'array': [], 'map': null } },
798           expected = [[1], [2, 3], 'a', { 'a': [1] }, { 'a': [2, 3] }, stack];
799
800       args = undefined;
801       value = { 'a': [1] };
802
803       fp.mergeWith(function() {
804         args || (args = _.map(arguments, _.cloneDeep));
805       })(value)({ 'a': [2, 3] });
806
807       args[5] = _.omitBy(args[5], _.isFunction);
808       assert.deepEqual(args, expected, 'fp.mergeWith');
809
810       args = undefined;
811       value = _.clone(object);
812
813       fp.setWith(function() {
814         args || (args = _.map(arguments, _.cloneDeep));
815       })('b.c')(2)(value);
816
817       assert.deepEqual(args, [undefined, 'b', { 'a': 1 }], 'fp.setWith');
818     });
819   }());
820
821   /*--------------------------------------------------------------------------*/
822
823   QUnit.module('fp.add and fp.subtract');
824
825   _.each(['add', 'subtract'], function(methodName) {
826     var func = fp[methodName],
827         isAdd = methodName == 'add';
828
829     QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
830       assert.expect(1);
831
832       assert.strictEqual(func('1')('2'), isAdd ? '12' : -1);
833     });
834   });
835
836   /*--------------------------------------------------------------------------*/
837
838   QUnit.module('fp.castArray');
839
840   (function() {
841     QUnit.test('should shallow clone array values', function(assert) {
842       assert.expect(2);
843
844       var array = [1],
845           actual = fp.castArray(array);
846
847       assert.deepEqual(actual, array);
848       assert.notStrictEqual(actual, array);
849     });
850
851     QUnit.test('should not shallow clone non-array values', function(assert) {
852       assert.expect(2);
853
854       var object = { 'a': 1 },
855           actual = fp.castArray(object);
856
857       assert.deepEqual(actual, [object]);
858       assert.strictEqual(actual[0], object);
859     });
860
861     QUnit.test('should convert by name', function(assert) {
862       assert.expect(4);
863
864       var array = [1],
865           object = { 'a': 1 },
866           castArray = convert('castArray', _.castArray),
867           actual = castArray(array);
868
869       assert.deepEqual(actual, array);
870       assert.notStrictEqual(actual, array);
871
872       actual = castArray(object);
873       assert.deepEqual(actual, [object]);
874       assert.strictEqual(actual[0], object);
875     });
876   }());
877
878   /*--------------------------------------------------------------------------*/
879
880   QUnit.module('fp.curry and fp.curryRight');
881
882   _.each(['curry', 'curryRight'], function(methodName) {
883     var func = fp[methodName];
884
885     QUnit.test('`_.' + methodName + '` should only accept a `func` param', function(assert) {
886       assert.expect(1);
887
888       assert.raises(function() { func(1, _.noop); }, TypeError);
889     });
890   });
891
892   /*--------------------------------------------------------------------------*/
893
894   QUnit.module('fp.curryN and fp.curryRightN');
895
896   _.each(['curryN', 'curryRightN'], function(methodName) {
897     var func = fp[methodName];
898
899     QUnit.test('`_.' + methodName + '` should accept an `arity` param', function(assert) {
900       assert.expect(1);
901
902       var actual = func(1)(function(a, b) { return [a, b]; })('a');
903       assert.deepEqual(actual, ['a', undefined]);
904     });
905   });
906
907   /*--------------------------------------------------------------------------*/
908
909   QUnit.module('fp.difference');
910
911   (function() {
912     QUnit.test('should return the elements of the first array not included in the second array', function(assert) {
913       assert.expect(1);
914
915       assert.deepEqual(fp.difference([1, 2])([2, 3]), [1]);
916     });
917   }());
918
919   /*--------------------------------------------------------------------------*/
920
921   QUnit.module('fp.extend');
922
923   (function() {
924     QUnit.test('should convert by name', function(assert) {
925       assert.expect(2);
926
927       function Foo() {}
928       Foo.prototype = { 'b': 2 };
929
930       var object = { 'a': 1 },
931           extend = convert('extend', _.extend),
932           value = _.clone(object),
933           actual = extend(value)(new Foo);
934
935       assert.deepEqual(value, object);
936       assert.deepEqual(actual, { 'a': 1, 'b': 2 });
937     });
938   }());
939
940   /*--------------------------------------------------------------------------*/
941
942   QUnit.module('fp.fill');
943
944   (function() {
945     QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) {
946       assert.expect(1);
947
948       var array = [1, 2, 3];
949       assert.deepEqual(fp.fill(1)(2)('*')(array), [1, '*', 3]);
950     });
951   }());
952
953   /*--------------------------------------------------------------------------*/
954
955   QUnit.module('fp.flow and fp.flowRight');
956
957   _.each(['flow', 'flowRight'], function(methodName) {
958     var func = fp[methodName],
959         isFlow = methodName == 'flow';
960
961     QUnit.test('`fp.' + methodName + '` should support shortcut fusion', function(assert) {
962       assert.expect(6);
963
964       var filterCount,
965           mapCount,
966           array = fp.range(0, LARGE_ARRAY_SIZE);
967
968       var iteratee = function(value) {
969         mapCount++;
970         return value * value;
971       };
972
973       var predicate = function(value) {
974         filterCount++;
975         return value % 2 == 0;
976       };
977
978       var filter = fp.filter(predicate),
979           map = fp.map(iteratee),
980           take = fp.take(2);
981
982       _.times(2, function(index) {
983         var combined = isFlow
984           ? func(map, filter, fp.compact, take)
985           : func(take, fp.compact, filter, map);
986
987         filterCount = mapCount = 0;
988
989         if (WeakMap && WeakMap.name) {
990           assert.deepEqual(combined(array), [4, 16]);
991           assert.strictEqual(filterCount, 5, 'filterCount');
992           assert.strictEqual(mapCount, 5, 'mapCount');
993         }
994         else {
995           skipAssert(assert, 3);
996         }
997       });
998     });
999   });
1000   /*--------------------------------------------------------------------------*/
1001
1002   QUnit.module('fp.getOr');
1003
1004   QUnit.test('should accept a `defaultValue` param', function(assert) {
1005     assert.expect(1);
1006
1007     var actual = fp.getOr('default')('path')({});
1008     assert.strictEqual(actual, 'default');
1009   });
1010
1011   /*--------------------------------------------------------------------------*/
1012
1013   QUnit.module('fp.gt and fp.gte');
1014
1015   _.each(['gt', 'gte'], function(methodName) {
1016     var func = fp[methodName];
1017
1018     QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
1019       assert.expect(1);
1020
1021       assert.strictEqual(func(2)(1), true);
1022     });
1023   });
1024
1025   /*--------------------------------------------------------------------------*/
1026
1027   QUnit.module('fp.inRange');
1028
1029   (function() {
1030     QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) {
1031       assert.expect(2);
1032
1033       assert.strictEqual(fp.inRange(2)(4)(3), true);
1034       assert.strictEqual(fp.inRange(-2)(-6)(-3), true);
1035     });
1036   }());
1037
1038   /*--------------------------------------------------------------------------*/
1039
1040   QUnit.module('fp.iteratee');
1041
1042   (function() {
1043     QUnit.test('should return a iteratee with capped params', function(assert) {
1044       assert.expect(1);
1045
1046       var func = fp.iteratee(function(a, b, c) { return [a, b, c]; }, 3);
1047       assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]);
1048     });
1049
1050     QUnit.test('should convert by name', function(assert) {
1051       assert.expect(1);
1052
1053       var iteratee = convert('iteratee', _.iteratee),
1054           func = iteratee(function(a, b, c) { return [a, b, c]; }, 3);
1055
1056       assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]);
1057     });
1058   }());
1059
1060   /*--------------------------------------------------------------------------*/
1061
1062   QUnit.module('fp.lt and fp.lte');
1063
1064   _.each(['lt', 'lte'], function(methodName) {
1065     var func = fp[methodName];
1066
1067     QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
1068       assert.expect(1);
1069
1070       assert.strictEqual(func(1)(2), true);
1071     });
1072   });
1073
1074   /*--------------------------------------------------------------------------*/
1075
1076   QUnit.module('fp.mapKeys');
1077
1078   (function() {
1079     QUnit.test('should only provide `key` to `iteratee`', function(assert) {
1080       assert.expect(1);
1081
1082       var args,
1083           object = { 'a': 1 };
1084
1085       var actual = fp.mapKeys(function() {
1086         args || (args = slice.call(arguments));
1087       }, object);
1088
1089       assert.deepEqual(args, ['a']);
1090     });
1091   }());
1092
1093   /*--------------------------------------------------------------------------*/
1094
1095   QUnit.module('fp.maxBy and fp.minBy');
1096
1097   _.each(['maxBy', 'minBy'], function(methodName) {
1098     var array = [1, 2, 3],
1099         func = fp[methodName],
1100         isMax = methodName == 'maxBy';
1101
1102     QUnit.test('`fp.' + methodName + '` should work with an `iteratee` argument', function(assert) {
1103       assert.expect(1);
1104
1105       var actual = func(function(num) {
1106         return -num;
1107       })(array);
1108
1109       assert.strictEqual(actual, isMax ? 1 : 3);
1110     });
1111
1112     QUnit.test('`fp.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) {
1113       assert.expect(1);
1114
1115       var args;
1116
1117       func(function() {
1118         args || (args = slice.call(arguments));
1119       })(array);
1120
1121       assert.deepEqual(args, [1]);
1122     });
1123   });
1124
1125   /*--------------------------------------------------------------------------*/
1126
1127   QUnit.module('fp.mixin');
1128
1129   (function() {
1130     var source = { 'a': _.noop };
1131
1132     QUnit.test('should mixin static methods but not prototype methods', function(assert) {
1133       assert.expect(2);
1134
1135       fp.mixin(source);
1136
1137       assert.strictEqual(typeof fp.a, 'function');
1138       assert.notOk('a' in fp.prototype);
1139
1140       delete fp.a;
1141       delete fp.prototype.a;
1142     });
1143
1144     QUnit.test('should not assign inherited `source` methods', function(assert) {
1145       assert.expect(2);
1146
1147       function Foo() {}
1148       Foo.prototype.a = _.noop;
1149       fp.mixin(new Foo);
1150
1151       assert.notOk('a' in fp);
1152       assert.notOk('a' in fp.prototype);
1153
1154       delete fp.a;
1155       delete fp.prototype.a;
1156     });
1157
1158     QUnit.test('should not remove existing prototype methods', function(assert) {
1159       assert.expect(2);
1160
1161       var each1 = fp.each,
1162           each2 = fp.prototype.each;
1163
1164       fp.mixin({ 'each': source.a });
1165
1166       assert.strictEqual(fp.each, source.a);
1167       assert.strictEqual(fp.prototype.each, each2);
1168
1169       fp.each = each1;
1170       fp.prototype.each = each2;
1171     });
1172
1173     QUnit.test('should not export to the global when `source` is not an object', function(assert) {
1174       assert.expect(2);
1175
1176       var props = _.without(_.keys(_), '_');
1177
1178       _.times(2, function(index) {
1179         fp.mixin.apply(fp, index ? [1] : []);
1180
1181         assert.ok(_.every(props, function(key) {
1182           return root[key] !== fp[key];
1183         }));
1184
1185         _.each(props, function(key) {
1186           if (root[key] === fp[key]) {
1187             delete root[key];
1188           }
1189         });
1190       });
1191     });
1192
1193     QUnit.test('should convert by name', function(assert) {
1194       assert.expect(3);
1195
1196       var object = { 'mixin': convert('mixin', _.mixin) };
1197
1198       function Foo() {}
1199       Foo.mixin = object.mixin;
1200       Foo.mixin(source);
1201
1202       assert.strictEqual(typeof Foo.a, 'function');
1203       assert.notOk('a' in Foo.prototype);
1204
1205       object.mixin(source);
1206       assert.strictEqual(typeof object.a, 'function');
1207     });
1208   }());
1209
1210   /*--------------------------------------------------------------------------*/
1211
1212   QUnit.module('fp.omitBy and fp.pickBy');
1213
1214   _.each(['omitBy', 'pickBy'], function(methodName) {
1215     var func = fp[methodName];
1216
1217     QUnit.test('`fp.' + methodName + '` should provide `value` and `key` to `iteratee`', function(assert) {
1218       assert.expect(1);
1219
1220       var args,
1221           object = { 'a': 1 };
1222
1223       func(function() {
1224         args || (args = slice.call(arguments));
1225       })(object);
1226
1227       assert.deepEqual(args, [1, 'a']);
1228     });
1229   });
1230
1231   /*--------------------------------------------------------------------------*/
1232
1233   QUnit.module('fp.partial and fp.partialRight');
1234
1235   _.each(['partial', 'partialRight'], function(methodName) {
1236     var func = fp[methodName],
1237         isPartial = methodName == 'partial';
1238
1239     QUnit.test('`_.' + methodName + '` should accept an `args` param', function(assert) {
1240       assert.expect(1);
1241
1242       var expected = isPartial ? [1, 2, 3] : [0, 1, 2];
1243
1244       var actual = func(function(a, b, c) {
1245         return [a, b, c];
1246       })([1, 2])(isPartial ? 3 : 0);
1247
1248       assert.deepEqual(actual, expected);
1249     });
1250
1251     QUnit.test('`_.' + methodName + '` should convert by name', function(assert) {
1252       assert.expect(2);
1253
1254       var expected = isPartial ? [1, 2, 3] : [0, 1, 2],
1255           par = convert(methodName, _[methodName]),
1256           ph = par.placeholder;
1257
1258       var actual = par(function(a, b, c) {
1259         return [a, b, c];
1260       })([1, 2])(isPartial ? 3 : 0);
1261
1262       assert.deepEqual(actual, expected);
1263
1264       actual = par(function(a, b, c) {
1265         return [a, b, c];
1266       })([ph, 2])(isPartial ? 1 : 0, isPartial ? 3 : 1);
1267
1268       assert.deepEqual(actual, expected);
1269     });
1270   });
1271
1272   /*--------------------------------------------------------------------------*/
1273
1274   QUnit.module('fp.random');
1275
1276   (function() {
1277     var array = Array(1000);
1278
1279     QUnit.test('should support a `min` and `max` argument', function(assert) {
1280       assert.expect(1);
1281
1282       var min = 5,
1283           max = 10;
1284
1285       assert.ok(_.some(array, function() {
1286         var result = fp.random(min)(max);
1287         return result >= min && result <= max;
1288       }));
1289     });
1290   }());
1291
1292   /*--------------------------------------------------------------------------*/
1293
1294   QUnit.module('fp.range');
1295
1296   (function() {
1297     QUnit.test('should have an argument order of `start` then `end`', function(assert) {
1298       assert.expect(1);
1299
1300       assert.deepEqual(fp.range(1)(4), [1, 2, 3]);
1301     });
1302   }());
1303
1304   /*--------------------------------------------------------------------------*/
1305
1306   QUnit.module('fp.reduce and fp.reduceRight');
1307
1308   _.each(['reduce', 'reduceRight'], function(methodName) {
1309     var func = fp[methodName],
1310         isReduce = methodName == 'reduce';
1311
1312     QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an array', function(assert) {
1313       assert.expect(1);
1314
1315       var args,
1316           array = [1, 2, 3];
1317
1318       func(function() {
1319         args || (args = slice.call(arguments));
1320       })(0)(array);
1321
1322       assert.deepEqual(args, isReduce ? [0, 1] : [0, 3]);
1323     });
1324
1325     QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an object', function(assert) {
1326       assert.expect(1);
1327
1328       var args,
1329           object = { 'a': 1, 'b': 2 },
1330           isFIFO = _.keys(object)[0] == 'a';
1331
1332       var expected = isFIFO
1333         ? (isReduce ? [0, 1] : [0, 2])
1334         : (isReduce ? [0, 2] : [0, 1]);
1335
1336       func(function() {
1337         args || (args = slice.call(arguments));
1338       })(0)(object);
1339
1340       assert.deepEqual(args, expected);
1341     });
1342   });
1343
1344   /*--------------------------------------------------------------------------*/
1345
1346   QUnit.module('fp.runInContext');
1347
1348   (function() {
1349     QUnit.test('should return a converted lodash instance', function(assert) {
1350       assert.expect(1);
1351
1352       assert.strictEqual(typeof fp.runInContext({}).curryN, 'function');
1353     });
1354
1355     QUnit.test('should convert by name', function(assert) {
1356       assert.expect(1);
1357
1358       var runInContext = convert('runInContext', _.runInContext);
1359       assert.strictEqual(typeof runInContext({}).curryN, 'function');
1360     });
1361   }());
1362
1363   /*--------------------------------------------------------------------------*/
1364
1365   QUnit.module('fp.trimChars');
1366
1367   _.each(['trimChars', 'trimCharsStart', 'trimCharsEnd'], function(methodName, index) {
1368     var func = fp[methodName],
1369         parts = [];
1370
1371     if (index != 2) {
1372       parts.push('leading');
1373     }
1374     if (index != 1) {
1375       parts.push('trailing');
1376     }
1377     parts = parts.join(' and ');
1378
1379     QUnit.test('`_.' + methodName + '` should remove ' + parts + ' `chars`', function(assert) {
1380       assert.expect(1);
1381
1382       var string = '-_-a-b-c-_-',
1383           expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : '');
1384
1385       assert.strictEqual(func('_-')(string), expected);
1386     });
1387   });
1388
1389   /*--------------------------------------------------------------------------*/
1390
1391   QUnit.module('fp.uniqBy');
1392
1393   (function() {
1394     var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }];
1395
1396     QUnit.test('should work with an `iteratee` argument', function(assert) {
1397       assert.expect(1);
1398
1399       var expected = objects.slice(0, 3);
1400
1401       var actual = fp.uniqBy(function(object) {
1402         return object.a;
1403       })(objects);
1404
1405       assert.deepEqual(actual, expected);
1406     });
1407
1408     QUnit.test('should provide the correct `iteratee` arguments', function(assert) {
1409       assert.expect(1);
1410
1411       var args;
1412
1413       fp.uniqBy(function() {
1414         args || (args = slice.call(arguments));
1415       })(objects);
1416
1417       assert.deepEqual(args, [objects[0]]);
1418     });
1419   }());
1420
1421   /*--------------------------------------------------------------------------*/
1422
1423   QUnit.module('fp.zip');
1424
1425   (function() {
1426     QUnit.test('should zip together two arrays', function(assert) {
1427       assert.expect(1);
1428
1429       assert.deepEqual(fp.zip([1, 2])([3, 4]), [[1, 3], [2, 4]]);
1430     });
1431   }());
1432
1433   /*--------------------------------------------------------------------------*/
1434
1435   QUnit.module('fp.zipObject');
1436
1437   (function() {
1438     QUnit.test('should zip together key/value arrays into an object', function(assert) {
1439       assert.expect(1);
1440
1441       assert.deepEqual(fp.zipObject(['a', 'b'])([1, 2]), { 'a': 1, 'b': 2 });
1442     });
1443   }());
1444
1445   /*--------------------------------------------------------------------------*/
1446
1447   QUnit.module('fp.zipWith');
1448
1449   (function() {
1450     QUnit.test('should zip arrays combining grouped elements with `iteratee`', function(assert) {
1451       assert.expect(1);
1452
1453       var array1 = [1, 2, 3],
1454           array2 = [4, 5, 6];
1455
1456       var actual = fp.zipWith(function(a, b) {
1457         return a + b;
1458       })(array1)(array2);
1459
1460       assert.deepEqual(actual, [5, 7, 9]);
1461     });
1462   }());
1463
1464   /*--------------------------------------------------------------------------*/
1465
1466   QUnit.config.asyncRetries = 10;
1467   QUnit.config.hidepassed = true;
1468
1469   if (!document) {
1470     QUnit.config.noglobals = true;
1471     QUnit.load();
1472   }
1473 }.call(this));