3 /** Used as a safe reference for `undefined` in pre-ES5 environments. */
6 /** Used as the size to cover large array optimizations. */
7 var LARGE_ARRAY_SIZE = 200;
9 /** Used as a reference to the global object. */
10 var root = (typeof global == 'object' && global) || this;
12 /** Used for native method references. */
13 var arrayProto = Array.prototype;
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,
21 slice = arrayProto.slice,
22 WeakMap = root.WeakMap;
24 // Leak to avoid sporadic `noglobals` fails on Edge in Sauce Labs.
25 root.msWDfn = undefined;
27 /*--------------------------------------------------------------------------*/
29 /** Use a single "load" function. */
30 var load = (!amd && typeof require == 'function')
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
40 /** Load stable Lodash and QUnit Extras. */
41 var _ = root._ || (root._ = (
42 _ = load('../lodash.js'),
46 var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js');
48 QUnitExtras.runInContext(root);
51 var convert = (function() {
52 var baseConvert = root.fp || load('../fp/_baseConvert.js');
54 return function(name, func, options) {
55 return baseConvert(_, name, func, options);
58 return function(name, func, options) {
59 if (typeof name == 'function') {
64 return name === undefined
65 ? baseConvert(func, options)
66 : baseConvert(_.runInContext(), options)[name];
70 var allFalseOptions = {
79 ? (fp = _.noConflict(), _ = root._, fp)
80 : convert(_.runInContext());
82 var mapping = root.mapping || load('../fp/_mapping.js');
84 /*--------------------------------------------------------------------------*/
87 * Skips a given number of tests with a passing result.
90 * @param {Object} assert The QUnit assert object.
91 * @param {number} [count=1] The number of tests to skip.
93 function skipAssert(assert, count) {
96 assert.ok(true, 'test skipped');
100 /*--------------------------------------------------------------------------*/
103 console.log('Running lodash/fp tests.');
106 QUnit.module('convert module');
109 QUnit.test('should work with `name` and `func`', function(assert) {
112 var array = [1, 2, 3, 4],
113 remove = convert('remove', _.remove);
115 var actual = remove(function(n) {
119 assert.deepEqual(array, [1, 2, 3, 4]);
120 assert.deepEqual(actual, [1, 3]);
123 QUnit.test('should work with `name`, `func`, and `options`', function(assert) {
126 var array = [1, 2, 3, 4],
127 remove = convert('remove', _.remove, allFalseOptions);
129 var actual = remove(array, function(n, index) {
130 return index % 2 == 0;
133 assert.deepEqual(array, [2, 4]);
134 assert.deepEqual(actual, [1, 3]);
135 assert.deepEqual(remove(), []);
138 QUnit.test('should work with an object', function(assert) {
142 var array = [1, 2, 3, 4],
143 lodash = convert({ 'remove': _.remove });
145 var actual = lodash.remove(function(n) {
149 assert.deepEqual(array, [1, 2, 3, 4]);
150 assert.deepEqual(actual, [1, 3]);
153 skipAssert(assert, 2);
157 QUnit.test('should work with an object and `options`', function(assert) {
161 var array = [1, 2, 3, 4],
162 lodash = convert({ 'remove': _.remove }, allFalseOptions);
164 var actual = lodash.remove(array, function(n, index) {
165 return index % 2 == 0;
168 assert.deepEqual(array, [2, 4]);
169 assert.deepEqual(actual, [1, 3]);
170 assert.deepEqual(lodash.remove(), []);
173 skipAssert(assert, 3);
177 QUnit.test('should work with lodash and `options`', function(assert) {
180 var array = [1, 2, 3, 4],
181 lodash = convert(_.runInContext(), allFalseOptions);
183 var actual = lodash.remove(array, function(n, index) {
184 return index % 2 == 0;
187 assert.deepEqual(array, [2, 4]);
188 assert.deepEqual(actual, [1, 3]);
189 assert.deepEqual(lodash.remove(), []);
192 QUnit.test('should work with `runInContext` and `options`', function(assert) {
195 var array = [1, 2, 3, 4],
196 runInContext = convert('runInContext', _.runInContext, allFalseOptions),
197 lodash = runInContext();
199 var actual = lodash.remove(array, function(n, index) {
200 return index % 2 == 0;
203 assert.deepEqual(array, [2, 4]);
204 assert.deepEqual(actual, [1, 3]);
205 assert.deepEqual(lodash.remove(), []);
208 QUnit.test('should accept a variety of options', function(assert) {
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);
217 assert.deepEqual(value, [1, 2, 3, 4]);
218 assert.deepEqual(actual, [2, 4]);
220 remove = convert('remove', _.remove, { 'curry': false });
221 actual = remove(predicate);
223 assert.deepEqual(actual, []);
225 var trim = convert('trim', _.trim, { 'fixed': false });
226 assert.strictEqual(trim('_-abc-_', '_-'), 'abc');
228 value = _.clone(array);
229 remove = convert('remove', _.remove, { 'immutable': false });
230 actual = remove(predicate)(value);
232 assert.deepEqual(value, [1, 3]);
233 assert.deepEqual(actual, [2, 4]);
235 value = _.clone(array);
236 remove = convert('remove', _.remove, { 'rearg': false });
237 actual = remove(value)(predicate);
239 assert.deepEqual(value, [1, 2, 3, 4]);
240 assert.deepEqual(actual, [1, 3]);
243 QUnit.test('should respect the `cap` option', function(assert) {
246 var iteratee = convert('iteratee', _.iteratee, { 'cap': false });
248 var func = iteratee(function(a, b, c) {
252 assert.deepEqual(func(1, 2, 3), [1, 2, 3]);
255 QUnit.test('should respect the `rearg` option', function(assert) {
258 var add = convert('add', _.add, { 'rearg': true });
260 assert.strictEqual(add('2')('1'), '12');
263 QUnit.test('should only add a `placeholder` property if needed', function(assert) {
267 var methodNames = _.keys(mapping.placeholder),
268 expected = _.map(methodNames, _.constant(true));
270 var actual = _.map(methodNames, function(methodName) {
272 object[methodName] = _[methodName];
274 var lodash = convert(object);
275 return methodName in lodash;
278 assert.deepEqual(actual, expected);
280 var lodash = convert({ 'add': _.add });
281 assert.notOk('placeholder' in lodash);
284 skipAssert(assert, 2);
289 /*--------------------------------------------------------------------------*/
291 QUnit.module('method.convert');
294 QUnit.test('should exist on unconverted methods', function(assert) {
298 isArray = fp.isArray.convert({ 'curry': true });
300 assert.strictEqual(fp.isArray(array), true);
301 assert.strictEqual(isArray()(array), true);
305 /*--------------------------------------------------------------------------*/
307 QUnit.module('convert methods');
309 _.each(['fp.convert', 'method.convert'], function(methodName) {
310 var isFp = methodName == 'fp.convert',
311 func = isFp ? fp.convert : fp.remove.convert;
313 QUnit.test('`' + methodName + '` should work with an object', function(assert) {
316 var array = [1, 2, 3, 4],
317 lodash = func(allFalseOptions),
318 remove = isFp ? lodash.remove : lodash;
320 var actual = remove(array, function(n, index) {
321 return index % 2 == 0;
324 assert.deepEqual(array, [2, 4]);
325 assert.deepEqual(actual, [1, 3]);
326 assert.deepEqual(remove(), []);
329 QUnit.test('`' + methodName + '` should extend existing configs', function(assert) {
332 var array = [1, 2, 3, 4],
333 lodash = func({ 'cap': false }),
334 remove = (isFp ? lodash.remove : lodash).convert({ 'rearg': false });
336 var actual = remove(array)(function(n, index) {
337 return index % 2 == 0;
340 assert.deepEqual(array, [1, 2, 3, 4]);
341 assert.deepEqual(actual, [2, 4]);
345 /*--------------------------------------------------------------------------*/
347 QUnit.module('method arity checks');
350 QUnit.test('should wrap methods with an arity > `1`', function(assert) {
353 var methodNames = _.filter(_.functions(fp), function(methodName) {
354 return fp[methodName].length > 1;
357 assert.deepEqual(methodNames, []);
360 QUnit.test('should have >= arity of `aryMethod` designation', function(assert) {
363 _.times(4, function(index) {
364 var aryCap = index + 1;
366 var methodNames = _.filter(mapping.aryMethod[aryCap], function(methodName) {
367 var key = _.result(mapping.remap, methodName, methodName),
368 arity = _[key].length;
370 return arity != 0 && arity < aryCap;
373 assert.deepEqual(methodNames, [], '`aryMethod[' + aryCap + ']`');
378 /*--------------------------------------------------------------------------*/
380 QUnit.module('method aliases');
383 QUnit.test('should have correct aliases', function(assert) {
386 var actual = _.transform(mapping.aliasToReal, function(result, realName, alias) {
387 result.push([alias, fp[alias] === fp[realName]]);
390 assert.deepEqual(_.reject(actual, 1), []);
394 /*--------------------------------------------------------------------------*/
396 QUnit.module('method ary caps');
399 QUnit.test('should have a cap of 1', function(assert) {
403 'curry', 'iteratee', 'memoize', 'over', 'overEvery', 'overSome',
404 'method', 'methodOf', 'rest', 'runInContext'
407 var exceptions = funcMethods.concat('mixin', 'template'),
408 expected = _.map(mapping.aryMethod[1], _.constant(true));
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); });
414 if (_.includes(exceptions, methodName)
415 ? typeof result == 'function'
416 : typeof result != 'function'
420 console.log(methodName, result);
424 assert.deepEqual(actual, expected);
427 QUnit.test('should have a cap of 2', function(assert) {
431 'after', 'ary', 'before', 'bind', 'bindKey', 'curryN', 'debounce',
432 'delay', 'overArgs', 'partial', 'partialRight', 'rearg', 'throttle',
436 var exceptions = _.difference(funcMethods.concat('matchesProperty'), ['cloneDeepWith', 'cloneWith', 'delay']),
437 expected = _.map(mapping.aryMethod[2], _.constant(true));
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]); });
443 if (_.includes(exceptions, methodName)
444 ? typeof result == 'function'
445 : typeof result != 'function'
449 console.log(methodName, result);
453 assert.deepEqual(actual, expected);
456 QUnit.test('should have a cap of 3', function(assert) {
460 'assignWith', 'extendWith', 'isEqualWith', 'isMatchWith', 'reduce',
461 'reduceRight', 'transform', 'zipWith'
464 var expected = _.map(mapping.aryMethod[3], _.constant(true));
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]); });
470 if (typeof result != 'function') {
473 console.log(methodName, result);
477 assert.deepEqual(actual, expected);
481 /*--------------------------------------------------------------------------*/
483 QUnit.module('methods that use `indexOf`');
486 QUnit.test('should work with `fp.indexOf`', function(assert) {
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);
494 assert.deepEqual(actual, ['a', 'c'], 'fp.difference');
496 actual = fp.includes('b')(array);
497 assert.strictEqual(actual, true, 'fp.includes');
499 actual = fp.intersection(other)(array);
500 assert.deepEqual(actual, ['b'], 'fp.intersection');
502 actual = fp.omit(other)(object);
503 assert.deepEqual(actual, { 'a': 1, 'c': 2 }, 'fp.omit');
505 actual = fp.union(other)(array);
506 assert.deepEqual(actual, ['a', 'b', 'c', 'd'], 'fp.union');
508 actual = fp.uniq(other);
509 assert.deepEqual(actual, ['b', 'd'], 'fp.uniq');
511 actual = fp.uniqBy(_.identity, other);
512 assert.deepEqual(actual, ['b', 'd'], 'fp.uniqBy');
514 actual = fp.without(array)(other);
515 assert.deepEqual(actual, ['a', 'c'], 'fp.without');
517 actual = fp.xor(other)(array);
518 assert.deepEqual(actual, ['a', 'c', 'd'], 'fp.xor');
520 actual = fp.pull('b')(array);
521 assert.deepEqual(actual, ['a', 'c'], 'fp.pull');
525 /*--------------------------------------------------------------------------*/
527 QUnit.module('cherry-picked methods');
530 QUnit.test('should provide the correct `iteratee` arguments', function(assert) {
535 object = { 'a': 1, 'b': 2 },
536 isFIFO = _.keys(object)[0] == 'a',
537 map = convert('map', _.map),
538 reduce = convert('reduce', _.reduce);
541 args || (args = slice.call(arguments));
544 assert.deepEqual(args, [1]);
548 args || (args = slice.call(arguments));
551 assert.deepEqual(args, isFIFO ? [1] : [2]);
555 args || (args = slice.call(arguments));
558 assert.deepEqual(args, [0, 1]);
562 args || (args = slice.call(arguments));
565 assert.deepEqual(args, isFIFO ? [0, 1] : [0, 2]);
568 QUnit.test('should not support shortcut fusion', function(assert) {
571 var array = fp.range(0, LARGE_ARRAY_SIZE),
575 var iteratee = function(value) {
577 return value * value;
580 var predicate = function(value) {
582 return value % 2 == 0;
585 var map1 = convert('map', _.map),
586 filter1 = convert('filter', _.filter),
587 take1 = convert('take', _.take);
589 var filter2 = filter1(predicate),
590 map2 = map1(iteratee),
593 var combined = fp.flow(map2, filter2, fp.compact, take2);
595 assert.deepEqual(combined(array), [4, 16]);
596 assert.strictEqual(filterCount, 200, 'filterCount');
597 assert.strictEqual(mapCount, 200, 'mapCount');
601 /*--------------------------------------------------------------------------*/
603 QUnit.module('iteratee shorthands');
606 var objects = [{ 'a': 1, 'b': 2 }, { 'a': 3, 'b': 4 }];
608 QUnit.test('should work with "_.matches" shorthands', function(assert) {
611 assert.deepEqual(fp.filter({ 'a': 3 })(objects), [objects[1]]);
614 QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) {
617 assert.deepEqual(fp.filter(['a', 3])(objects), [objects[1]]);
620 QUnit.test('should work with "_.property" shorthands', function(assert) {
623 assert.deepEqual(fp.map('a')(objects), [1, 3]);
627 /*--------------------------------------------------------------------------*/
629 QUnit.module('mutation methods');
632 var array = [1, 2, 3],
634 deepObject = { 'a': { 'b': 2, 'c': 3 } };
636 QUnit.test('should not mutate values', function(assert) {
640 Foo.prototype = { 'b': 2 };
642 var value = _.clone(object),
643 actual = fp.assign(value)({ 'b': 2 });
645 assert.deepEqual(value, object, 'fp.assign');
646 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assign');
648 value = _.clone(object);
649 actual = fp.assignWith(function(objValue, srcValue) {
651 })(value)({ 'b': 2 });
653 assert.deepEqual(value, object, 'fp.assignWith');
654 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignWith');
656 value = _.clone(object);
657 actual = fp.assignIn(value)(new Foo);
659 assert.deepEqual(value, object, 'fp.assignIn');
660 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignIn');
662 value = _.clone(object);
663 actual = fp.assignInWith(function(objValue, srcValue) {
667 assert.deepEqual(value, object, 'fp.assignInWith');
668 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignInWith');
670 value = _.clone(object);
671 actual = fp.defaults({ 'a': 2, 'b': 2 })(value);
673 assert.deepEqual(value, object, 'fp.defaults');
674 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.defaults');
676 value = _.cloneDeep(deepObject);
677 actual = fp.defaultsDeep({ 'a': { 'c': 4, 'd': 4 } })(deepObject);
679 assert.deepEqual(value, { 'a': { 'b': 2, 'c': 3 } }, 'fp.defaultsDeep');
680 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3, 'd': 4 } }, 'fp.defaultsDeep');
682 value = _.clone(object);
683 actual = fp.extend(value)(new Foo);
685 assert.deepEqual(value, object, 'fp.extend');
686 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extend');
688 value = _.clone(object);
689 actual = fp.extendWith(function(objValue, srcValue) {
693 assert.deepEqual(value, object, 'fp.extendWith');
694 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extendWith');
696 value = _.clone(array);
697 actual = fp.fill(1)(2)('*')(value);
699 assert.deepEqual(value, array, 'fp.fill');
700 assert.deepEqual(actual, [1, '*', 3], 'fp.fill');
702 value = _.cloneDeep(deepObject);
703 actual = fp.merge(value)({ 'a': { 'd': 4 } });
705 assert.deepEqual(value, { 'a': { 'b': 2, 'c': 3 } }, 'fp.merge');
706 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3, 'd': 4 } }, 'fp.merge');
708 value = _.cloneDeep(deepObject);
711 actual = fp.mergeWith(function(objValue, srcValue) {
712 if (_.isArray(objValue)) {
713 return objValue.concat(srcValue);
715 }, value, { 'a': { 'b': [2, 3] } });
717 assert.deepEqual(value, { 'a': { 'b': [1], 'c': 3 } }, 'fp.mergeWith');
718 assert.deepEqual(actual, { 'a': { 'b': [1, 2, 3], 'c': 3 } }, 'fp.mergeWith');
720 value = _.clone(array);
721 actual = fp.pull(2)(value);
723 assert.deepEqual(value, array, 'fp.pull');
724 assert.deepEqual(actual, [1, 3], 'fp.pull');
726 value = _.clone(array);
727 actual = fp.pullAll([1, 3])(value);
729 assert.deepEqual(value, array, 'fp.pullAll');
730 assert.deepEqual(actual, [2], 'fp.pullAll');
732 value = _.clone(array);
733 actual = fp.pullAt([0, 2])(value);
735 assert.deepEqual(value, array, 'fp.pullAt');
736 assert.deepEqual(actual, [2], 'fp.pullAt');
738 value = _.clone(array);
739 actual = fp.remove(function(value) {
743 assert.deepEqual(value, array, 'fp.remove');
744 assert.deepEqual(actual, [1, 3], 'fp.remove');
746 value = _.clone(array);
747 actual = fp.reverse(value);
749 assert.deepEqual(value, array, 'fp.reverse');
750 assert.deepEqual(actual, [3, 2, 1], 'fp.reverse');
752 value = _.cloneDeep(deepObject);
753 actual = fp.set('a.b')(3)(value);
755 assert.deepEqual(value, deepObject, 'fp.set');
756 assert.deepEqual(actual, { 'a': { 'b': 3, 'c': 3 } }, 'fp.set');
758 value = _.cloneDeep(deepObject);
759 actual = fp.setWith(Object)('d.e')(4)(value);
761 assert.deepEqual(value, deepObject, 'fp.setWith');
762 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }, 'fp.setWith');
764 value = _.cloneDeep(deepObject);
765 actual = fp.unset('a.b')(value);
767 assert.deepEqual(value, deepObject, 'fp.unset');
768 assert.deepEqual(actual, { 'a': { 'c': 3 } }, 'fp.unset');
770 value = _.cloneDeep(deepObject);
771 actual = fp.update('a.b')(function(n) { return n * n; })(value);
773 assert.deepEqual(value, deepObject, 'fp.update');
774 assert.deepEqual(actual, { 'a': { 'b': 4, 'c': 3 } }, 'fp.update');
776 value = _.cloneDeep(deepObject);
777 actual = fp.updateWith(Object)('d.e')(_.constant(4))(value);
779 assert.deepEqual(value, deepObject, 'fp.updateWith');
780 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }, 'fp.updateWith');
784 /*--------------------------------------------------------------------------*/
786 QUnit.module('placeholder methods');
789 QUnit.test('should use `fp` as the default placeholder', function(assert) {
792 var actual = fp.add(fp, 'b')('a');
793 assert.strictEqual(actual, 'ab');
795 actual = fp.slice(fp, 2)(1)(['a', 'b', 'c']);
796 assert.deepEqual(actual, ['b']);
798 actual = fp.fill(fp, 2)(1, '*')([1, 2, 3]);
799 assert.deepEqual(actual, [1, '*', 3]);
802 QUnit.test('should support `fp.placeholder`', function(assert) {
805 _.each([[], fp.__], function(ph) {
808 var actual = fp.add(ph, 'b')('a');
809 assert.strictEqual(actual, 'ab');
811 actual = fp.slice(ph, 2)(1)(['a', 'b', 'c']);
812 assert.deepEqual(actual, ['b']);
814 actual = fp.fill(ph, 2)(1, '*')([1, 2, 3]);
815 assert.deepEqual(actual, [1, '*', 3]);
819 _.forOwn(mapping.placeholder, function(truthy, methodName) {
820 var func = fp[methodName];
822 QUnit.test('`_.' + methodName + '` should have a `placeholder` property', function(assert) {
825 assert.ok(_.isObject(func.placeholder));
826 assert.strictEqual(func.placeholder, fp.__);
831 /*--------------------------------------------------------------------------*/
833 QUnit.module('set methods');
836 QUnit.test('should only clone objects in `path`', function(assert) {
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);
843 assert.ok(_.isObject(actual.a.b), 'fp.set');
844 assert.ok(_.isNumber(actual.a.b), 'fp.set');
846 assert.strictEqual(actual.a.b.c.d, 5, 'fp.set');
847 assert.strictEqual(actual.d, value.d, 'fp.set');
849 value = _.cloneDeep(object);
850 actual = fp.setWith(Object)('[0][1]')('a')(value);
852 assert.deepEqual(actual[0], { '1': 'a' }, 'fp.setWith');
854 value = _.cloneDeep(object);
855 actual = fp.unset('a.b')(value);
857 assert.notOk('b' in actual.a, 'fp.unset');
858 assert.strictEqual(actual.a.c, value.a.c, 'fp.unset');
860 value = _.cloneDeep(object);
861 actual = fp.update('a.b')(function(n) { return n * n; })(value);
863 assert.strictEqual(actual.a.b, 4, 'fp.update');
864 assert.strictEqual(actual.d, value.d, 'fp.update');
866 value = _.cloneDeep(object);
867 actual = fp.updateWith(Object)('[0][1]')(_.constant('a'))(value);
869 assert.deepEqual(actual[0], { '1': 'a' }, 'fp.updateWith');
870 assert.strictEqual(actual.d, value.d, 'fp.updateWith');
874 /*--------------------------------------------------------------------------*/
876 QUnit.module('with methods');
879 var object = { 'a': 1 };
881 QUnit.test('should provide the correct `customizer` arguments', function(assert) {
885 value = _.clone(object);
887 fp.assignWith(function() {
888 args || (args = _.map(arguments, _.cloneDeep));
889 })(value)({ 'b': 2 });
891 assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.assignWith');
894 value = _.clone(object);
896 fp.extendWith(function() {
897 args || (args = _.map(arguments, _.cloneDeep));
898 })(value)({ 'b': 2 });
900 assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.extendWith');
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];
909 fp.isEqualWith(function() {
910 if (++iteration == 2) {
911 args = _.map(arguments, _.cloneDeep);
913 })(objects[0])(objects[1]);
915 args[5] = _.omitBy(args[5], _.isFunction);
916 assert.deepEqual(args, expected, 'fp.isEqualWith');
919 stack = { '__data__': { 'array': [], 'map': null } };
920 expected = [2, 1, 'a', objects[1], objects[0], stack];
922 fp.isMatchWith(function() {
923 args || (args = _.map(arguments, _.cloneDeep));
924 })(objects[0])(objects[1]);
926 args[5] = _.omitBy(args[5], _.isFunction);
927 assert.deepEqual(args, expected, 'fp.isMatchWith');
930 value = { 'a': [1] };
931 expected = [[1], [2, 3], 'a', { 'a': [1] }, { 'a': [2, 3] }, stack];
933 fp.mergeWith(function() {
934 args || (args = _.map(arguments, _.cloneDeep));
935 })(value)({ 'a': [2, 3] });
937 args[5] = _.omitBy(args[5], _.isFunction);
938 assert.deepEqual(args, expected, 'fp.mergeWith');
941 value = _.clone(object);
943 fp.setWith(function() {
944 args || (args = _.map(arguments, _.cloneDeep));
947 assert.deepEqual(args, [undefined, 'b', { 'a': 1 }], 'fp.setWith');
950 value = _.clone(object);
952 fp.updateWith(function() {
953 args || (args = _.map(arguments, _.cloneDeep));
954 })('b.c')(_.constant(2))(value);
956 assert.deepEqual(args, [undefined, 'b', { 'a': 1 }], 'fp.updateWith');
960 /*--------------------------------------------------------------------------*/
962 QUnit.module('fp.add and fp.subtract');
964 _.each(['add', 'subtract'], function(methodName) {
965 var func = fp[methodName],
966 isAdd = methodName == 'add';
968 QUnit.test('`fp.' + methodName + '` should not have `rearg` applied', function(assert) {
971 assert.strictEqual(func('1')('2'), isAdd ? '12' : -1);
975 /*--------------------------------------------------------------------------*/
977 QUnit.module('fp.castArray');
980 QUnit.test('should shallow clone array values', function(assert) {
984 actual = fp.castArray(array);
986 assert.deepEqual(actual, array);
987 assert.notStrictEqual(actual, array);
990 QUnit.test('should not shallow clone non-array values', function(assert) {
993 var object = { 'a': 1 },
994 actual = fp.castArray(object);
996 assert.deepEqual(actual, [object]);
997 assert.strictEqual(actual[0], object);
1000 QUnit.test('should convert by name', function(assert) {
1004 object = { 'a': 1 },
1005 castArray = convert('castArray', _.castArray),
1006 actual = castArray(array);
1008 assert.deepEqual(actual, array);
1009 assert.notStrictEqual(actual, array);
1011 actual = castArray(object);
1012 assert.deepEqual(actual, [object]);
1013 assert.strictEqual(actual[0], object);
1017 /*--------------------------------------------------------------------------*/
1019 QUnit.module('fp.curry and fp.curryRight');
1021 _.each(['curry', 'curryRight'], function(methodName) {
1022 var func = fp[methodName];
1024 QUnit.test('`_.' + methodName + '` should only accept a `func` param', function(assert) {
1027 assert.raises(function() { func(1, _.noop); }, TypeError);
1031 /*--------------------------------------------------------------------------*/
1033 QUnit.module('fp.curryN and fp.curryRightN');
1035 _.each(['curryN', 'curryRightN'], function(methodName) {
1036 var func = fp[methodName];
1038 QUnit.test('`_.' + methodName + '` should accept an `arity` param', function(assert) {
1041 var actual = func(1)(function(a, b) { return [a, b]; })('a');
1042 assert.deepEqual(actual, ['a', undefined]);
1046 /*--------------------------------------------------------------------------*/
1048 QUnit.module('fp.difference');
1051 QUnit.test('should return the elements of the first array not included in the second array', function(assert) {
1054 assert.deepEqual(fp.difference([1, 2])([2, 3]), [1]);
1058 /*--------------------------------------------------------------------------*/
1060 QUnit.module('fp.divide and fp.multiply');
1062 _.each(['divide', 'multiply'], function(methodName) {
1063 var func = fp[methodName],
1064 isDivide = methodName == 'divide';
1066 QUnit.test('`fp.' + methodName + '` should not have `rearg` applied', function(assert) {
1069 assert.strictEqual(func('2')('4'), isDivide ? 0.5 : 8);
1073 /*--------------------------------------------------------------------------*/
1075 QUnit.module('fp.extend');
1078 QUnit.test('should convert by name', function(assert) {
1082 Foo.prototype = { 'b': 2 };
1084 var object = { 'a': 1 },
1085 extend = convert('extend', _.extend),
1086 value = _.clone(object),
1087 actual = extend(value)(new Foo);
1089 assert.deepEqual(value, object);
1090 assert.deepEqual(actual, { 'a': 1, 'b': 2 });
1094 /*--------------------------------------------------------------------------*/
1096 QUnit.module('fp.fill');
1099 QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) {
1102 var array = [1, 2, 3];
1103 assert.deepEqual(fp.fill(1)(2)('*')(array), [1, '*', 3]);
1107 /*--------------------------------------------------------------------------*/
1109 QUnit.module('fp.flatMapDepth');
1112 QUnit.test('should have an argument order of `iteratee`, `depth`, then `collection`', function(assert) {
1115 function duplicate(n) {
1120 object = { 'a': 1, 'b': 2 },
1121 expected = [[1, 1], [2, 2]];
1123 assert.deepEqual(fp.flatMapDepth(duplicate)(2)(array), expected);
1124 assert.deepEqual(fp.flatMapDepth(duplicate)(2)(object), expected);
1128 /*--------------------------------------------------------------------------*/
1130 QUnit.module('fp.flow and fp.flowRight');
1132 _.each(['flow', 'flowRight'], function(methodName) {
1133 var func = fp[methodName],
1134 isFlow = methodName == 'flow';
1136 QUnit.test('`fp.' + methodName + '` should support shortcut fusion', function(assert) {
1141 array = fp.range(0, LARGE_ARRAY_SIZE);
1143 var iteratee = function(value) {
1145 return value * value;
1148 var predicate = function(value) {
1150 return value % 2 == 0;
1153 var filter = fp.filter(predicate),
1154 map = fp.map(iteratee),
1157 _.times(2, function(index) {
1158 var combined = isFlow
1159 ? func(map, filter, fp.compact, take)
1160 : func(take, fp.compact, filter, map);
1162 filterCount = mapCount = 0;
1164 if (WeakMap && WeakMap.name) {
1165 assert.deepEqual(combined(array), [4, 16]);
1166 assert.strictEqual(filterCount, 5, 'filterCount');
1167 assert.strictEqual(mapCount, 5, 'mapCount');
1170 skipAssert(assert, 3);
1175 /*--------------------------------------------------------------------------*/
1177 QUnit.module('fp.getOr');
1180 QUnit.test('should accept a `defaultValue` param', function(assert) {
1183 var actual = fp.getOr('default')('path')({});
1184 assert.strictEqual(actual, 'default');
1188 /*--------------------------------------------------------------------------*/
1190 QUnit.module('fp.gt and fp.gte');
1192 _.each(['gt', 'gte'], function(methodName) {
1193 var func = fp[methodName];
1195 QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
1198 assert.strictEqual(func(2)(1), true);
1202 /*--------------------------------------------------------------------------*/
1204 QUnit.module('fp.inRange');
1207 QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) {
1210 assert.strictEqual(fp.inRange(2)(4)(3), true);
1211 assert.strictEqual(fp.inRange(-2)(-6)(-3), true);
1215 /*--------------------------------------------------------------------------*/
1217 QUnit.module('fp.invoke');
1220 QUnit.test('should not accept an `args` param', function(assert) {
1223 var actual = fp.invoke('toUpperCase')('a');
1224 assert.strictEqual(actual, 'A');
1228 /*--------------------------------------------------------------------------*/
1230 QUnit.module('fp.invokeMap');
1233 QUnit.test('should not accept an `args` param', function(assert) {
1236 var actual = fp.invokeMap('toUpperCase')(['a', 'b']);
1237 assert.deepEqual(actual, ['A', 'B']);
1241 /*--------------------------------------------------------------------------*/
1243 QUnit.module('fp.invokeArgs');
1246 QUnit.test('should accept an `args` param', function(assert) {
1249 var actual = fp.invokeArgs('concat')(['b', 'c'])('a');
1250 assert.strictEqual(actual, 'abc');
1254 /*--------------------------------------------------------------------------*/
1256 QUnit.module('fp.invokeArgsMap');
1259 QUnit.test('should accept an `args` param', function(assert) {
1262 var actual = fp.invokeArgsMap('concat')(['b', 'c'])(['a', 'A']);
1263 assert.deepEqual(actual, ['abc', 'Abc']);
1267 /*--------------------------------------------------------------------------*/
1269 QUnit.module('fp.iteratee');
1272 QUnit.test('should return a iteratee with capped params', function(assert) {
1275 var func = fp.iteratee(function(a, b, c) { return [a, b, c]; }, 3);
1276 assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]);
1279 QUnit.test('should convert by name', function(assert) {
1282 var iteratee = convert('iteratee', _.iteratee),
1283 func = iteratee(function(a, b, c) { return [a, b, c]; }, 3);
1285 assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]);
1289 /*--------------------------------------------------------------------------*/
1291 QUnit.module('fp.lt and fp.lte');
1293 _.each(['lt', 'lte'], function(methodName) {
1294 var func = fp[methodName];
1296 QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
1299 assert.strictEqual(func(1)(2), true);
1303 /*--------------------------------------------------------------------------*/
1305 QUnit.module('fp.mapKeys');
1308 QUnit.test('should only provide `key` to `iteratee`', function(assert) {
1312 object = { 'a': 1 };
1314 fp.mapKeys(function() {
1315 args || (args = slice.call(arguments));
1318 assert.deepEqual(args, ['a']);
1322 /*--------------------------------------------------------------------------*/
1324 QUnit.module('fp.maxBy and fp.minBy');
1326 _.each(['maxBy', 'minBy'], function(methodName) {
1327 var array = [1, 2, 3],
1328 func = fp[methodName],
1329 isMax = methodName == 'maxBy';
1331 QUnit.test('`fp.' + methodName + '` should work with an `iteratee` argument', function(assert) {
1334 var actual = func(function(num) {
1338 assert.strictEqual(actual, isMax ? 1 : 3);
1341 QUnit.test('`fp.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) {
1347 args || (args = slice.call(arguments));
1350 assert.deepEqual(args, [1]);
1354 /*--------------------------------------------------------------------------*/
1356 QUnit.module('fp.mixin');
1359 var source = { 'a': _.noop };
1361 QUnit.test('should mixin static methods but not prototype methods', function(assert) {
1366 assert.strictEqual(typeof fp.a, 'function');
1367 assert.notOk('a' in fp.prototype);
1370 delete fp.prototype.a;
1373 QUnit.test('should not assign inherited `source` methods', function(assert) {
1377 Foo.prototype.a = _.noop;
1380 assert.notOk('a' in fp);
1381 assert.notOk('a' in fp.prototype);
1384 delete fp.prototype.a;
1387 QUnit.test('should not remove existing prototype methods', function(assert) {
1390 var each1 = fp.each,
1391 each2 = fp.prototype.each;
1393 fp.mixin({ 'each': source.a });
1395 assert.strictEqual(fp.each, source.a);
1396 assert.strictEqual(fp.prototype.each, each2);
1399 fp.prototype.each = each2;
1402 QUnit.test('should not export to the global when `source` is not an object', function(assert) {
1405 var props = _.without(_.keys(_), '_');
1407 _.times(2, function(index) {
1408 fp.mixin.apply(fp, index ? [1] : []);
1410 assert.ok(_.every(props, function(key) {
1411 return root[key] !== fp[key];
1414 _.each(props, function(key) {
1415 if (root[key] === fp[key]) {
1422 QUnit.test('should convert by name', function(assert) {
1425 var object = { 'mixin': convert('mixin', _.mixin) };
1428 Foo.mixin = object.mixin;
1431 assert.strictEqual(typeof Foo.a, 'function');
1432 assert.notOk('a' in Foo.prototype);
1434 object.mixin(source);
1435 assert.strictEqual(typeof object.a, 'function');
1439 /*--------------------------------------------------------------------------*/
1441 QUnit.module('fp.over');
1444 QUnit.test('should not cap iteratee args', function(assert) {
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]);
1454 /*--------------------------------------------------------------------------*/
1456 QUnit.module('fp.omitBy and fp.pickBy');
1458 _.each(['omitBy', 'pickBy'], function(methodName) {
1459 var func = fp[methodName];
1461 QUnit.test('`fp.' + methodName + '` should provide `value` and `key` to `iteratee`', function(assert) {
1465 object = { 'a': 1 };
1468 args || (args = slice.call(arguments));
1471 assert.deepEqual(args, [1, 'a']);
1475 /*--------------------------------------------------------------------------*/
1477 QUnit.module('padChars methods');
1479 _.each(['padChars', 'padCharsStart', 'padCharsEnd'], function(methodName) {
1480 var func = fp[methodName],
1481 isPad = methodName == 'padChars',
1482 isStart = methodName == 'padCharsStart';
1484 QUnit.test('`_.' + methodName + '` should truncate pad characters to fit the pad length', function(assert) {
1488 assert.strictEqual(func('_-')(8)('abc'), '_-abc_-_');
1490 assert.strictEqual(func('_-')(6)('abc'), isStart ? '_-_abc' : 'abc_-_');
1495 /*--------------------------------------------------------------------------*/
1497 QUnit.module('fp.partial and fp.partialRight');
1499 _.each(['partial', 'partialRight'], function(methodName) {
1500 var func = fp[methodName],
1501 isPartial = methodName == 'partial';
1503 QUnit.test('`_.' + methodName + '` should accept an `args` param', function(assert) {
1506 var expected = isPartial ? [1, 2, 3] : [0, 1, 2];
1508 var actual = func(function(a, b, c) {
1510 })([1, 2])(isPartial ? 3 : 0);
1512 assert.deepEqual(actual, expected);
1515 QUnit.test('`_.' + methodName + '` should convert by name', function(assert) {
1518 var expected = isPartial ? [1, 2, 3] : [0, 1, 2],
1519 par = convert(methodName, _[methodName]),
1520 ph = par.placeholder;
1522 var actual = par(function(a, b, c) {
1524 })([1, 2])(isPartial ? 3 : 0);
1526 assert.deepEqual(actual, expected);
1528 actual = par(function(a, b, c) {
1530 })([ph, 2])(isPartial ? 1 : 0, isPartial ? 3 : 1);
1532 assert.deepEqual(actual, expected);
1536 /*--------------------------------------------------------------------------*/
1538 QUnit.module('fp.random');
1541 var array = Array(1000);
1543 QUnit.test('should support a `min` and `max` argument', function(assert) {
1549 assert.ok(_.some(array, function() {
1550 var result = fp.random(min)(max);
1551 return result >= min && result <= max;
1556 /*--------------------------------------------------------------------------*/
1558 QUnit.module('fp.range');
1561 QUnit.test('should have an argument order of `start` then `end`', function(assert) {
1564 assert.deepEqual(fp.range(1)(4), [1, 2, 3]);
1568 /*--------------------------------------------------------------------------*/
1570 QUnit.module('fp.reduce and fp.reduceRight');
1572 _.each(['reduce', 'reduceRight'], function(methodName) {
1573 var func = fp[methodName],
1574 isReduce = methodName == 'reduce';
1576 QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an array', function(assert) {
1583 args || (args = slice.call(arguments));
1586 assert.deepEqual(args, isReduce ? [0, 1] : [0, 3]);
1589 QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an object', function(assert) {
1593 object = { 'a': 1, 'b': 2 },
1594 isFIFO = _.keys(object)[0] == 'a';
1596 var expected = isFIFO
1597 ? (isReduce ? [0, 1] : [0, 2])
1598 : (isReduce ? [0, 2] : [0, 1]);
1601 args || (args = slice.call(arguments));
1604 assert.deepEqual(args, expected);
1608 /*--------------------------------------------------------------------------*/
1610 QUnit.module('fp.restFrom');
1613 QUnit.test('should accept a `start` param', function(assert) {
1616 var actual = fp.restFrom(2)(function() {
1617 return slice.call(arguments);
1618 })('a', 'b', 'c', 'd');
1620 assert.deepEqual(actual, ['a', 'b', ['c', 'd']]);
1624 /*--------------------------------------------------------------------------*/
1626 QUnit.module('fp.runInContext');
1629 QUnit.test('should return a converted lodash instance', function(assert) {
1632 assert.strictEqual(typeof fp.runInContext({}).curryN, 'function');
1635 QUnit.test('should convert by name', function(assert) {
1638 var runInContext = convert('runInContext', _.runInContext);
1639 assert.strictEqual(typeof runInContext({}).curryN, 'function');
1643 /*--------------------------------------------------------------------------*/
1645 QUnit.module('fp.spreadFrom');
1648 QUnit.test('should accept a `start` param', function(assert) {
1651 var actual = fp.spreadFrom(2)(function() {
1652 return slice.call(arguments);
1653 })('a', 'b', ['c', 'd']);
1655 assert.deepEqual(actual, ['a', 'b', 'c', 'd']);
1659 /*--------------------------------------------------------------------------*/
1661 QUnit.module('trimChars methods');
1663 _.each(['trimChars', 'trimCharsStart', 'trimCharsEnd'], function(methodName, index) {
1664 var func = fp[methodName],
1668 parts.push('leading');
1671 parts.push('trailing');
1673 parts = parts.join(' and ');
1675 QUnit.test('`_.' + methodName + '` should remove ' + parts + ' `chars`', function(assert) {
1678 var string = '-_-a-b-c-_-',
1679 expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : '');
1681 assert.strictEqual(func('_-')(string), expected);
1685 /*--------------------------------------------------------------------------*/
1687 QUnit.module('fp.uniqBy');
1690 var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }];
1692 QUnit.test('should work with an `iteratee` argument', function(assert) {
1695 var expected = objects.slice(0, 3);
1697 var actual = fp.uniqBy(function(object) {
1701 assert.deepEqual(actual, expected);
1704 QUnit.test('should provide the correct `iteratee` arguments', function(assert) {
1709 fp.uniqBy(function() {
1710 args || (args = slice.call(arguments));
1713 assert.deepEqual(args, [objects[0]]);
1717 /*--------------------------------------------------------------------------*/
1719 QUnit.module('fp.zip');
1722 QUnit.test('should zip together two arrays', function(assert) {
1725 assert.deepEqual(fp.zip([1, 2])([3, 4]), [[1, 3], [2, 4]]);
1729 /*--------------------------------------------------------------------------*/
1731 QUnit.module('fp.zipObject');
1734 QUnit.test('should zip together key/value arrays into an object', function(assert) {
1737 assert.deepEqual(fp.zipObject(['a', 'b'])([1, 2]), { 'a': 1, 'b': 2 });
1741 /*--------------------------------------------------------------------------*/
1743 QUnit.module('fp.zipWith');
1746 QUnit.test('should zip arrays combining grouped elements with `iteratee`', function(assert) {
1749 var array1 = [1, 2, 3],
1752 var actual = fp.zipWith(function(a, b) {
1756 assert.deepEqual(actual, [5, 7, 9]);
1760 /*--------------------------------------------------------------------------*/
1762 QUnit.config.asyncRetries = 10;
1763 QUnit.config.hidepassed = true;
1766 QUnit.config.noglobals = true;