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