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 /*--------------------------------------------------------------------------*/
26 /** Use a single "load" function. */
27 var load = (!amd && typeof require == 'function')
31 /** The unit testing framework. */
32 var QUnit = root.QUnit || (root.QUnit = (
33 QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
34 QUnit = QUnit.QUnit || QUnit
37 /** Load stable Lodash and QUnit Extras. */
38 var _ = root._ || (root._ = (
39 _ = load('../lodash.js'),
43 var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js');
45 QUnitExtras.runInContext(root);
48 var convert = (function() {
49 var baseConvert = root.fp || load('../fp/_baseConvert.js');
51 return function(name, func, options) {
52 return baseConvert(_, name, func, options);
55 return function(name, func, options) {
56 if (typeof name == 'function') {
61 return name === undefined
62 ? baseConvert(func, options)
63 : baseConvert(_.runInContext(), options)[name];
68 ? (fp = _.noConflict(), _ = root._, fp)
69 : convert(_.runInContext());
71 var mapping = root.mapping || load('../fp/_mapping.js');
73 /*--------------------------------------------------------------------------*/
76 * Skips a given number of tests with a passing result.
79 * @param {Object} assert The QUnit assert object.
80 * @param {number} [count=1] The number of tests to skip.
82 function skipAssert(assert, count) {
85 assert.ok(true, 'test skipped');
89 /*--------------------------------------------------------------------------*/
92 console.log('Running lodash/fp tests.');
95 QUnit.module('convert');
98 var allFalseOptions = {
106 QUnit.test('should work when given an object', function(assert) {
110 var array = [1, 2, 3, 4],
111 lodash = convert({ 'remove': _.remove });
113 var actual = lodash.remove(function(n) {
117 assert.deepEqual(array, [1, 2, 3, 4]);
118 assert.deepEqual(actual, [1, 3]);
121 skipAssert(assert, 2);
125 QUnit.test('should only add a `placeholder` property if needed', function(assert) {
129 var methodNames = _.keys(mapping.placeholder),
130 expected = _.map(methodNames, _.constant(true));
132 var actual = _.map(methodNames, function(methodName) {
134 object[methodName] = _[methodName];
136 var lodash = convert(object);
137 return methodName in lodash;
140 assert.deepEqual(actual, expected);
142 var lodash = convert({ 'add': _.add });
143 assert.notOk('placeholder' in lodash);
146 skipAssert(assert, 2);
150 QUnit.test('should accept an `options` argument', function(assert) {
153 var array = [1, 2, 3, 4],
154 remove = convert('remove', _.remove, allFalseOptions);
156 var actual = remove(array, function(n, index) {
157 return index % 2 == 0;
160 assert.deepEqual(array, [2, 4]);
161 assert.deepEqual(actual, [1, 3]);
162 assert.deepEqual(remove(), []);
165 QUnit.test('should accept a variety of options', function(assert) {
168 var array = [1, 2, 3, 4],
169 predicate = function(n) { return n % 2 == 0; },
170 value = _.clone(array),
171 remove = convert('remove', _.remove, { 'cap': false }),
172 actual = remove(function(n, index) { return index % 2 == 0; })(value);
174 assert.deepEqual(value, [1, 2, 3, 4]);
175 assert.deepEqual(actual, [2, 4]);
177 remove = convert('remove', _.remove, { 'curry': false });
178 actual = remove(predicate);
180 assert.deepEqual(actual, []);
182 var trim = convert('trim', _.trim, { 'fixed': false });
183 assert.strictEqual(trim('_-abc-_', '_-'), 'abc');
185 value = _.clone(array);
186 remove = convert('remove', _.remove, { 'immutable': false });
187 actual = remove(predicate)(value);
189 assert.deepEqual(value, [1, 3]);
190 assert.deepEqual(actual, [2, 4]);
192 value = _.clone(array);
193 remove = convert('remove', _.remove, { 'rearg': false });
194 actual = remove(value)(predicate);
196 assert.deepEqual(value, [1, 2, 3, 4]);
197 assert.deepEqual(actual, [1, 3]);
200 QUnit.test('should respect the `cap` option', function(assert) {
203 var iteratee = convert('iteratee', _.iteratee, { 'cap': false });
205 var func = iteratee(function(a, b, c) {
209 assert.deepEqual(func(1, 2, 3), [1, 2, 3]);
212 QUnit.test('should respect the `rearg` option', function(assert) {
215 var add = convert('add', _.add, { 'rearg': true });
217 assert.strictEqual(add('2')('1'), '12');
220 QUnit.test('should use `options` in `runInContext`', function(assert) {
223 var array = [1, 2, 3, 4],
224 runInContext = convert('runInContext', _.runInContext, allFalseOptions),
225 lodash = runInContext();
227 var actual = lodash.remove(array, function(n, index) {
228 return index % 2 == 0;
231 assert.deepEqual(array, [2, 4]);
232 assert.deepEqual(actual, [1, 3]);
233 assert.deepEqual(lodash.remove(), []);
236 QUnit.test('should work when given lodash and `options`', function(assert) {
239 var array = [1, 2, 3, 4],
240 lodash = convert(_.runInContext(), allFalseOptions);
242 var actual = lodash.remove(array, function(n, index) {
243 return index % 2 == 0;
246 assert.deepEqual(array, [2, 4]);
247 assert.deepEqual(actual, [1, 3]);
248 assert.deepEqual(lodash.remove(), []);
251 QUnit.test('should work when given an object and `options`', function(assert) {
255 var array = [1, 2, 3, 4],
256 lodash = convert({ 'remove': _.remove }, allFalseOptions);
258 var actual = lodash.remove(array, function(n, index) {
259 return index % 2 == 0;
262 assert.deepEqual(array, [2, 4]);
263 assert.deepEqual(actual, [1, 3]);
264 assert.deepEqual(lodash.remove(), []);
267 skipAssert(assert, 3);
272 /*--------------------------------------------------------------------------*/
274 QUnit.module('method arity checks');
277 QUnit.test('should wrap methods with an arity > `1`', function(assert) {
280 var methodNames = _.filter(_.functions(fp), function(methodName) {
281 return fp[methodName].length > 1;
284 assert.deepEqual(methodNames, []);
287 QUnit.test('should have >= arity of `aryMethod` designation', function(assert) {
290 _.times(4, function(index) {
291 var aryCap = index + 1;
293 var methodNames = _.filter(mapping.aryMethod[aryCap], function(methodName) {
294 var key = _.result(mapping.remap, methodName, methodName),
295 arity = _[key].length;
297 return arity != 0 && arity < aryCap;
300 assert.deepEqual(methodNames, [], '`aryMethod[' + aryCap + ']`');
305 /*--------------------------------------------------------------------------*/
307 QUnit.module('method aliases');
310 QUnit.test('should have correct aliases', function(assert) {
313 var actual = _.transform(mapping.aliasToReal, function(result, realName, alias) {
314 result.push([alias, fp[alias] === fp[realName]]);
317 assert.deepEqual(_.reject(actual, 1), []);
321 /*--------------------------------------------------------------------------*/
323 QUnit.module('method ary caps');
326 QUnit.test('should have a cap of 1', function(assert) {
330 'curry', 'iteratee', 'memoize', 'over', 'overEvery', 'overSome',
331 'method', 'methodOf', 'rest', 'runInContext'
334 var exceptions = funcMethods.concat('mixin', 'template'),
335 expected = _.map(mapping.aryMethod[1], _.constant(true));
337 var actual = _.map(mapping.aryMethod[1], function(methodName) {
338 var arg = _.includes(funcMethods, methodName) ? _.noop : 1,
339 result = _.attempt(function() { return fp[methodName](arg); });
341 if (_.includes(exceptions, methodName)
342 ? typeof result == 'function'
343 : typeof result != 'function'
347 console.log(methodName, result);
351 assert.deepEqual(actual, expected);
354 QUnit.test('should have a cap of 2', function(assert) {
358 'after', 'ary', 'before', 'bind', 'bindKey', 'curryN', 'debounce', 'delay',
359 'overArgs', 'partial', 'partialRight', 'rearg', 'throttle', 'wrap'
362 var exceptions = _.difference(funcMethods.concat('matchesProperty'), ['cloneDeepWith', 'cloneWith', 'delay']),
363 expected = _.map(mapping.aryMethod[2], _.constant(true));
365 var actual = _.map(mapping.aryMethod[2], function(methodName) {
366 var args = _.includes(funcMethods, methodName) ? [methodName == 'curryN' ? 1 : _.noop, _.noop] : [1, []],
367 result = _.attempt(function() { return fp[methodName](args[0])(args[1]); });
369 if (_.includes(exceptions, methodName)
370 ? typeof result == 'function'
371 : typeof result != 'function'
375 console.log(methodName, result);
379 assert.deepEqual(actual, expected);
382 QUnit.test('should have a cap of 3', function(assert) {
386 'assignWith', 'extendWith', 'isEqualWith', 'isMatchWith', 'reduce',
387 'reduceRight', 'transform', 'zipWith'
390 var expected = _.map(mapping.aryMethod[3], _.constant(true));
392 var actual = _.map(mapping.aryMethod[3], function(methodName) {
393 var args = _.includes(funcMethods, methodName) ? [_.noop, 0, 1] : [0, 1, []],
394 result = _.attempt(function() { return fp[methodName](args[0])(args[1])(args[2]); });
396 if (typeof result != 'function') {
399 console.log(methodName, result);
403 assert.deepEqual(actual, expected);
407 /*--------------------------------------------------------------------------*/
409 QUnit.module('methods that use `indexOf`');
412 QUnit.test('should work with `fp.indexOf`', function(assert) {
415 var array = ['a', 'b', 'c'],
416 other = ['b', 'b', 'd'],
417 object = { 'a': 1, 'b': 2, 'c': 2 },
418 actual = fp.difference(array)(other);
420 assert.deepEqual(actual, ['a', 'c'], 'fp.difference');
422 actual = fp.includes('b')(array);
423 assert.strictEqual(actual, true, 'fp.includes');
425 actual = fp.intersection(other)(array);
426 assert.deepEqual(actual, ['b'], 'fp.intersection');
428 actual = fp.omit(other)(object);
429 assert.deepEqual(actual, { 'a': 1, 'c': 2 }, 'fp.omit');
431 actual = fp.union(other)(array);
432 assert.deepEqual(actual, ['a', 'b', 'c', 'd'], 'fp.union');
434 actual = fp.uniq(other);
435 assert.deepEqual(actual, ['b', 'd'], 'fp.uniq');
437 actual = fp.uniqBy(_.identity, other);
438 assert.deepEqual(actual, ['b', 'd'], 'fp.uniqBy');
440 actual = fp.without('b')(array);
441 assert.deepEqual(actual, ['a', 'c'], 'fp.without');
443 actual = fp.xor(other)(array);
444 assert.deepEqual(actual, ['a', 'c', 'd'], 'fp.xor');
446 actual = fp.pull('b')(array);
447 assert.deepEqual(actual, ['a', 'c'], 'fp.pull');
451 /*--------------------------------------------------------------------------*/
453 QUnit.module('cherry-picked methods');
456 QUnit.test('should provide the correct `iteratee` arguments', function(assert) {
461 object = { 'a': 1, 'b': 2 },
462 isFIFO = _.keys(object)[0] == 'a',
463 map = convert('map', _.map),
464 reduce = convert('reduce', _.reduce);
467 args || (args = slice.call(arguments));
470 assert.deepEqual(args, [1]);
474 args || (args = slice.call(arguments));
477 assert.deepEqual(args, isFIFO ? [1] : [2]);
481 args || (args = slice.call(arguments));
484 assert.deepEqual(args, [0, 1]);
488 args || (args = slice.call(arguments));
491 assert.deepEqual(args, isFIFO ? [0, 1] : [0, 2]);
494 QUnit.test('should not support shortcut fusion', function(assert) {
497 var array = fp.range(0, LARGE_ARRAY_SIZE),
501 var iteratee = function(value) {
503 return value * value;
506 var predicate = function(value) {
508 return value % 2 == 0;
511 var map1 = convert('map', _.map),
512 filter1 = convert('filter', _.filter),
513 take1 = convert('take', _.take);
515 var filter2 = filter1(predicate),
516 map2 = map1(iteratee),
519 var combined = fp.flow(map2, filter2, fp.compact, take2);
521 assert.deepEqual(combined(array), [4, 16]);
522 assert.strictEqual(filterCount, 200, 'filterCount');
523 assert.strictEqual(mapCount, 200, 'mapCount');
527 /*--------------------------------------------------------------------------*/
529 QUnit.module('iteratee shorthands');
532 var objects = [{ 'a': 1, 'b': 2 }, { 'a': 3, 'b': 4 }];
534 QUnit.test('should work with "_.matches" shorthands', function(assert) {
537 assert.deepEqual(fp.filter({ 'a': 3 })(objects), [objects[1]]);
540 QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) {
543 assert.deepEqual(fp.filter(['a', 3])(objects), [objects[1]]);
546 QUnit.test('should work with "_.property" shorthands', function(assert) {
549 assert.deepEqual(fp.map('a')(objects), [1, 3]);
553 /*--------------------------------------------------------------------------*/
555 QUnit.module('mutation methods');
558 var array = [1, 2, 3],
560 deepObject = { 'a': { 'b': 2, 'c': 3 } };
562 QUnit.test('should not mutate values', function(assert) {
566 Foo.prototype = { 'b': 2 };
568 var value = _.clone(object),
569 actual = fp.assign(value)({ 'b': 2 });
571 assert.deepEqual(value, object, 'fp.assign');
572 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assign');
574 value = _.clone(object);
575 actual = fp.assignWith(function(objValue, srcValue) {
577 })(value)({ 'b': 2 });
579 assert.deepEqual(value, object, 'fp.assignWith');
580 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignWith');
582 value = _.clone(object);
583 actual = fp.assignIn(value)(new Foo);
585 assert.deepEqual(value, object, 'fp.assignIn');
586 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignIn');
588 value = _.clone(object);
589 actual = fp.assignInWith(function(objValue, srcValue) {
593 assert.deepEqual(value, object, 'fp.assignInWith');
594 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.assignInWith');
596 value = _.clone(object);
597 actual = fp.defaults({ 'a': 2, 'b': 2 })(value);
599 assert.deepEqual(value, object, 'fp.defaults');
600 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.defaults');
602 value = _.cloneDeep(deepObject);
603 actual = fp.defaultsDeep({ 'a': { 'c': 4, 'd': 4 } })(deepObject);
605 assert.deepEqual(value, { 'a': { 'b': 2, 'c': 3 } }, 'fp.defaultsDeep');
606 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3, 'd': 4 } }, 'fp.defaultsDeep');
608 value = _.clone(object);
609 actual = fp.extend(value)(new Foo);
611 assert.deepEqual(value, object, 'fp.extend');
612 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extend');
614 value = _.clone(object);
615 actual = fp.extendWith(function(objValue, srcValue) {
619 assert.deepEqual(value, object, 'fp.extendWith');
620 assert.deepEqual(actual, { 'a': 1, 'b': 2 }, 'fp.extendWith');
622 value = _.clone(array);
623 actual = fp.fill(1)(2)('*')(value);
625 assert.deepEqual(value, array, 'fp.fill');
626 assert.deepEqual(actual, [1, '*', 3], 'fp.fill');
628 value = _.cloneDeep(deepObject);
629 actual = fp.merge(value)({ 'a': { 'd': 4 } });
631 assert.deepEqual(value, { 'a': { 'b': 2, 'c': 3 } }, 'fp.merge');
632 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3, 'd': 4 } }, 'fp.merge');
634 value = _.cloneDeep(deepObject);
637 actual = fp.mergeWith(function(objValue, srcValue) {
638 if (_.isArray(objValue)) {
639 return objValue.concat(srcValue);
641 }, value, { 'a': { 'b': [2, 3] } });
643 assert.deepEqual(value, { 'a': { 'b': [1], 'c': 3 } }, 'fp.mergeWith');
644 assert.deepEqual(actual, { 'a': { 'b': [1, 2, 3], 'c': 3 } }, 'fp.mergeWith');
646 value = _.clone(array);
647 actual = fp.pull(2)(value);
649 assert.deepEqual(value, array, 'fp.pull');
650 assert.deepEqual(actual, [1, 3], 'fp.pull');
652 value = _.clone(array);
653 actual = fp.pullAll([1, 3])(value);
655 assert.deepEqual(value, array, 'fp.pullAll');
656 assert.deepEqual(actual, [2], 'fp.pullAll');
658 value = _.clone(array);
659 actual = fp.pullAt([0, 2])(value);
661 assert.deepEqual(value, array, 'fp.pullAt');
662 assert.deepEqual(actual, [2], 'fp.pullAt');
664 value = _.clone(array);
665 actual = fp.remove(function(value) {
669 assert.deepEqual(value, array, 'fp.remove');
670 assert.deepEqual(actual, [1, 3], 'fp.remove');
672 value = _.clone(array);
673 actual = fp.reverse(value);
675 assert.deepEqual(value, array, 'fp.reverse');
676 assert.deepEqual(actual, [3, 2, 1], 'fp.reverse');
678 value = _.cloneDeep(deepObject);
679 actual = fp.set('a.b')(3)(value);
681 assert.deepEqual(value, deepObject, 'fp.set');
682 assert.deepEqual(actual, { 'a': { 'b': 3, 'c': 3 } }, 'fp.set');
684 value = _.cloneDeep(deepObject);
685 actual = fp.setWith(Object)('d.e')(4)(value);
687 assert.deepEqual(value, deepObject, 'fp.setWith');
688 assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }, 'fp.setWith');
690 value = _.cloneDeep(deepObject);
691 actual = fp.unset('a.b')(value);
693 assert.deepEqual(value, deepObject, 'fp.unset');
694 assert.deepEqual(actual, { 'a': { 'c': 3 } }, 'fp.unset');
698 /*--------------------------------------------------------------------------*/
700 QUnit.module('placeholder methods');
703 QUnit.test('should support placeholders', function(assert) {
706 _.each([[], fp.__], function(ph) {
709 var actual = fp.add(ph, 'b')('a');
710 assert.strictEqual(actual, 'ab');
712 actual = fp.slice(ph, 2)(1)(['a', 'b', 'c']);
713 assert.deepEqual(actual, ['b']);
715 actual = fp.fill(ph, 2)(1, '*')([1, 2, 3]);
716 assert.deepEqual(actual, [1, '*', 3]);
720 _.forOwn(mapping.placeholder, function(truthy, methodName) {
721 var func = fp[methodName];
723 QUnit.test('`_.' + methodName + '` should have a `placeholder` property', function(assert) {
726 assert.ok(_.isObject(func.placeholder));
727 assert.strictEqual(func.placeholder, fp.__);
732 /*--------------------------------------------------------------------------*/
734 QUnit.module('set methods');
737 var array = [1, 2, 3],
739 deepObject = { 'a': { 'b': 2, 'c': 3 } };
741 QUnit.test('should only clone objects in `path`', function(assert) {
744 var object = { 'a': { 'b': { 'c': 1 }, 'd': { 'e': 1 } } },
745 value = _.cloneDeep(object),
746 actual = fp.set('a.b.c.d.e', 3, value);
748 assert.ok(_.isObject(actual.a.b.c), 'fp.set');
749 assert.ok(_.isNumber(actual.a.b.c), 'fp.set');
751 assert.strictEqual(actual.a.b.c.d.e, 3, 'fp.set');
752 assert.strictEqual(actual.d, value.d, 'fp.set');
754 value = _.cloneDeep(object);
755 actual = fp.setWith(Object)('a.b.c')(2)(value);
757 assert.strictEqual(actual.a.b.c, 2, 'fp.setWith');
758 assert.strictEqual(actual.d, value.d, 'fp.setWith');
760 value = _.cloneDeep(object);
761 actual = fp.unset('a.b')(value);
763 assert.notOk('b' in actual, 'fp.unset');
764 assert.strictEqual(actual.d, value.d, 'fp.unset');
768 /*--------------------------------------------------------------------------*/
770 QUnit.module('with methods');
773 var array = [1, 2, 3],
776 QUnit.test('should provide the correct `customizer` arguments', function(assert) {
780 value = _.clone(object);
782 fp.assignWith(function() {
783 args || (args = _.map(arguments, _.cloneDeep));
784 })(value)({ 'b': 2 });
786 assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.assignWith');
789 value = _.clone(object);
791 fp.extendWith(function() {
792 args || (args = _.map(arguments, _.cloneDeep));
793 })(value)({ 'b': 2 });
795 assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }], 'fp.extendWith');
797 var stack = { '__data__': { 'array': [], 'map': null } },
798 expected = [[1], [2, 3], 'a', { 'a': [1] }, { 'a': [2, 3] }, stack];
801 value = { 'a': [1] };
803 fp.mergeWith(function() {
804 args || (args = _.map(arguments, _.cloneDeep));
805 })(value)({ 'a': [2, 3] });
807 args[5] = _.omitBy(args[5], _.isFunction);
808 assert.deepEqual(args, expected, 'fp.mergeWith');
811 value = _.clone(object);
813 fp.setWith(function() {
814 args || (args = _.map(arguments, _.cloneDeep));
817 assert.deepEqual(args, [undefined, 'b', { 'a': 1 }], 'fp.setWith');
821 /*--------------------------------------------------------------------------*/
823 QUnit.module('fp.add and fp.subtract');
825 _.each(['add', 'subtract'], function(methodName) {
826 var func = fp[methodName],
827 isAdd = methodName == 'add';
829 QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
832 assert.strictEqual(func('1')('2'), isAdd ? '12' : -1);
836 /*--------------------------------------------------------------------------*/
838 QUnit.module('fp.castArray');
841 QUnit.test('should shallow clone array values', function(assert) {
845 actual = fp.castArray(array);
847 assert.deepEqual(actual, array);
848 assert.notStrictEqual(actual, array);
851 QUnit.test('should not shallow clone non-array values', function(assert) {
854 var object = { 'a': 1 },
855 actual = fp.castArray(object);
857 assert.deepEqual(actual, [object]);
858 assert.strictEqual(actual[0], object);
861 QUnit.test('should convert by name', function(assert) {
866 castArray = convert('castArray', _.castArray),
867 actual = castArray(array);
869 assert.deepEqual(actual, array);
870 assert.notStrictEqual(actual, array);
872 actual = castArray(object);
873 assert.deepEqual(actual, [object]);
874 assert.strictEqual(actual[0], object);
878 /*--------------------------------------------------------------------------*/
880 QUnit.module('fp.curry and fp.curryRight');
882 _.each(['curry', 'curryRight'], function(methodName) {
883 var func = fp[methodName];
885 QUnit.test('`_.' + methodName + '` should only accept a `func` param', function(assert) {
888 assert.raises(function() { func(1, _.noop); }, TypeError);
892 /*--------------------------------------------------------------------------*/
894 QUnit.module('fp.curryN and fp.curryRightN');
896 _.each(['curryN', 'curryRightN'], function(methodName) {
897 var func = fp[methodName];
899 QUnit.test('`_.' + methodName + '` should accept an `arity` param', function(assert) {
902 var actual = func(1)(function(a, b) { return [a, b]; })('a');
903 assert.deepEqual(actual, ['a', undefined]);
907 /*--------------------------------------------------------------------------*/
909 QUnit.module('fp.difference');
912 QUnit.test('should return the elements of the first array not included in the second array', function(assert) {
915 assert.deepEqual(fp.difference([1, 2])([2, 3]), [1]);
919 /*--------------------------------------------------------------------------*/
921 QUnit.module('fp.extend');
924 QUnit.test('should convert by name', function(assert) {
928 Foo.prototype = { 'b': 2 };
930 var object = { 'a': 1 },
931 extend = convert('extend', _.extend),
932 value = _.clone(object),
933 actual = extend(value)(new Foo);
935 assert.deepEqual(value, object);
936 assert.deepEqual(actual, { 'a': 1, 'b': 2 });
940 /*--------------------------------------------------------------------------*/
942 QUnit.module('fp.fill');
945 QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) {
948 var array = [1, 2, 3];
949 assert.deepEqual(fp.fill(1)(2)('*')(array), [1, '*', 3]);
953 /*--------------------------------------------------------------------------*/
955 QUnit.module('fp.flow and fp.flowRight');
957 _.each(['flow', 'flowRight'], function(methodName) {
958 var func = fp[methodName],
959 isFlow = methodName == 'flow';
961 QUnit.test('`fp.' + methodName + '` should support shortcut fusion', function(assert) {
966 array = fp.range(0, LARGE_ARRAY_SIZE);
968 var iteratee = function(value) {
970 return value * value;
973 var predicate = function(value) {
975 return value % 2 == 0;
978 var filter = fp.filter(predicate),
979 map = fp.map(iteratee),
982 _.times(2, function(index) {
983 var combined = isFlow
984 ? func(map, filter, fp.compact, take)
985 : func(take, fp.compact, filter, map);
987 filterCount = mapCount = 0;
989 if (WeakMap && WeakMap.name) {
990 assert.deepEqual(combined(array), [4, 16]);
991 assert.strictEqual(filterCount, 5, 'filterCount');
992 assert.strictEqual(mapCount, 5, 'mapCount');
995 skipAssert(assert, 3);
1000 /*--------------------------------------------------------------------------*/
1002 QUnit.module('fp.getOr');
1004 QUnit.test('should accept a `defaultValue` param', function(assert) {
1007 var actual = fp.getOr('default')('path')({});
1008 assert.strictEqual(actual, 'default');
1011 /*--------------------------------------------------------------------------*/
1013 QUnit.module('fp.gt and fp.gte');
1015 _.each(['gt', 'gte'], function(methodName) {
1016 var func = fp[methodName];
1018 QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
1021 assert.strictEqual(func(2)(1), true);
1025 /*--------------------------------------------------------------------------*/
1027 QUnit.module('fp.inRange');
1030 QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) {
1033 assert.strictEqual(fp.inRange(2)(4)(3), true);
1034 assert.strictEqual(fp.inRange(-2)(-6)(-3), true);
1038 /*--------------------------------------------------------------------------*/
1040 QUnit.module('fp.iteratee');
1043 QUnit.test('should return a iteratee with capped params', function(assert) {
1046 var func = fp.iteratee(function(a, b, c) { return [a, b, c]; }, 3);
1047 assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]);
1050 QUnit.test('should convert by name', function(assert) {
1053 var iteratee = convert('iteratee', _.iteratee),
1054 func = iteratee(function(a, b, c) { return [a, b, c]; }, 3);
1056 assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]);
1060 /*--------------------------------------------------------------------------*/
1062 QUnit.module('fp.lt and fp.lte');
1064 _.each(['lt', 'lte'], function(methodName) {
1065 var func = fp[methodName];
1067 QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) {
1070 assert.strictEqual(func(1)(2), true);
1074 /*--------------------------------------------------------------------------*/
1076 QUnit.module('fp.mapKeys');
1079 QUnit.test('should only provide `key` to `iteratee`', function(assert) {
1083 object = { 'a': 1 };
1085 var actual = fp.mapKeys(function() {
1086 args || (args = slice.call(arguments));
1089 assert.deepEqual(args, ['a']);
1093 /*--------------------------------------------------------------------------*/
1095 QUnit.module('fp.maxBy and fp.minBy');
1097 _.each(['maxBy', 'minBy'], function(methodName) {
1098 var array = [1, 2, 3],
1099 func = fp[methodName],
1100 isMax = methodName == 'maxBy';
1102 QUnit.test('`fp.' + methodName + '` should work with an `iteratee` argument', function(assert) {
1105 var actual = func(function(num) {
1109 assert.strictEqual(actual, isMax ? 1 : 3);
1112 QUnit.test('`fp.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) {
1118 args || (args = slice.call(arguments));
1121 assert.deepEqual(args, [1]);
1125 /*--------------------------------------------------------------------------*/
1127 QUnit.module('fp.mixin');
1130 var source = { 'a': _.noop };
1132 QUnit.test('should mixin static methods but not prototype methods', function(assert) {
1137 assert.strictEqual(typeof fp.a, 'function');
1138 assert.notOk('a' in fp.prototype);
1141 delete fp.prototype.a;
1144 QUnit.test('should not assign inherited `source` methods', function(assert) {
1148 Foo.prototype.a = _.noop;
1151 assert.notOk('a' in fp);
1152 assert.notOk('a' in fp.prototype);
1155 delete fp.prototype.a;
1158 QUnit.test('should not remove existing prototype methods', function(assert) {
1161 var each1 = fp.each,
1162 each2 = fp.prototype.each;
1164 fp.mixin({ 'each': source.a });
1166 assert.strictEqual(fp.each, source.a);
1167 assert.strictEqual(fp.prototype.each, each2);
1170 fp.prototype.each = each2;
1173 QUnit.test('should not export to the global when `source` is not an object', function(assert) {
1176 var props = _.without(_.keys(_), '_');
1178 _.times(2, function(index) {
1179 fp.mixin.apply(fp, index ? [1] : []);
1181 assert.ok(_.every(props, function(key) {
1182 return root[key] !== fp[key];
1185 _.each(props, function(key) {
1186 if (root[key] === fp[key]) {
1193 QUnit.test('should convert by name', function(assert) {
1196 var object = { 'mixin': convert('mixin', _.mixin) };
1199 Foo.mixin = object.mixin;
1202 assert.strictEqual(typeof Foo.a, 'function');
1203 assert.notOk('a' in Foo.prototype);
1205 object.mixin(source);
1206 assert.strictEqual(typeof object.a, 'function');
1210 /*--------------------------------------------------------------------------*/
1212 QUnit.module('fp.omitBy and fp.pickBy');
1214 _.each(['omitBy', 'pickBy'], function(methodName) {
1215 var func = fp[methodName];
1217 QUnit.test('`fp.' + methodName + '` should provide `value` and `key` to `iteratee`', function(assert) {
1221 object = { 'a': 1 };
1224 args || (args = slice.call(arguments));
1227 assert.deepEqual(args, [1, 'a']);
1231 /*--------------------------------------------------------------------------*/
1233 QUnit.module('fp.partial and fp.partialRight');
1235 _.each(['partial', 'partialRight'], function(methodName) {
1236 var func = fp[methodName],
1237 isPartial = methodName == 'partial';
1239 QUnit.test('`_.' + methodName + '` should accept an `args` param', function(assert) {
1242 var expected = isPartial ? [1, 2, 3] : [0, 1, 2];
1244 var actual = func(function(a, b, c) {
1246 })([1, 2])(isPartial ? 3 : 0);
1248 assert.deepEqual(actual, expected);
1251 QUnit.test('`_.' + methodName + '` should convert by name', function(assert) {
1254 var expected = isPartial ? [1, 2, 3] : [0, 1, 2],
1255 par = convert(methodName, _[methodName]),
1256 ph = par.placeholder;
1258 var actual = par(function(a, b, c) {
1260 })([1, 2])(isPartial ? 3 : 0);
1262 assert.deepEqual(actual, expected);
1264 actual = par(function(a, b, c) {
1266 })([ph, 2])(isPartial ? 1 : 0, isPartial ? 3 : 1);
1268 assert.deepEqual(actual, expected);
1272 /*--------------------------------------------------------------------------*/
1274 QUnit.module('fp.random');
1277 var array = Array(1000);
1279 QUnit.test('should support a `min` and `max` argument', function(assert) {
1285 assert.ok(_.some(array, function() {
1286 var result = fp.random(min)(max);
1287 return result >= min && result <= max;
1292 /*--------------------------------------------------------------------------*/
1294 QUnit.module('fp.range');
1297 QUnit.test('should have an argument order of `start` then `end`', function(assert) {
1300 assert.deepEqual(fp.range(1)(4), [1, 2, 3]);
1304 /*--------------------------------------------------------------------------*/
1306 QUnit.module('fp.reduce and fp.reduceRight');
1308 _.each(['reduce', 'reduceRight'], function(methodName) {
1309 var func = fp[methodName],
1310 isReduce = methodName == 'reduce';
1312 QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an array', function(assert) {
1319 args || (args = slice.call(arguments));
1322 assert.deepEqual(args, isReduce ? [0, 1] : [0, 3]);
1325 QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an object', function(assert) {
1329 object = { 'a': 1, 'b': 2 },
1330 isFIFO = _.keys(object)[0] == 'a';
1332 var expected = isFIFO
1333 ? (isReduce ? [0, 1] : [0, 2])
1334 : (isReduce ? [0, 2] : [0, 1]);
1337 args || (args = slice.call(arguments));
1340 assert.deepEqual(args, expected);
1344 /*--------------------------------------------------------------------------*/
1346 QUnit.module('fp.runInContext');
1349 QUnit.test('should return a converted lodash instance', function(assert) {
1352 assert.strictEqual(typeof fp.runInContext({}).curryN, 'function');
1355 QUnit.test('should convert by name', function(assert) {
1358 var runInContext = convert('runInContext', _.runInContext);
1359 assert.strictEqual(typeof runInContext({}).curryN, 'function');
1363 /*--------------------------------------------------------------------------*/
1365 QUnit.module('fp.trimChars');
1367 _.each(['trimChars', 'trimCharsStart', 'trimCharsEnd'], function(methodName, index) {
1368 var func = fp[methodName],
1372 parts.push('leading');
1375 parts.push('trailing');
1377 parts = parts.join(' and ');
1379 QUnit.test('`_.' + methodName + '` should remove ' + parts + ' `chars`', function(assert) {
1382 var string = '-_-a-b-c-_-',
1383 expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : '');
1385 assert.strictEqual(func('_-')(string), expected);
1389 /*--------------------------------------------------------------------------*/
1391 QUnit.module('fp.uniqBy');
1394 var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }];
1396 QUnit.test('should work with an `iteratee` argument', function(assert) {
1399 var expected = objects.slice(0, 3);
1401 var actual = fp.uniqBy(function(object) {
1405 assert.deepEqual(actual, expected);
1408 QUnit.test('should provide the correct `iteratee` arguments', function(assert) {
1413 fp.uniqBy(function() {
1414 args || (args = slice.call(arguments));
1417 assert.deepEqual(args, [objects[0]]);
1421 /*--------------------------------------------------------------------------*/
1423 QUnit.module('fp.zip');
1426 QUnit.test('should zip together two arrays', function(assert) {
1429 assert.deepEqual(fp.zip([1, 2])([3, 4]), [[1, 3], [2, 4]]);
1433 /*--------------------------------------------------------------------------*/
1435 QUnit.module('fp.zipObject');
1438 QUnit.test('should zip together key/value arrays into an object', function(assert) {
1441 assert.deepEqual(fp.zipObject(['a', 'b'])([1, 2]), { 'a': 1, 'b': 2 });
1445 /*--------------------------------------------------------------------------*/
1447 QUnit.module('fp.zipWith');
1450 QUnit.test('should zip arrays combining grouped elements with `iteratee`', function(assert) {
1453 var array1 = [1, 2, 3],
1456 var actual = fp.zipWith(function(a, b) {
1460 assert.deepEqual(actual, [5, 7, 9]);
1464 /*--------------------------------------------------------------------------*/
1466 QUnit.config.asyncRetries = 10;
1467 QUnit.config.hidepassed = true;
1470 QUnit.config.noglobals = true;