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