mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-01 23:57:49 +00:00
Add initial test files from lodash v4. (#4172)
* Install test dependencies. * Add initial test files. These files were created using a simplistic AST manipulator using `recast` to preserve formatting. There's bound to be a huge chunk of errors, but this serves as a good start. QUnit was replaced with Mocha, with ES2015 imports running via `esm`. As far as possible, QUnit-specific syntax has been replaced with Mocha's `describe` and `it`, while the native Node.js `assert` module is used for assertions. Files in the `test` directory ending in `.test.js` will be treated as test files. * Add initial passing files to test run.
This commit is contained in:
committed by
John-David Dalton
parent
7606ea3e25
commit
d5ef31929a
69
package-lock.json
generated
69
package-lock.json
generated
@@ -1228,6 +1228,12 @@
|
||||
"repeat-element": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"browser-stdout": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
|
||||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||
"dev": true
|
||||
},
|
||||
"browserify-aes": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-0.4.0.tgz",
|
||||
@@ -1877,6 +1883,12 @@
|
||||
"repeating": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||
"dev": true
|
||||
},
|
||||
"docdown": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/docdown/-/docdown-0.7.3.tgz",
|
||||
@@ -2252,6 +2264,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"esm": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/esm/-/esm-3.1.3.tgz",
|
||||
"integrity": "sha512-W5DKpMvvvtdn4Wzwl9scBUlsdiy4sXALG5oKIrCgnalg6db6vAztKVHWfOW4R8TlFvXlZDjipXSTrqhJDHpdRg==",
|
||||
"dev": true
|
||||
},
|
||||
"espree": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "http://backoffice-npm-proxy.prod:4873/espree/-/espree-3.5.4.tgz",
|
||||
@@ -3209,6 +3227,12 @@
|
||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
|
||||
"dev": true
|
||||
},
|
||||
"growl": {
|
||||
"version": "1.10.5",
|
||||
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
|
||||
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
|
||||
@@ -4154,6 +4178,51 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mocha": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz",
|
||||
"integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"browser-stdout": "1.3.1",
|
||||
"commander": "2.15.1",
|
||||
"debug": "3.1.0",
|
||||
"diff": "3.5.0",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"glob": "7.1.2",
|
||||
"growl": "1.10.5",
|
||||
"he": "1.1.1",
|
||||
"minimatch": "3.0.4",
|
||||
"mkdirp": "0.5.1",
|
||||
"supports-color": "5.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"test": "npm run test:main && npm run test:fp",
|
||||
"test:doc": "markdown-doctest doc/*.md",
|
||||
"test:fp": "node test/test-fp",
|
||||
"test:wip": "mocha -r esm test/*.test.js",
|
||||
"test:main": "node test/test",
|
||||
"validate": "npm run style && npm run test"
|
||||
},
|
||||
@@ -39,6 +40,7 @@
|
||||
"ecstatic": "^2.1.0",
|
||||
"eslint": "^3.15.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"esm": "^3.1.3",
|
||||
"fs-extra": "~1.0.0",
|
||||
"glob": "^7.1.1",
|
||||
"istanbul": "0.4.5",
|
||||
@@ -46,6 +48,7 @@
|
||||
"lodash": "4.17.11",
|
||||
"lodash-doc-globals": "^0.1.1",
|
||||
"markdown-doctest": "^0.9.1",
|
||||
"mocha": "^5.2.0",
|
||||
"optional-dev-dependency": "^2.0.0",
|
||||
"platform": "^1.3.3",
|
||||
"qunit-extras": "^3.0.0",
|
||||
|
||||
97
test/Arrays-category-methods.js
Normal file
97
test/Arrays-category-methods.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import assert from 'assert';
|
||||
import { args, toArgs, identity } from './utils.js';
|
||||
import difference from '../difference.js';
|
||||
import union from '../union.js';
|
||||
import compact from '../compact.js';
|
||||
import drop from '../drop.js';
|
||||
import dropRight from '../dropRight.js';
|
||||
import dropRightWhile from '../dropRightWhile.js';
|
||||
import dropWhile from '../dropWhile.js';
|
||||
import findIndex from '../findIndex.js';
|
||||
import findLastIndex from '../findLastIndex.js';
|
||||
import flatten from '../flatten.js';
|
||||
import head from '../head.js';
|
||||
import indexOf from '../indexOf.js';
|
||||
import initial from '../initial.js';
|
||||
import intersection from '../intersection.js';
|
||||
import last from '../last.js';
|
||||
import lastIndexOf from '../lastIndexOf.js';
|
||||
import sortedIndex from '../sortedIndex.js';
|
||||
import sortedIndexOf from '../sortedIndexOf.js';
|
||||
import sortedLastIndex from '../sortedLastIndex.js';
|
||||
import sortedLastIndexOf from '../sortedLastIndexOf.js';
|
||||
import tail from '../tail.js';
|
||||
import take from '../take.js';
|
||||
import takeRight from '../takeRight.js';
|
||||
import takeRightWhile from '../takeRightWhile.js';
|
||||
import takeWhile from '../takeWhile.js';
|
||||
import uniq from '../uniq.js';
|
||||
import without from '../without.js';
|
||||
import zip from '../zip.js';
|
||||
import xor from '../xor.js';
|
||||
|
||||
describe('"Arrays" category methods', function() {
|
||||
var args = toArgs([1, null, [3], null, 5]),
|
||||
sortedArgs = toArgs([1, [3], 5, null, null]),
|
||||
array = [1, 2, 3, 4, 5, 6];
|
||||
|
||||
it('should work with `arguments` objects', function() {
|
||||
function message(methodName) {
|
||||
return '`_.' + methodName + '` should work with `arguments` objects';
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(difference(args, [null]), [1, [3], 5], message('difference'));
|
||||
assert.deepStrictEqual(difference(array, args), [2, 3, 4, 6], '_.difference should work with `arguments` objects as secondary arguments');
|
||||
|
||||
assert.deepStrictEqual(union(args, [null, 6]), [1, null, [3], 5, 6], message('union'));
|
||||
assert.deepStrictEqual(union(array, args), array.concat([null, [3]]), '_.union should work with `arguments` objects as secondary arguments');
|
||||
|
||||
assert.deepStrictEqual(compact(args), [1, [3], 5], message('compact'));
|
||||
assert.deepStrictEqual(drop(args, 3), [null, 5], message('drop'));
|
||||
assert.deepStrictEqual(dropRight(args, 3), [1, null], message('dropRight'));
|
||||
assert.deepStrictEqual(dropRightWhile(args,identity), [1, null, [3], null], message('dropRightWhile'));
|
||||
assert.deepStrictEqual(dropWhile(args,identity), [null, [3], null, 5], message('dropWhile'));
|
||||
assert.deepStrictEqual(findIndex(args, identity), 0, message('findIndex'));
|
||||
assert.deepStrictEqual(findLastIndex(args, identity), 4, message('findLastIndex'));
|
||||
assert.deepStrictEqual(flatten(args), [1, null, 3, null, 5], message('flatten'));
|
||||
assert.deepStrictEqual(head(args), 1, message('head'));
|
||||
assert.deepStrictEqual(indexOf(args, 5), 4, message('indexOf'));
|
||||
assert.deepStrictEqual(initial(args), [1, null, [3], null], message('initial'));
|
||||
assert.deepStrictEqual(intersection(args, [1]), [1], message('intersection'));
|
||||
assert.deepStrictEqual(last(args), 5, message('last'));
|
||||
assert.deepStrictEqual(lastIndexOf(args, 1), 0, message('lastIndexOf'));
|
||||
assert.deepStrictEqual(sortedIndex(sortedArgs, 6), 3, message('sortedIndex'));
|
||||
assert.deepStrictEqual(sortedIndexOf(sortedArgs, 5), 2, message('sortedIndexOf'));
|
||||
assert.deepStrictEqual(sortedLastIndex(sortedArgs, 5), 3, message('sortedLastIndex'));
|
||||
assert.deepStrictEqual(sortedLastIndexOf(sortedArgs, 1), 0, message('sortedLastIndexOf'));
|
||||
assert.deepStrictEqual(tail(args, 4), [null, [3], null, 5], message('tail'));
|
||||
assert.deepStrictEqual(take(args, 2), [1, null], message('take'));
|
||||
assert.deepStrictEqual(takeRight(args, 1), [5], message('takeRight'));
|
||||
assert.deepStrictEqual(takeRightWhile(args, identity), [5], message('takeRightWhile'));
|
||||
assert.deepStrictEqual(takeWhile(args, identity), [1], message('takeWhile'));
|
||||
assert.deepStrictEqual(uniq(args), [1, null, [3], 5], message('uniq'));
|
||||
assert.deepStrictEqual(without(args, null), [1, [3], 5], message('without'));
|
||||
assert.deepStrictEqual(zip(args, args), [[1, 1], [null, null], [[3], [3]], [null, null], [5, 5]], message('zip'));
|
||||
});
|
||||
|
||||
it('should accept falsey primary arguments', function() {
|
||||
function message(methodName) {
|
||||
return '`_.' + methodName + '` should accept falsey primary arguments';
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(difference(null, array), [], message('difference'));
|
||||
assert.deepStrictEqual(intersection(null, array), [], message('intersection'));
|
||||
assert.deepStrictEqual(union(null, array), array, message('union'));
|
||||
assert.deepStrictEqual(xor(null, array), array, message('xor'));
|
||||
});
|
||||
|
||||
it('should accept falsey secondary arguments', function() {
|
||||
function message(methodName) {
|
||||
return '`_.' + methodName + '` should accept falsey secondary arguments';
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(difference(array, null), array, message('difference'));
|
||||
assert.deepStrictEqual(intersection(array, null), [], message('intersection'));
|
||||
assert.deepStrictEqual(union(array, null), array, message('union'));
|
||||
});
|
||||
});
|
||||
43
test/Strings-category-methods.js
Normal file
43
test/Strings-category-methods.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, stubString } from './utils.js';
|
||||
|
||||
describe('"Strings" category methods', function() {
|
||||
var stringMethods = [
|
||||
'camelCase',
|
||||
'capitalize',
|
||||
'escape',
|
||||
'kebabCase',
|
||||
'lowerCase',
|
||||
'lowerFirst',
|
||||
'pad',
|
||||
'padEnd',
|
||||
'padStart',
|
||||
'repeat',
|
||||
'snakeCase',
|
||||
'toLower',
|
||||
'toUpper',
|
||||
'trim',
|
||||
'trimEnd',
|
||||
'trimStart',
|
||||
'truncate',
|
||||
'unescape',
|
||||
'upperCase',
|
||||
'upperFirst'
|
||||
];
|
||||
|
||||
lodashStable.each(stringMethods, function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should return an empty string for empty values', function() {
|
||||
var values = [, null, undefined, ''],
|
||||
expected = lodashStable.map(values, stubString);
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? func(value) : func();
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
87
test/__proto__-property-bugs.js
Normal file
87
test/__proto__-property-bugs.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE, isEven, _, create, stubFalse, objectProto, funcProto } from './utils.js';
|
||||
import difference from '../difference.js';
|
||||
import intersection from '../intersection.js';
|
||||
import uniq from '../uniq.js';
|
||||
import without from '../without.js';
|
||||
import groupBy from '../groupBy.js';
|
||||
import merge from '../merge.js';
|
||||
|
||||
describe('`__proto__` property bugs', function() {
|
||||
it('should work with the "__proto__" key in internal data objects', function() {
|
||||
var stringLiteral = '__proto__',
|
||||
stringObject = Object(stringLiteral),
|
||||
expected = [stringLiteral, stringObject];
|
||||
|
||||
var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, function(count) {
|
||||
return isEven(count) ? stringLiteral : stringObject;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(difference(largeArray, largeArray), []);
|
||||
assert.deepStrictEqual(intersection(largeArray, largeArray), expected);
|
||||
assert.deepStrictEqual(uniq(largeArray), expected);
|
||||
assert.deepStrictEqual(without.apply(_, [largeArray].concat(largeArray)), []);
|
||||
});
|
||||
|
||||
it('should treat "__proto__" as a regular key in assignments', function() {
|
||||
var methods = [
|
||||
'assign',
|
||||
'assignIn',
|
||||
'defaults',
|
||||
'defaultsDeep',
|
||||
'merge'
|
||||
];
|
||||
|
||||
var source = create(null);
|
||||
source.__proto__ = [];
|
||||
|
||||
var expected = lodashStable.map(methods, stubFalse);
|
||||
|
||||
var actual = lodashStable.map(methods, function(methodName) {
|
||||
var result = _[methodName]({}, source);
|
||||
return result instanceof Array;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
actual = groupBy([{ 'a': '__proto__' }], 'a');
|
||||
assert.ok(!(actual instanceof Array));
|
||||
});
|
||||
|
||||
it('should not merge "__proto__" properties', function() {
|
||||
if (JSON) {
|
||||
merge({}, JSON.parse('{"__proto__":{"a":1}}'));
|
||||
|
||||
var actual = 'a' in objectProto;
|
||||
delete objectProto.a;
|
||||
|
||||
assert.ok(!actual);
|
||||
}
|
||||
});
|
||||
|
||||
it('should not indirectly merge builtin prototype properties', function() {
|
||||
merge({}, { 'toString': { 'constructor': { 'prototype': { 'a': 1 } } } });
|
||||
|
||||
var actual = 'a' in funcProto;
|
||||
delete funcProto.a;
|
||||
|
||||
assert.ok(!actual);
|
||||
|
||||
merge({}, { 'constructor': { 'prototype': { 'a': 1 } } });
|
||||
|
||||
actual = 'a' in objectProto;
|
||||
delete objectProto.a;
|
||||
|
||||
assert.ok(!actual);
|
||||
});
|
||||
|
||||
it('should not indirectly merge `Object` properties', function() {
|
||||
merge({}, { 'constructor': { 'a': 1 } });
|
||||
|
||||
var actual = 'a' in Object;
|
||||
delete Object.a;
|
||||
|
||||
assert.ok(!actual);
|
||||
});
|
||||
});
|
||||
15
test/add.test.js
Normal file
15
test/add.test.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import assert from 'assert';
|
||||
import add from '../add.js';
|
||||
|
||||
describe('add', function() {
|
||||
it('should add two numbers', function() {
|
||||
assert.strictEqual(add(6, 4), 10);
|
||||
assert.strictEqual(add(-6, 4), -2);
|
||||
assert.strictEqual(add(-6, -4), -10);
|
||||
});
|
||||
|
||||
it('should not coerce arguments to numbers', function() {
|
||||
assert.strictEqual(add('6', '4'), '64');
|
||||
assert.strictEqual(add('x', 'y'), 'xy');
|
||||
});
|
||||
});
|
||||
31
test/after.js
Normal file
31
test/after.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _ } from './utils.js';
|
||||
|
||||
describe('after', function() {
|
||||
function after(n, times) {
|
||||
var count = 0;
|
||||
lodashStable.times(times, _.after(n, function() { count++; }));
|
||||
return count;
|
||||
}
|
||||
|
||||
it('should create a function that invokes `func` after `n` calls', function() {
|
||||
assert.strictEqual(after(5, 5), 1, 'after(n) should invoke `func` after being called `n` times');
|
||||
assert.strictEqual(after(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times');
|
||||
assert.strictEqual(after(0, 0), 0, 'after(0) should not invoke `func` immediately');
|
||||
assert.strictEqual(after(0, 1), 1, 'after(0) should invoke `func` when called once');
|
||||
});
|
||||
|
||||
it('should coerce `n` values of `NaN` to `0`', function() {
|
||||
assert.strictEqual(after(NaN, 1), 1);
|
||||
});
|
||||
|
||||
it('should use `this` binding of function', function() {
|
||||
var after = _.after(1, function() { return ++this.count; }),
|
||||
object = { 'after': after, 'count': 0 };
|
||||
|
||||
object.after();
|
||||
assert.strictEqual(object.after(), 2);
|
||||
assert.strictEqual(object.count, 2);
|
||||
});
|
||||
});
|
||||
91
test/ary.js
Normal file
91
test/ary.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { slice, _ } from './utils.js';
|
||||
import ary from '../ary.js';
|
||||
import curry from '../curry.js';
|
||||
import rearg from '../rearg.js';
|
||||
|
||||
describe('ary', function() {
|
||||
function fn(a, b, c) {
|
||||
return slice.call(arguments);
|
||||
}
|
||||
|
||||
it('should cap the number of arguments provided to `func`', function() {
|
||||
var actual = lodashStable.map(['6', '8', '10'], ary(parseInt, 1));
|
||||
assert.deepStrictEqual(actual, [6, 8, 10]);
|
||||
|
||||
var capped = ary(fn, 2);
|
||||
assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']);
|
||||
});
|
||||
|
||||
it('should use `func.length` if `n` is not given', function() {
|
||||
var capped = ary(fn);
|
||||
assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should treat a negative `n` as `0`', function() {
|
||||
var capped = ary(fn, -1);
|
||||
|
||||
try {
|
||||
var actual = capped('a');
|
||||
} catch (e) {}
|
||||
|
||||
assert.deepStrictEqual(actual, []);
|
||||
});
|
||||
|
||||
it('should coerce `n` to an integer', function() {
|
||||
var values = ['1', 1.6, 'xyz'],
|
||||
expected = [['a'], ['a'], []];
|
||||
|
||||
var actual = lodashStable.map(values, function(n) {
|
||||
var capped = ary(fn, n);
|
||||
return capped('a', 'b');
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should not force a minimum argument count', function() {
|
||||
var args = ['a', 'b', 'c'],
|
||||
capped = ary(fn, 3);
|
||||
|
||||
var expected = lodashStable.map(args, function(arg, index) {
|
||||
return args.slice(0, index);
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(expected, function(array) {
|
||||
return capped.apply(undefined, array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should use `this` binding of function', function() {
|
||||
var capped = ary(function(a, b) { return this; }, 1),
|
||||
object = { 'capped': capped };
|
||||
|
||||
assert.strictEqual(object.capped(), object);
|
||||
});
|
||||
|
||||
it('should use the existing `ary` if smaller', function() {
|
||||
var capped = ary(ary(fn, 1), 2);
|
||||
assert.deepStrictEqual(capped('a', 'b', 'c'), ['a']);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var funcs = lodashStable.map([fn], ary),
|
||||
actual = funcs[0]('a', 'b', 'c');
|
||||
|
||||
assert.deepStrictEqual(actual, ['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should work when combined with other methods that use metadata', function() {
|
||||
var array = ['a', 'b', 'c'],
|
||||
includes = curry(rearg(ary(_.includes, 2), 1, 0), 2);
|
||||
|
||||
assert.strictEqual(includes('b')(array, 2), true);
|
||||
|
||||
includes = _(_.includes).ary(2).rearg(1, 0).curry(2).value();
|
||||
assert.strictEqual(includes('b')(array, 2), true);
|
||||
});
|
||||
});
|
||||
88
test/assign-and-assignIn.js
Normal file
88
test/assign-and-assignIn.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, defineProperty, stubOne, noop, stubNaN } from './utils.js';
|
||||
|
||||
describe('assign and assignIn', function() {
|
||||
lodashStable.each(['assign', 'assignIn'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should assign source properties to `object`', function() {
|
||||
assert.deepStrictEqual(func({ 'a': 1 }, { 'b': 2 }), { 'a': 1, 'b': 2 });
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should accept multiple sources', function() {
|
||||
var expected = { 'a': 1, 'b': 2, 'c': 3 };
|
||||
assert.deepStrictEqual(func({ 'a': 1 }, { 'b': 2 }, { 'c': 3 }), expected);
|
||||
assert.deepStrictEqual(func({ 'a': 1 }, { 'b': 2, 'c': 2 }, { 'c': 3 }), expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should overwrite destination properties', function() {
|
||||
var expected = { 'a': 3, 'b': 2, 'c': 1 };
|
||||
assert.deepStrictEqual(func({ 'a': 1, 'b': 2 }, expected), expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should assign source properties with nullish values', function() {
|
||||
var expected = { 'a': null, 'b': undefined, 'c': null };
|
||||
assert.deepStrictEqual(func({ 'a': 1, 'b': 2 }, expected), expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should skip assignments if values are the same', function() {
|
||||
var object = {};
|
||||
|
||||
var descriptor = {
|
||||
'configurable': true,
|
||||
'enumerable': true,
|
||||
'set': function() { throw new Error; }
|
||||
};
|
||||
|
||||
var source = {
|
||||
'a': 1,
|
||||
'b': undefined,
|
||||
'c': NaN,
|
||||
'd': undefined,
|
||||
'constructor': Object,
|
||||
'toString': lodashStable.constant('source')
|
||||
};
|
||||
|
||||
defineProperty(object, 'a', lodashStable.assign({}, descriptor, {
|
||||
'get': stubOne
|
||||
}));
|
||||
|
||||
defineProperty(object, 'b', lodashStable.assign({}, descriptor, {
|
||||
'get': noop
|
||||
}));
|
||||
|
||||
defineProperty(object, 'c', lodashStable.assign({}, descriptor, {
|
||||
'get': stubNaN
|
||||
}));
|
||||
|
||||
defineProperty(object, 'constructor', lodashStable.assign({}, descriptor, {
|
||||
'get': lodashStable.constant(Object)
|
||||
}));
|
||||
|
||||
try {
|
||||
var actual = func(object, source);
|
||||
} catch (e) {}
|
||||
|
||||
assert.deepStrictEqual(actual, source);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat sparse array sources as dense', function() {
|
||||
var array = [1];
|
||||
array[2] = 3;
|
||||
|
||||
assert.deepStrictEqual(func({}, array), { '0': 1, '1': undefined, '2': 3 });
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should assign values of prototype objects', function() {
|
||||
function Foo() {}
|
||||
Foo.prototype.a = 1;
|
||||
|
||||
assert.deepStrictEqual(func({}, Foo.prototype), { 'a': 1 });
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should coerce string sources to objects', function() {
|
||||
assert.deepStrictEqual(func({}, 'a'), { '0': 'a' });
|
||||
});
|
||||
});
|
||||
});
|
||||
9
test/assignIn.js
Normal file
9
test/assignIn.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import assert from 'assert';
|
||||
import extend from '../extend.js';
|
||||
import assignIn from '../assignIn.js';
|
||||
|
||||
describe('assignIn', function() {
|
||||
it('should be aliased', function() {
|
||||
assert.strictEqual(extend, assignIn);
|
||||
});
|
||||
});
|
||||
9
test/assignInWith.js
Normal file
9
test/assignInWith.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import assert from 'assert';
|
||||
import extendWith from '../extendWith.js';
|
||||
import assignInWith from '../assignInWith.js';
|
||||
|
||||
describe('assignInWith', function() {
|
||||
it('should be aliased', function() {
|
||||
assert.strictEqual(extendWith, assignInWith);
|
||||
});
|
||||
});
|
||||
22
test/assignWith-and-assignInWith.js
Normal file
22
test/assignWith-and-assignInWith.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, noop } from './utils.js';
|
||||
|
||||
describe('assignWith and assignInWith', function() {
|
||||
lodashStable.each(['assignWith', 'assignInWith'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should work with a `customizer` callback', function() {
|
||||
var actual = func({ 'a': 1, 'b': 2 }, { 'a': 3, 'c': 3 }, function(a, b) {
|
||||
return a === undefined ? b : a;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, { 'a': 1, 'b': 2, 'c': 3 });
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a `customizer` that returns `undefined`', function() {
|
||||
var expected = { 'a': 1 };
|
||||
assert.deepStrictEqual(func({}, expected, noop), expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
124
test/at.js
Normal file
124
test/at.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { empties, stubOne, falsey, args, LARGE_ARRAY_SIZE, square, identity } from './utils.js';
|
||||
import at from '../at.js';
|
||||
|
||||
describe('at', function() {
|
||||
var array = ['a', 'b', 'c'],
|
||||
object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
|
||||
|
||||
it('should return the elements corresponding to the specified keys', function() {
|
||||
var actual = at(array, [0, 2]);
|
||||
assert.deepStrictEqual(actual, ['a', 'c']);
|
||||
});
|
||||
|
||||
it('should return `undefined` for nonexistent keys', function() {
|
||||
var actual = at(array, [2, 4, 0]);
|
||||
assert.deepStrictEqual(actual, ['c', undefined, 'a']);
|
||||
});
|
||||
|
||||
it('should work with non-index keys on array values', function() {
|
||||
var values = lodashStable.reject(empties, function(value) {
|
||||
return (value === 0) || lodashStable.isArray(value);
|
||||
}).concat(-1, 1.1);
|
||||
|
||||
var array = lodashStable.transform(values, function(result, value) {
|
||||
result[value] = 1;
|
||||
}, []);
|
||||
|
||||
var expected = lodashStable.map(values, stubOne),
|
||||
actual = at(array, values);
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return an empty array when no keys are given', function() {
|
||||
assert.deepStrictEqual(at(array), []);
|
||||
assert.deepStrictEqual(at(array, [], []), []);
|
||||
});
|
||||
|
||||
it('should accept multiple key arguments', function() {
|
||||
var actual = at(['a', 'b', 'c', 'd'], 3, 0, 2);
|
||||
assert.deepStrictEqual(actual, ['d', 'a', 'c']);
|
||||
});
|
||||
|
||||
it('should work with a falsey `object` when keys are given', function() {
|
||||
var expected = lodashStable.map(falsey, lodashStable.constant(Array(4)));
|
||||
|
||||
var actual = lodashStable.map(falsey, function(object) {
|
||||
try {
|
||||
return at(object, 0, 1, 'pop', 'push');
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with an `arguments` object for `object`', function() {
|
||||
var actual = at(args, [2, 0]);
|
||||
assert.deepStrictEqual(actual, [3, 1]);
|
||||
});
|
||||
|
||||
it('should work with `arguments` object as secondary arguments', function() {
|
||||
var actual = at([1, 2, 3, 4, 5], args);
|
||||
assert.deepStrictEqual(actual, [2, 3, 4]);
|
||||
});
|
||||
|
||||
it('should work with an object for `object`', function() {
|
||||
var actual = at(object, ['a[0].b.c', 'a[1]']);
|
||||
assert.deepStrictEqual(actual, [3, 4]);
|
||||
});
|
||||
|
||||
it('should pluck inherited property values', function() {
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
}
|
||||
Foo.prototype.b = 2;
|
||||
|
||||
var actual = at(new Foo, 'b');
|
||||
assert.deepStrictEqual(actual, [2]);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var largeArray = lodashStable.range(LARGE_ARRAY_SIZE),
|
||||
smallArray = array;
|
||||
|
||||
lodashStable.each([[2], ['2'], [2, 1]], function(paths) {
|
||||
lodashStable.times(2, function(index) {
|
||||
var array = index ? largeArray : smallArray,
|
||||
wrapped = _(array).map(identity).at(paths);
|
||||
|
||||
assert.deepEqual(wrapped.value(), at(_.map(array, identity), paths));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support shortcut fusion', function() {
|
||||
var array = lodashStable.range(LARGE_ARRAY_SIZE),
|
||||
count = 0,
|
||||
iteratee = function(value) { count++; return square(value); },
|
||||
lastIndex = LARGE_ARRAY_SIZE - 1;
|
||||
|
||||
lodashStable.each([lastIndex, lastIndex + '', LARGE_ARRAY_SIZE, []], function(n, index) {
|
||||
count = 0;
|
||||
var actual = _(array).map(iteratee).at(n).value(),
|
||||
expected = index < 2 ? 1 : 0;
|
||||
|
||||
assert.strictEqual(count, expected);
|
||||
|
||||
expected = index == 3 ? [] : [index == 2 ? undefined : square(lastIndex)];
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('work with an object for `object` when chaining', function() {
|
||||
var paths = ['a[0].b.c', 'a[1]'],
|
||||
actual = _(object).map(identity).at(paths).value();
|
||||
|
||||
assert.deepEqual(actual, at(_.map(object, identity), paths));
|
||||
|
||||
var indexObject = { '0': 1 };
|
||||
actual = _(indexObject).at(0).value();
|
||||
assert.deepEqual(actual, at(indexObject, 0));
|
||||
});
|
||||
});
|
||||
55
test/attempt.test.js
Normal file
55
test/attempt.test.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { slice, errors, stubTrue, CustomError, realm } from './utils.js';
|
||||
import attempt from '../attempt.js';
|
||||
|
||||
describe('attempt', function() {
|
||||
it('should return the result of `func`', function() {
|
||||
assert.strictEqual(attempt(lodashStable.constant('x')), 'x');
|
||||
});
|
||||
|
||||
it('should provide additional arguments to `func`', function() {
|
||||
var actual = attempt(function() { return slice.call(arguments); }, 1, 2);
|
||||
assert.deepStrictEqual(actual, [1, 2]);
|
||||
});
|
||||
|
||||
it('should return the caught error', function() {
|
||||
var expected = lodashStable.map(errors, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(errors, function(error) {
|
||||
return attempt(function() { throw error; }) === error;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should coerce errors to error objects', function() {
|
||||
var actual = attempt(function() { throw 'x'; });
|
||||
assert.ok(lodashStable.isEqual(actual, Error('x')));
|
||||
});
|
||||
|
||||
it('should preserve custom errors', function() {
|
||||
var actual = attempt(function() { throw new CustomError('x'); });
|
||||
assert.ok(actual instanceof CustomError);
|
||||
});
|
||||
|
||||
it('should work with an error object from another realm', function() {
|
||||
if (realm.errors) {
|
||||
var expected = lodashStable.map(realm.errors, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(realm.errors, function(error) {
|
||||
return attempt(function() { throw error; }) === error;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return an unwrapped value when implicitly chaining', function() {
|
||||
assert.strictEqual(_(lodashStable.constant('x')).attempt(), 'x');
|
||||
});
|
||||
|
||||
it('should return a wrapped value when explicitly chaining', function() {
|
||||
assert.ok(_(lodashStable.constant('x')).chain().attempt() instanceof _);
|
||||
});
|
||||
});
|
||||
151
test/basename.js
Normal file
151
test/basename.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
|
||||
import {
|
||||
basename,
|
||||
amd,
|
||||
ui,
|
||||
Worker,
|
||||
QUnit,
|
||||
lodashBizarro,
|
||||
LARGE_ARRAY_SIZE,
|
||||
symbol,
|
||||
setProperty,
|
||||
} from './utils.js';
|
||||
|
||||
import _VERSION from '../.internal/VERSION.js';
|
||||
import VERSION from '../VERSION.js';
|
||||
|
||||
describe(basename, function() {
|
||||
it('should support loading ' + basename + ' as the "lodash" module', function() {
|
||||
if (amd) {
|
||||
assert.strictEqual((lodashModule || {}).moduleName, 'lodash');
|
||||
}
|
||||
});
|
||||
|
||||
it('should support loading ' + basename + ' with the Require.js "shim" configuration option', function() {
|
||||
if (amd && lodashStable.includes(ui.loaderPath, 'requirejs')) {
|
||||
assert.strictEqual((shimmedModule || {}).moduleName, 'shimmed');
|
||||
}
|
||||
});
|
||||
|
||||
it('should support loading ' + basename + ' as the "underscore" module', function() {
|
||||
if (amd) {
|
||||
assert.strictEqual((underscoreModule || {}).moduleName, 'underscore');
|
||||
}
|
||||
});
|
||||
|
||||
it('should support loading ' + basename + ' in a web worker', function(done) {
|
||||
if (Worker) {
|
||||
var limit = 30000 / QUnit.config.asyncRetries,
|
||||
start = +new Date;
|
||||
|
||||
var attempt = function() {
|
||||
var actual = _VERSION;
|
||||
if ((new Date - start) < limit && typeof actual != 'string') {
|
||||
setTimeout(attempt, 16);
|
||||
return;
|
||||
}
|
||||
assert.strictEqual(actual, VERSION);
|
||||
done();
|
||||
};
|
||||
|
||||
attempt();
|
||||
}
|
||||
else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('should not add `Function.prototype` extensions to lodash', function() {
|
||||
if (lodashBizarro) {
|
||||
assert.ok(!('_method' in lodashBizarro));
|
||||
}
|
||||
});
|
||||
|
||||
it('should avoid non-native built-ins', function() {
|
||||
function message(lodashMethod, nativeMethod) {
|
||||
return '`' + lodashMethod + '` should avoid overwritten native `' + nativeMethod + '`';
|
||||
}
|
||||
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
}
|
||||
Foo.prototype.b = 2;
|
||||
|
||||
var object = { 'a': 1 },
|
||||
otherObject = { 'b': 2 },
|
||||
largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object));
|
||||
|
||||
if (lodashBizarro) {
|
||||
try {
|
||||
var actual = lodashBizarro.create(Foo.prototype);
|
||||
} catch (e) {
|
||||
actual = null;
|
||||
}
|
||||
var label = message('_.create', 'Object.create');
|
||||
assert.ok(actual instanceof Foo, label);
|
||||
|
||||
try {
|
||||
actual = [
|
||||
lodashBizarro.difference([object, otherObject], largeArray),
|
||||
lodashBizarro.intersection(largeArray, [object]),
|
||||
lodashBizarro.uniq(largeArray)
|
||||
];
|
||||
} catch (e) {
|
||||
actual = null;
|
||||
}
|
||||
label = message('_.difference`, `_.intersection`, and `_.uniq', 'Map');
|
||||
assert.deepStrictEqual(actual, [[otherObject], [object], [object]], label);
|
||||
|
||||
try {
|
||||
if (Symbol) {
|
||||
object[symbol] = {};
|
||||
}
|
||||
actual = [
|
||||
lodashBizarro.clone(object),
|
||||
lodashBizarro.cloneDeep(object)
|
||||
];
|
||||
} catch (e) {
|
||||
actual = null;
|
||||
}
|
||||
label = message('_.clone` and `_.cloneDeep', 'Object.getOwnPropertySymbols');
|
||||
assert.deepStrictEqual(actual, [object, object], label);
|
||||
|
||||
try {
|
||||
// Avoid buggy symbol detection in Babel's `_typeof` helper.
|
||||
var symObject = setProperty(Object(symbol), 'constructor', Object);
|
||||
actual = [
|
||||
Symbol ? lodashBizarro.clone(symObject) : {},
|
||||
Symbol ? lodashBizarro.isEqual(symObject, Object(symbol)) : false,
|
||||
Symbol ? lodashBizarro.toString(symObject) : ''
|
||||
];
|
||||
} catch (e) {
|
||||
actual = null;
|
||||
}
|
||||
label = message('_.clone`, `_.isEqual`, and `_.toString', 'Symbol');
|
||||
assert.deepStrictEqual(actual, [{}, false, ''], label);
|
||||
|
||||
try {
|
||||
var map = new lodashBizarro.memoize.Cache;
|
||||
actual = map.set('a', 1).get('a');
|
||||
} catch (e) {
|
||||
actual = null;
|
||||
}
|
||||
label = message('_.memoize.Cache', 'Map');
|
||||
assert.deepStrictEqual(actual, 1, label);
|
||||
|
||||
try {
|
||||
map = new (Map || Object);
|
||||
if (Symbol && Symbol.iterator) {
|
||||
map[Symbol.iterator] = null;
|
||||
}
|
||||
actual = lodashBizarro.toArray(map);
|
||||
} catch (e) {
|
||||
actual = null;
|
||||
}
|
||||
label = message('_.toArray', 'Map');
|
||||
assert.deepStrictEqual(actual, [], label);
|
||||
}
|
||||
});
|
||||
});
|
||||
31
test/before.js
Normal file
31
test/before.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _ } from './utils.js';
|
||||
|
||||
describe('before', function() {
|
||||
function before(n, times) {
|
||||
var count = 0;
|
||||
lodashStable.times(times, _.before(n, function() { count++; }));
|
||||
return count;
|
||||
}
|
||||
|
||||
it('should create a function that invokes `func` after `n` calls', function() {
|
||||
assert.strictEqual(before(5, 4), 4, 'before(n) should invoke `func` before being called `n` times');
|
||||
assert.strictEqual(before(5, 6), 4, 'before(n) should not invoke `func` after being called `n - 1` times');
|
||||
assert.strictEqual(before(0, 0), 0, 'before(0) should not invoke `func` immediately');
|
||||
assert.strictEqual(before(0, 1), 0, 'before(0) should not invoke `func` when called');
|
||||
});
|
||||
|
||||
it('should coerce `n` values of `NaN` to `0`', function() {
|
||||
assert.strictEqual(before(NaN, 1), 0);
|
||||
});
|
||||
|
||||
it('should use `this` binding of function', function() {
|
||||
var before = _.before(2, function() { return ++this.count; }),
|
||||
object = { 'before': before, 'count': 0 };
|
||||
|
||||
object.before();
|
||||
assert.strictEqual(object.before(), 1);
|
||||
assert.strictEqual(object.count, 1);
|
||||
});
|
||||
});
|
||||
231
test/bind.js
Normal file
231
test/bind.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { push, falsey, stubTrue } from './utils.js';
|
||||
import bind from '../bind.js';
|
||||
import placeholder from '../placeholder.js';
|
||||
|
||||
describe('bind', function() {
|
||||
function fn() {
|
||||
var result = [this];
|
||||
push.apply(result, arguments);
|
||||
return result;
|
||||
}
|
||||
|
||||
it('should bind a function to an object', function() {
|
||||
var object = {},
|
||||
bound = bind(fn, object);
|
||||
|
||||
assert.deepStrictEqual(bound('a'), [object, 'a']);
|
||||
});
|
||||
|
||||
it('should accept a falsey `thisArg`', function() {
|
||||
var values = lodashStable.reject(falsey.slice(1), function(value) { return value == null; }),
|
||||
expected = lodashStable.map(values, function(value) { return [value]; });
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
try {
|
||||
var bound = bind(fn, value);
|
||||
return bound();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.ok(lodashStable.every(actual, function(value, index) {
|
||||
return lodashStable.isEqual(value, expected[index]);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should bind a function to nullish values', function() {
|
||||
var bound = bind(fn, null),
|
||||
actual = bound('a');
|
||||
|
||||
assert.ok((actual[0] === null) || (actual[0] && actual[0].Array));
|
||||
assert.strictEqual(actual[1], 'a');
|
||||
|
||||
lodashStable.times(2, function(index) {
|
||||
bound = index ? bind(fn, undefined) : bind(fn);
|
||||
actual = bound('b');
|
||||
|
||||
assert.ok((actual[0] === undefined) || (actual[0] && actual[0].Array));
|
||||
assert.strictEqual(actual[1], 'b');
|
||||
});
|
||||
});
|
||||
|
||||
it('should partially apply arguments ', function() {
|
||||
var object = {},
|
||||
bound = bind(fn, object, 'a');
|
||||
|
||||
assert.deepStrictEqual(bound(), [object, 'a']);
|
||||
|
||||
bound = bind(fn, object, 'a');
|
||||
assert.deepStrictEqual(bound('b'), [object, 'a', 'b']);
|
||||
|
||||
bound = bind(fn, object, 'a', 'b');
|
||||
assert.deepStrictEqual(bound(), [object, 'a', 'b']);
|
||||
assert.deepStrictEqual(bound('c', 'd'), [object, 'a', 'b', 'c', 'd']);
|
||||
});
|
||||
|
||||
it('should support placeholders', function() {
|
||||
var object = {},
|
||||
ph = bind.placeholder,
|
||||
bound = bind(fn, object, ph, 'b', ph);
|
||||
|
||||
assert.deepStrictEqual(bound('a', 'c'), [object, 'a', 'b', 'c']);
|
||||
assert.deepStrictEqual(bound('a'), [object, 'a', 'b', undefined]);
|
||||
assert.deepStrictEqual(bound('a', 'c', 'd'), [object, 'a', 'b', 'c', 'd']);
|
||||
assert.deepStrictEqual(bound(), [object, undefined, 'b', undefined]);
|
||||
});
|
||||
|
||||
it('should use `_.placeholder` when set', function() {
|
||||
var _ph = placeholder = {},
|
||||
ph = bind.placeholder,
|
||||
object = {},
|
||||
bound = bind(fn, object, _ph, 'b', ph);
|
||||
|
||||
assert.deepEqual(bound('a', 'c'), [object, 'a', 'b', ph, 'c']);
|
||||
delete placeholder;
|
||||
});
|
||||
|
||||
it('should create a function with a `length` of `0`', function() {
|
||||
var fn = function(a, b, c) {},
|
||||
bound = bind(fn, {});
|
||||
|
||||
assert.strictEqual(bound.length, 0);
|
||||
|
||||
bound = bind(fn, {}, 1);
|
||||
assert.strictEqual(bound.length, 0);
|
||||
});
|
||||
|
||||
it('should ignore binding when called with the `new` operator', function() {
|
||||
function Foo() {
|
||||
return this;
|
||||
}
|
||||
|
||||
var bound = bind(Foo, { 'a': 1 }),
|
||||
newBound = new bound;
|
||||
|
||||
assert.strictEqual(bound().a, 1);
|
||||
assert.strictEqual(newBound.a, undefined);
|
||||
assert.ok(newBound instanceof Foo);
|
||||
});
|
||||
|
||||
it('should handle a number of arguments when called with the `new` operator', function() {
|
||||
function Foo() {
|
||||
return this;
|
||||
}
|
||||
|
||||
function Bar() {}
|
||||
|
||||
var thisArg = { 'a': 1 },
|
||||
boundFoo = bind(Foo, thisArg),
|
||||
boundBar = bind(Bar, thisArg),
|
||||
count = 9,
|
||||
expected = lodashStable.times(count, lodashStable.constant([undefined, undefined]));
|
||||
|
||||
var actual = lodashStable.times(count, function(index) {
|
||||
try {
|
||||
switch (index) {
|
||||
case 0: return [new boundFoo().a, new boundBar().a];
|
||||
case 1: return [new boundFoo(1).a, new boundBar(1).a];
|
||||
case 2: return [new boundFoo(1, 2).a, new boundBar(1, 2).a];
|
||||
case 3: return [new boundFoo(1, 2, 3).a, new boundBar(1, 2, 3).a];
|
||||
case 4: return [new boundFoo(1, 2, 3, 4).a, new boundBar(1, 2, 3, 4).a];
|
||||
case 5: return [new boundFoo(1, 2, 3, 4, 5).a, new boundBar(1, 2, 3, 4, 5).a];
|
||||
case 6: return [new boundFoo(1, 2, 3, 4, 5, 6).a, new boundBar(1, 2, 3, 4, 5, 6).a];
|
||||
case 7: return [new boundFoo(1, 2, 3, 4, 5, 6, 7).a, new boundBar(1, 2, 3, 4, 5, 6, 7).a];
|
||||
case 8: return [new boundFoo(1, 2, 3, 4, 5, 6, 7, 8).a, new boundBar(1, 2, 3, 4, 5, 6, 7, 8).a];
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should ensure `new bound` is an instance of `func`', function() {
|
||||
function Foo(value) {
|
||||
return value && object;
|
||||
}
|
||||
|
||||
var bound = bind(Foo),
|
||||
object = {};
|
||||
|
||||
assert.ok(new bound instanceof Foo);
|
||||
assert.strictEqual(new bound(true), object);
|
||||
});
|
||||
|
||||
it('should append array arguments to partially applied arguments', function() {
|
||||
var object = {},
|
||||
bound = bind(fn, object, 'a');
|
||||
|
||||
assert.deepStrictEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']);
|
||||
});
|
||||
|
||||
it('should not rebind functions', function() {
|
||||
var object1 = {},
|
||||
object2 = {},
|
||||
object3 = {};
|
||||
|
||||
var bound1 = bind(fn, object1),
|
||||
bound2 = bind(bound1, object2, 'a'),
|
||||
bound3 = bind(bound1, object3, 'b');
|
||||
|
||||
assert.deepStrictEqual(bound1(), [object1]);
|
||||
assert.deepStrictEqual(bound2(), [object1, 'a']);
|
||||
assert.deepStrictEqual(bound3(), [object1, 'b']);
|
||||
});
|
||||
|
||||
it('should not error when instantiating bound built-ins', function() {
|
||||
var Ctor = bind(Date, null),
|
||||
expected = new Date(2012, 4, 23, 0, 0, 0, 0);
|
||||
|
||||
try {
|
||||
var actual = new Ctor(2012, 4, 23, 0, 0, 0, 0);
|
||||
} catch (e) {}
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
Ctor = bind(Date, null, 2012, 4, 23);
|
||||
|
||||
try {
|
||||
actual = new Ctor(0, 0, 0, 0);
|
||||
} catch (e) {}
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should not error when calling bound class constructors with the `new` operator', function() {
|
||||
var createCtor = lodashStable.attempt(Function, '"use strict";return class A{}');
|
||||
|
||||
if (typeof createCtor == 'function') {
|
||||
var bound = bind(createCtor()),
|
||||
count = 8,
|
||||
expected = lodashStable.times(count, stubTrue);
|
||||
|
||||
var actual = lodashStable.times(count, function(index) {
|
||||
try {
|
||||
switch (index) {
|
||||
case 0: return !!(new bound);
|
||||
case 1: return !!(new bound(1));
|
||||
case 2: return !!(new bound(1, 2));
|
||||
case 3: return !!(new bound(1, 2, 3));
|
||||
case 4: return !!(new bound(1, 2, 3, 4));
|
||||
case 5: return !!(new bound(1, 2, 3, 4, 5));
|
||||
case 6: return !!(new bound(1, 2, 3, 4, 5, 6));
|
||||
case 7: return !!(new bound(1, 2, 3, 4, 5, 6, 7));
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var object = {},
|
||||
bound = _(fn).bind({}, 'a', 'b');
|
||||
|
||||
assert.ok(bound instanceof _);
|
||||
|
||||
var actual = bound.value()('c');
|
||||
assert.deepEqual(actual, [object, 'a', 'b', 'c']);
|
||||
});
|
||||
});
|
||||
74
test/bindAll.js
Normal file
74
test/bindAll.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { args, toArgs, arrayProto } from './utils.js';
|
||||
import bindAll from '../bindAll.js';
|
||||
|
||||
describe('bindAll', function() {
|
||||
var args = toArgs(['a']);
|
||||
|
||||
var source = {
|
||||
'_n0': -2,
|
||||
'_p0': -1,
|
||||
'_a': 1,
|
||||
'_b': 2,
|
||||
'_c': 3,
|
||||
'_d': 4,
|
||||
'-0': function() { return this._n0; },
|
||||
'0': function() { return this._p0; },
|
||||
'a': function() { return this._a; },
|
||||
'b': function() { return this._b; },
|
||||
'c': function() { return this._c; },
|
||||
'd': function() { return this._d; }
|
||||
};
|
||||
|
||||
it('should accept individual method names', function() {
|
||||
var object = lodashStable.cloneDeep(source);
|
||||
bindAll(object, 'a', 'b');
|
||||
|
||||
var actual = lodashStable.map(['a', 'b', 'c'], function(key) {
|
||||
return object[key].call({});
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [1, 2, undefined]);
|
||||
});
|
||||
|
||||
it('should accept arrays of method names', function() {
|
||||
var object = lodashStable.cloneDeep(source);
|
||||
bindAll(object, ['a', 'b'], ['c']);
|
||||
|
||||
var actual = lodashStable.map(['a', 'b', 'c', 'd'], function(key) {
|
||||
return object[key].call({});
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [1, 2, 3, undefined]);
|
||||
});
|
||||
|
||||
it('should preserve the sign of `0`', function() {
|
||||
var props = [-0, Object(-0), 0, Object(0)];
|
||||
|
||||
var actual = lodashStable.map(props, function(key) {
|
||||
var object = lodashStable.cloneDeep(source);
|
||||
bindAll(object, key);
|
||||
return object[lodashStable.toString(key)].call({});
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [-2, -2, -1, -1]);
|
||||
});
|
||||
|
||||
it('should work with an array `object`', function() {
|
||||
var array = ['push', 'pop'];
|
||||
bindAll(array);
|
||||
assert.strictEqual(array.pop, arrayProto.pop);
|
||||
});
|
||||
|
||||
it('should work with `arguments` objects as secondary arguments', function() {
|
||||
var object = lodashStable.cloneDeep(source);
|
||||
bindAll(object, args);
|
||||
|
||||
var actual = lodashStable.map(args, function(key) {
|
||||
return object[key].call({});
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [1]);
|
||||
});
|
||||
});
|
||||
66
test/bindKey.js
Normal file
66
test/bindKey.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import bindKey from '../bindKey.js';
|
||||
|
||||
describe('bindKey', function() {
|
||||
it('should work when the target function is overwritten', function() {
|
||||
var object = {
|
||||
'user': 'fred',
|
||||
'greet': function(greeting) {
|
||||
return this.user + ' says: ' + greeting;
|
||||
}
|
||||
};
|
||||
|
||||
var bound = bindKey(object, 'greet', 'hi');
|
||||
assert.strictEqual(bound(), 'fred says: hi');
|
||||
|
||||
object.greet = function(greeting) {
|
||||
return this.user + ' says: ' + greeting + '!';
|
||||
};
|
||||
|
||||
assert.strictEqual(bound(), 'fred says: hi!');
|
||||
});
|
||||
|
||||
it('should support placeholders', function() {
|
||||
var object = {
|
||||
'fn': function() {
|
||||
return slice.call(arguments);
|
||||
}
|
||||
};
|
||||
|
||||
var ph = bindKey.placeholder,
|
||||
bound = bindKey(object, 'fn', ph, 'b', ph);
|
||||
|
||||
assert.deepStrictEqual(bound('a', 'c'), ['a', 'b', 'c']);
|
||||
assert.deepStrictEqual(bound('a'), ['a', 'b', undefined]);
|
||||
assert.deepStrictEqual(bound('a', 'c', 'd'), ['a', 'b', 'c', 'd']);
|
||||
assert.deepStrictEqual(bound(), [undefined, 'b', undefined]);
|
||||
});
|
||||
|
||||
it('should use `_.placeholder` when set', function() {
|
||||
var object = {
|
||||
'fn': function() {
|
||||
return slice.call(arguments);
|
||||
}
|
||||
};
|
||||
|
||||
var _ph = _.placeholder = {},
|
||||
ph = bindKey.placeholder,
|
||||
bound = bindKey(object, 'fn', _ph, 'b', ph);
|
||||
|
||||
assert.deepEqual(bound('a', 'c'), ['a', 'b', ph, 'c']);
|
||||
delete _.placeholder;
|
||||
});
|
||||
|
||||
it('should ensure `new bound` is an instance of `object[key]`', function() {
|
||||
function Foo(value) {
|
||||
return value && object;
|
||||
}
|
||||
|
||||
var object = { 'Foo': Foo },
|
||||
bound = bindKey(object, 'Foo');
|
||||
|
||||
assert.ok(new bound instanceof Foo);
|
||||
assert.strictEqual(new bound(true), object);
|
||||
});
|
||||
});
|
||||
28
test/camelCase.js
Normal file
28
test/camelCase.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import camelCase from '../camelCase.js';
|
||||
|
||||
describe('camelCase', function() {
|
||||
it('should work with numbers', function() {
|
||||
assert.strictEqual(camelCase('12 feet'), '12Feet');
|
||||
assert.strictEqual(camelCase('enable 6h format'), 'enable6HFormat');
|
||||
assert.strictEqual(camelCase('enable 24H format'), 'enable24HFormat');
|
||||
assert.strictEqual(camelCase('too legit 2 quit'), 'tooLegit2Quit');
|
||||
assert.strictEqual(camelCase('walk 500 miles'), 'walk500Miles');
|
||||
assert.strictEqual(camelCase('xhr2 request'), 'xhr2Request');
|
||||
});
|
||||
|
||||
it('should handle acronyms', function() {
|
||||
lodashStable.each(['safe HTML', 'safeHTML'], function(string) {
|
||||
assert.strictEqual(camelCase(string), 'safeHtml');
|
||||
});
|
||||
|
||||
lodashStable.each(['escape HTML entities', 'escapeHTMLEntities'], function(string) {
|
||||
assert.strictEqual(camelCase(string), 'escapeHtmlEntities');
|
||||
});
|
||||
|
||||
lodashStable.each(['XMLHttpRequest', 'XmlHTTPRequest'], function(string) {
|
||||
assert.strictEqual(camelCase(string), 'xmlHttpRequest');
|
||||
});
|
||||
});
|
||||
});
|
||||
10
test/capitalize.test.js
Normal file
10
test/capitalize.test.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import assert from 'assert';
|
||||
import capitalize from '../capitalize.js';
|
||||
|
||||
describe('capitalize', function() {
|
||||
it('should capitalize the first character of a string', function() {
|
||||
assert.strictEqual(capitalize('fred'), 'Fred');
|
||||
assert.strictEqual(capitalize('Fred'), 'Fred');
|
||||
assert.strictEqual(capitalize(' fred'), ' fred');
|
||||
});
|
||||
});
|
||||
119
test/case-methods.js
Normal file
119
test/case-methods.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, stubTrue, burredLetters, deburredLetters } from './utils.js';
|
||||
import camelCase from '../camelCase.js';
|
||||
import kebabCase from '../kebabCase.js';
|
||||
import lowerCase from '../lowerCase.js';
|
||||
import snakeCase from '../snakeCase.js';
|
||||
import startCase from '../startCase.js';
|
||||
|
||||
describe('case methods', function() {
|
||||
lodashStable.each(['camel', 'kebab', 'lower', 'snake', 'start', 'upper'], function(caseName) {
|
||||
var methodName = caseName + 'Case',
|
||||
func = _[methodName];
|
||||
|
||||
var strings = [
|
||||
'foo bar', 'Foo bar', 'foo Bar', 'Foo Bar',
|
||||
'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__'
|
||||
];
|
||||
|
||||
var converted = (function() {
|
||||
switch (caseName) {
|
||||
case 'camel': return 'fooBar';
|
||||
case 'kebab': return 'foo-bar';
|
||||
case 'lower': return 'foo bar';
|
||||
case 'snake': return 'foo_bar';
|
||||
case 'start': return 'Foo Bar';
|
||||
case 'upper': return 'FOO BAR';
|
||||
}
|
||||
}());
|
||||
|
||||
it('`_.' + methodName + '` should convert `string` to ' + caseName + ' case', function() {
|
||||
var actual = lodashStable.map(strings, function(string) {
|
||||
var expected = (caseName == 'start' && string == 'FOO BAR') ? string : converted;
|
||||
return func(string) === expected;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue));
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should handle double-converting strings', function() {
|
||||
var actual = lodashStable.map(strings, function(string) {
|
||||
var expected = (caseName == 'start' && string == 'FOO BAR') ? string : converted;
|
||||
return func(func(string)) === expected;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue));
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should deburr letters', function() {
|
||||
var actual = lodashStable.map(burredLetters, function(burred, index) {
|
||||
var letter = deburredLetters[index].replace(/['\u2019]/g, '');
|
||||
if (caseName == 'start') {
|
||||
letter = letter == 'IJ' ? letter : lodashStable.capitalize(letter);
|
||||
} else if (caseName == 'upper') {
|
||||
letter = letter.toUpperCase();
|
||||
} else {
|
||||
letter = letter.toLowerCase();
|
||||
}
|
||||
return func(burred) === letter;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, lodashStable.map(burredLetters, stubTrue));
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should remove contraction apostrophes', function() {
|
||||
var postfixes = ['d', 'll', 'm', 're', 's', 't', 've'];
|
||||
|
||||
lodashStable.each(["'", '\u2019'], function(apos) {
|
||||
var actual = lodashStable.map(postfixes, function(postfix) {
|
||||
return func('a b' + apos + postfix + ' c');
|
||||
});
|
||||
|
||||
var expected = lodashStable.map(postfixes, function(postfix) {
|
||||
switch (caseName) {
|
||||
case 'camel': return 'aB' + postfix + 'C';
|
||||
case 'kebab': return 'a-b' + postfix + '-c';
|
||||
case 'lower': return 'a b' + postfix + ' c';
|
||||
case 'snake': return 'a_b' + postfix + '_c';
|
||||
case 'start': return 'A B' + postfix + ' C';
|
||||
case 'upper': return 'A B' + postfix.toUpperCase() + ' C';
|
||||
}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should remove Latin mathematical operators', function() {
|
||||
var actual = lodashStable.map(['\xd7', '\xf7'], func);
|
||||
assert.deepStrictEqual(actual, ['', '']);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should coerce `string` to a string', function() {
|
||||
var string = 'foo bar';
|
||||
assert.strictEqual(func(Object(string)), converted);
|
||||
assert.strictEqual(func({ 'toString': lodashStable.constant(string) }), converted);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return an unwrapped value implicitly when chaining', function() {
|
||||
assert.strictEqual(_('foo bar')[methodName](), converted);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() {
|
||||
assert.ok(_('foo bar').chain()[methodName]() instanceof _);
|
||||
});
|
||||
});
|
||||
|
||||
(function() {
|
||||
it('should get the original value after cycling through all case methods', function() {
|
||||
var funcs = [camelCase, kebabCase, lowerCase, snakeCase, startCase, lowerCase, camelCase];
|
||||
|
||||
var actual = lodashStable.reduce(funcs, function(result, func) {
|
||||
return func(result);
|
||||
}, 'enable 6h format');
|
||||
|
||||
assert.strictEqual(actual, 'enable6HFormat');
|
||||
});
|
||||
})();
|
||||
});
|
||||
23
test/castArray.test.js
Normal file
23
test/castArray.test.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey } from './utils.js';
|
||||
import castArray from '../castArray.js';
|
||||
|
||||
describe('castArray', function() {
|
||||
it('should wrap non-array items in an array', function() {
|
||||
var values = falsey.concat(true, 1, 'a', { 'a': 1 }),
|
||||
expected = lodashStable.map(values, function(value) { return [value]; }),
|
||||
actual = lodashStable.map(values, castArray);
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return array values by reference', function() {
|
||||
var array = [1];
|
||||
assert.strictEqual(castArray(array), array);
|
||||
});
|
||||
|
||||
it('should return an empty array when no arguments are given', function() {
|
||||
assert.deepStrictEqual(castArray(), []);
|
||||
});
|
||||
});
|
||||
74
test/chain.js
Normal file
74
test/chain.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { square } from './utils.js';
|
||||
import chain from '../chain.js';
|
||||
|
||||
describe('chain', function() {
|
||||
it('should return a wrapped value', function() {
|
||||
var actual = chain({ 'a': 0 });
|
||||
assert.ok(actual instanceof _);
|
||||
});
|
||||
|
||||
it('should return existing wrapped values', function() {
|
||||
var wrapped = _({ 'a': 0 });
|
||||
assert.strictEqual(chain(wrapped), wrapped);
|
||||
assert.strictEqual(wrapped.chain(), wrapped);
|
||||
});
|
||||
|
||||
it('should enable chaining for methods that return unwrapped values', function() {
|
||||
var array = ['c', 'b', 'a'];
|
||||
|
||||
assert.ok(chain(array).head() instanceof _);
|
||||
assert.ok(_(array).chain().head() instanceof _);
|
||||
|
||||
assert.ok(chain(array).isArray() instanceof _);
|
||||
assert.ok(_(array).chain().isArray() instanceof _);
|
||||
|
||||
assert.ok(chain(array).sortBy().head() instanceof _);
|
||||
assert.ok(_(array).chain().sortBy().head() instanceof _);
|
||||
});
|
||||
|
||||
it('should chain multiple methods', function() {
|
||||
lodashStable.times(2, function(index) {
|
||||
var array = ['one two three four', 'five six seven eight', 'nine ten eleven twelve'],
|
||||
expected = { ' ': 9, 'e': 14, 'f': 2, 'g': 1, 'h': 2, 'i': 4, 'l': 2, 'n': 6, 'o': 3, 'r': 2, 's': 2, 't': 5, 'u': 1, 'v': 4, 'w': 2, 'x': 1 },
|
||||
wrapped = index ? _(array).chain() : chain(array);
|
||||
|
||||
var actual = wrapped
|
||||
.chain()
|
||||
.map(function(value) { return value.split(''); })
|
||||
.flatten()
|
||||
.reduce(function(object, chr) {
|
||||
object[chr] || (object[chr] = 0);
|
||||
object[chr]++;
|
||||
return object;
|
||||
}, {})
|
||||
.value();
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
array = [1, 2, 3, 4, 5, 6];
|
||||
wrapped = index ? _(array).chain() : chain(array);
|
||||
actual = wrapped
|
||||
.chain()
|
||||
.filter(function(n) { return n % 2 != 0; })
|
||||
.reject(function(n) { return n % 3 == 0; })
|
||||
.sortBy(function(n) { return -n; })
|
||||
.value();
|
||||
|
||||
assert.deepStrictEqual(actual, [5, 1]);
|
||||
|
||||
array = [3, 4];
|
||||
wrapped = index ? _(array).chain() : chain(array);
|
||||
actual = wrapped
|
||||
.reverse()
|
||||
.concat([2, 1])
|
||||
.unshift(5)
|
||||
.tap(function(value) { value.pop(); })
|
||||
.map(square)
|
||||
.value();
|
||||
|
||||
assert.deepStrictEqual(actual, [25, 16, 9, 4]);
|
||||
});
|
||||
});
|
||||
});
|
||||
50
test/chunk.js
Normal file
50
test/chunk.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, stubArray } from './utils.js';
|
||||
import chunk from '../chunk.js';
|
||||
|
||||
describe('chunk', function() {
|
||||
var array = [0, 1, 2, 3, 4, 5];
|
||||
|
||||
it('should return chunked arrays', function() {
|
||||
var actual = chunk(array, 3);
|
||||
assert.deepStrictEqual(actual, [[0, 1, 2], [3, 4, 5]]);
|
||||
});
|
||||
|
||||
it('should return the last chunk as remaining elements', function() {
|
||||
var actual = chunk(array, 4);
|
||||
assert.deepStrictEqual(actual, [[0, 1, 2, 3], [4, 5]]);
|
||||
});
|
||||
|
||||
it('should treat falsey `size` values, except `undefined`, as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return value === undefined ? [[0], [1], [2], [3], [4], [5]] : [];
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(size, index) {
|
||||
return index ? chunk(array, size) : chunk(array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should ensure the minimum `size` is `0`', function() {
|
||||
var values = lodashStable.reject(falsey, lodashStable.isUndefined).concat(-1, -Infinity),
|
||||
expected = lodashStable.map(values, stubArray);
|
||||
|
||||
var actual = lodashStable.map(values, function(n) {
|
||||
return chunk(array, n);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should coerce `size` to an integer', function() {
|
||||
assert.deepStrictEqual(chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var actual = lodashStable.map([[1, 2], [3, 4]], chunk);
|
||||
assert.deepStrictEqual(actual, [[[1], [2]], [[3], [4]]]);
|
||||
});
|
||||
});
|
||||
58
test/clamp.js
Normal file
58
test/clamp.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import assert from 'assert';
|
||||
import clamp from '../clamp.js';
|
||||
|
||||
describe('clamp', function() {
|
||||
it('should work with a `max`', function() {
|
||||
assert.strictEqual(clamp(5, 3), 3);
|
||||
assert.strictEqual(clamp(1, 3), 1);
|
||||
});
|
||||
|
||||
it('should clamp negative numbers', function() {
|
||||
assert.strictEqual(clamp(-10, -5, 5), -5);
|
||||
assert.strictEqual(clamp(-10.2, -5.5, 5.5), -5.5);
|
||||
assert.strictEqual(clamp(-Infinity, -5, 5), -5);
|
||||
});
|
||||
|
||||
it('should clamp positive numbers', function() {
|
||||
assert.strictEqual(clamp(10, -5, 5), 5);
|
||||
assert.strictEqual(clamp(10.6, -5.6, 5.4), 5.4);
|
||||
assert.strictEqual(clamp(Infinity, -5, 5), 5);
|
||||
});
|
||||
|
||||
it('should not alter negative numbers in range', function() {
|
||||
assert.strictEqual(clamp(-4, -5, 5), -4);
|
||||
assert.strictEqual(clamp(-5, -5, 5), -5);
|
||||
assert.strictEqual(clamp(-5.5, -5.6, 5.6), -5.5);
|
||||
});
|
||||
|
||||
it('should not alter positive numbers in range', function() {
|
||||
assert.strictEqual(clamp(4, -5, 5), 4);
|
||||
assert.strictEqual(clamp(5, -5, 5), 5);
|
||||
assert.strictEqual(clamp(4.5, -5.1, 5.2), 4.5);
|
||||
});
|
||||
|
||||
it('should not alter `0` in range', function() {
|
||||
assert.strictEqual(1 / clamp(0, -5, 5), Infinity);
|
||||
});
|
||||
|
||||
it('should clamp to `0`', function() {
|
||||
assert.strictEqual(1 / clamp(-10, 0, 5), Infinity);
|
||||
});
|
||||
|
||||
it('should not alter `-0` in range', function() {
|
||||
assert.strictEqual(1 / clamp(-0, -5, 5), -Infinity);
|
||||
});
|
||||
|
||||
it('should clamp to `-0`', function() {
|
||||
assert.strictEqual(1 / clamp(-10, -0, 5), -Infinity);
|
||||
});
|
||||
|
||||
it('should return `NaN` when `number` is `NaN`', function() {
|
||||
assert.deepStrictEqual(clamp(NaN, -5, 5), NaN);
|
||||
});
|
||||
|
||||
it('should coerce `min` and `max` of `NaN` to `0`', function() {
|
||||
assert.deepStrictEqual(clamp(1, -5, NaN), 0);
|
||||
assert.deepStrictEqual(clamp(-1, NaN, 5), 0);
|
||||
});
|
||||
});
|
||||
429
test/clone-methods.js
Normal file
429
test/clone-methods.js
Normal file
@@ -0,0 +1,429 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
|
||||
import {
|
||||
map,
|
||||
set,
|
||||
realm,
|
||||
body,
|
||||
asyncFunc,
|
||||
genFunc,
|
||||
errors,
|
||||
_,
|
||||
LARGE_ARRAY_SIZE,
|
||||
isNpm,
|
||||
mapCaches,
|
||||
arrayBuffer,
|
||||
stubTrue,
|
||||
objectProto,
|
||||
symbol,
|
||||
defineProperty,
|
||||
getSymbols,
|
||||
document,
|
||||
arrayViews,
|
||||
slice,
|
||||
noop,
|
||||
} from './utils.js';
|
||||
|
||||
import cloneDeep from '../cloneDeep.js';
|
||||
import cloneDeepWith from '../cloneDeepWith.js';
|
||||
import last from '../last.js';
|
||||
|
||||
describe('clone methods', function() {
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
}
|
||||
Foo.prototype.b = 1;
|
||||
Foo.c = function() {};
|
||||
|
||||
if (Map) {
|
||||
var map = new Map;
|
||||
map.set('a', 1);
|
||||
map.set('b', 2);
|
||||
}
|
||||
if (Set) {
|
||||
var set = new Set;
|
||||
set.add(1);
|
||||
set.add(2);
|
||||
}
|
||||
var objects = {
|
||||
'`arguments` objects': arguments,
|
||||
'arrays': ['a', ''],
|
||||
'array-like objects': { '0': 'a', 'length': 1 },
|
||||
'booleans': false,
|
||||
'boolean objects': Object(false),
|
||||
'date objects': new Date,
|
||||
'Foo instances': new Foo,
|
||||
'objects': { 'a': 0, 'b': 1, 'c': 2 },
|
||||
'objects with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
|
||||
'objects from another document': realm.object || {},
|
||||
'maps': map,
|
||||
'null values': null,
|
||||
'numbers': 0,
|
||||
'number objects': Object(0),
|
||||
'regexes': /a/gim,
|
||||
'sets': set,
|
||||
'strings': 'a',
|
||||
'string objects': Object('a'),
|
||||
'undefined values': undefined
|
||||
};
|
||||
|
||||
objects.arrays.length = 3;
|
||||
|
||||
var uncloneable = {
|
||||
'DOM elements': body,
|
||||
'functions': Foo,
|
||||
'async functions': asyncFunc,
|
||||
'generator functions': genFunc,
|
||||
'the `Proxy` constructor': Proxy
|
||||
};
|
||||
|
||||
lodashStable.each(errors, function(error) {
|
||||
uncloneable[error.name + 's'] = error;
|
||||
});
|
||||
|
||||
it('`_.clone` should perform a shallow clone', function() {
|
||||
var array = [{ 'a': 0 }, { 'b': 1 }],
|
||||
actual = _.clone(array);
|
||||
|
||||
assert.deepStrictEqual(actual, array);
|
||||
assert.ok(actual !== array && actual[0] === array[0]);
|
||||
});
|
||||
|
||||
it('`_.cloneDeep` should deep clone objects with circular references', function() {
|
||||
var object = {
|
||||
'foo': { 'b': { 'c': { 'd': {} } } },
|
||||
'bar': {}
|
||||
};
|
||||
|
||||
object.foo.b.c.d = object;
|
||||
object.bar.b = object.foo.b;
|
||||
|
||||
var actual = cloneDeep(object);
|
||||
assert.ok(actual.bar.b === actual.foo.b && actual === actual.foo.b.c.d && actual !== object);
|
||||
});
|
||||
|
||||
it('`_.cloneDeep` should deep clone objects with lots of circular references', function() {
|
||||
var cyclical = {};
|
||||
lodashStable.times(LARGE_ARRAY_SIZE + 1, function(index) {
|
||||
cyclical['v' + index] = [index ? cyclical['v' + (index - 1)] : cyclical];
|
||||
});
|
||||
|
||||
var clone = cloneDeep(cyclical),
|
||||
actual = clone['v' + LARGE_ARRAY_SIZE][0];
|
||||
|
||||
assert.strictEqual(actual, clone['v' + (LARGE_ARRAY_SIZE - 1)]);
|
||||
assert.notStrictEqual(actual, cyclical['v' + (LARGE_ARRAY_SIZE - 1)]);
|
||||
});
|
||||
|
||||
it('`_.cloneDeepWith` should provide `stack` to `customizer`', function() {
|
||||
var actual;
|
||||
|
||||
cloneDeepWith({ 'a': 1 }, function() {
|
||||
actual = last(arguments);
|
||||
});
|
||||
|
||||
assert.ok(isNpm
|
||||
? actual.constructor.name == 'Stack'
|
||||
: actual instanceof mapCaches.Stack
|
||||
);
|
||||
});
|
||||
|
||||
lodashStable.each(['clone', 'cloneDeep'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isDeep = methodName == 'cloneDeep';
|
||||
|
||||
lodashStable.forOwn(objects, function(object, kind) {
|
||||
it('`_.' + methodName + '` should clone ' + kind, function() {
|
||||
var actual = func(object);
|
||||
assert.ok(lodashStable.isEqual(actual, object));
|
||||
|
||||
if (lodashStable.isObject(object)) {
|
||||
assert.notStrictEqual(actual, object);
|
||||
} else {
|
||||
assert.strictEqual(actual, object);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone array buffers', function() {
|
||||
if (ArrayBuffer) {
|
||||
var actual = func(arrayBuffer);
|
||||
assert.strictEqual(actual.byteLength, arrayBuffer.byteLength);
|
||||
assert.notStrictEqual(actual, arrayBuffer);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone buffers', function() {
|
||||
if (Buffer) {
|
||||
var buffer = new Buffer([1, 2]),
|
||||
actual = func(buffer);
|
||||
|
||||
assert.strictEqual(actual.byteLength, buffer.byteLength);
|
||||
assert.strictEqual(actual.inspect(), buffer.inspect());
|
||||
assert.notStrictEqual(actual, buffer);
|
||||
|
||||
buffer[0] = 2;
|
||||
assert.strictEqual(actual[0], isDeep ? 2 : 1);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone `index` and `input` array properties', function() {
|
||||
var array = /c/.exec('abcde'),
|
||||
actual = func(array);
|
||||
|
||||
assert.strictEqual(actual.index, 2);
|
||||
assert.strictEqual(actual.input, 'abcde');
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone `lastIndex` regexp property', function() {
|
||||
var regexp = /c/g;
|
||||
regexp.exec('abcde');
|
||||
|
||||
assert.strictEqual(func(regexp).lastIndex, 3);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone expando properties', function() {
|
||||
var values = lodashStable.map([false, true, 1, 'a'], function(value) {
|
||||
var object = Object(value);
|
||||
object.a = 1;
|
||||
return object;
|
||||
});
|
||||
|
||||
var expected = lodashStable.map(values, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return func(value).a === 1;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone prototype objects', function() {
|
||||
var actual = func(Foo.prototype);
|
||||
|
||||
assert.ok(!(actual instanceof Foo));
|
||||
assert.deepStrictEqual(actual, { 'b': 1 });
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should set the `[[Prototype]]` of a clone', function() {
|
||||
assert.ok(func(new Foo) instanceof Foo);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should set the `[[Prototype]]` of a clone even when the `constructor` is incorrect', function() {
|
||||
Foo.prototype.constructor = Object;
|
||||
assert.ok(func(new Foo) instanceof Foo);
|
||||
Foo.prototype.constructor = Foo;
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should ensure `value` constructor is a function before using its `[[Prototype]]`', function() {
|
||||
Foo.prototype.constructor = null;
|
||||
assert.ok(!(func(new Foo) instanceof Foo));
|
||||
Foo.prototype.constructor = Foo;
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone properties that shadow those on `Object.prototype`', function() {
|
||||
var object = {
|
||||
'constructor': objectProto.constructor,
|
||||
'hasOwnProperty': objectProto.hasOwnProperty,
|
||||
'isPrototypeOf': objectProto.isPrototypeOf,
|
||||
'propertyIsEnumerable': objectProto.propertyIsEnumerable,
|
||||
'toLocaleString': objectProto.toLocaleString,
|
||||
'toString': objectProto.toString,
|
||||
'valueOf': objectProto.valueOf
|
||||
};
|
||||
|
||||
var actual = func(object);
|
||||
|
||||
assert.deepStrictEqual(actual, object);
|
||||
assert.notStrictEqual(actual, object);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone symbol properties', function() {
|
||||
function Foo() {
|
||||
this[symbol] = { 'c': 1 };
|
||||
}
|
||||
|
||||
if (Symbol) {
|
||||
var symbol2 = Symbol('b');
|
||||
Foo.prototype[symbol2] = 2;
|
||||
|
||||
var symbol3 = Symbol('c');
|
||||
defineProperty(Foo.prototype, symbol3, {
|
||||
'configurable': true,
|
||||
'enumerable': false,
|
||||
'writable': true,
|
||||
'value': 3
|
||||
});
|
||||
|
||||
var object = { 'a': { 'b': new Foo } };
|
||||
object[symbol] = { 'b': 1 };
|
||||
|
||||
var actual = func(object);
|
||||
if (isDeep) {
|
||||
assert.notStrictEqual(actual[symbol], object[symbol]);
|
||||
assert.notStrictEqual(actual.a, object.a);
|
||||
} else {
|
||||
assert.strictEqual(actual[symbol], object[symbol]);
|
||||
assert.strictEqual(actual.a, object.a);
|
||||
}
|
||||
assert.deepStrictEqual(actual[symbol], object[symbol]);
|
||||
assert.deepStrictEqual(getSymbols(actual.a.b), [symbol]);
|
||||
assert.deepStrictEqual(actual.a.b[symbol], object.a.b[symbol]);
|
||||
assert.deepStrictEqual(actual.a.b[symbol2], object.a.b[symbol2]);
|
||||
assert.deepStrictEqual(actual.a.b[symbol3], object.a.b[symbol3]);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should clone symbol objects', function() {
|
||||
if (Symbol) {
|
||||
assert.strictEqual(func(symbol), symbol);
|
||||
|
||||
var object = Object(symbol),
|
||||
actual = func(object);
|
||||
|
||||
assert.strictEqual(typeof actual, 'object');
|
||||
assert.strictEqual(typeof actual.valueOf(), 'symbol');
|
||||
assert.notStrictEqual(actual, object);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not clone symbol primitives', function() {
|
||||
if (Symbol) {
|
||||
assert.strictEqual(func(symbol), symbol);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not error on DOM elements', function() {
|
||||
if (document) {
|
||||
var element = document.createElement('div');
|
||||
|
||||
try {
|
||||
assert.deepStrictEqual(func(element), {});
|
||||
} catch (e) {
|
||||
assert.ok(false, e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should create an object from the same realm as `value`', function() {
|
||||
var props = [];
|
||||
|
||||
var objects = lodashStable.transform(_, function(result, value, key) {
|
||||
if (lodashStable.startsWith(key, '_') && lodashStable.isObject(value) &&
|
||||
!lodashStable.isArguments(value) && !lodashStable.isElement(value) &&
|
||||
!lodashStable.isFunction(value)) {
|
||||
props.push(lodashStable.capitalize(lodashStable.camelCase(key)));
|
||||
result.push(value);
|
||||
}
|
||||
}, []);
|
||||
|
||||
var expected = lodashStable.map(objects, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(objects, function(object) {
|
||||
var Ctor = object.constructor,
|
||||
result = func(object);
|
||||
|
||||
return result !== object && ((result instanceof Ctor) || !(new Ctor instanceof Ctor));
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected, props.join(', '));
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as an iteratee for methods like `_.map`', function() {
|
||||
var expected = [{ 'a': [0] }, { 'b': [1] }],
|
||||
actual = lodashStable.map(expected, func);
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
if (isDeep) {
|
||||
assert.ok(actual[0] !== expected[0] && actual[0].a !== expected[0].a && actual[1].b !== expected[1].b);
|
||||
} else {
|
||||
assert.ok(actual[0] !== expected[0] && actual[0].a === expected[0].a && actual[1].b === expected[1].b);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return a unwrapped value when chaining', function() {
|
||||
var object = objects.objects,
|
||||
actual = _(object)[methodName]();
|
||||
|
||||
assert.deepEqual(actual, object);
|
||||
assert.notStrictEqual(actual, object);
|
||||
});
|
||||
|
||||
lodashStable.each(arrayViews, function(type) {
|
||||
it('`_.' + methodName + '` should clone ' + type + ' values', function() {
|
||||
var Ctor = root[type];
|
||||
|
||||
lodashStable.times(2, function(index) {
|
||||
if (Ctor) {
|
||||
var buffer = new ArrayBuffer(24),
|
||||
view = index ? new Ctor(buffer, 8, 1) : new Ctor(buffer),
|
||||
actual = func(view);
|
||||
|
||||
assert.deepStrictEqual(actual, view);
|
||||
assert.notStrictEqual(actual, view);
|
||||
assert.strictEqual(actual.buffer === view.buffer, !isDeep);
|
||||
assert.strictEqual(actual.byteOffset, view.byteOffset);
|
||||
assert.strictEqual(actual.length, view.length);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
lodashStable.forOwn(uncloneable, function(value, key) {
|
||||
it('`_.' + methodName + '` should not clone ' + key, function() {
|
||||
if (value) {
|
||||
var object = { 'a': value, 'b': { 'c': value } },
|
||||
actual = func(object),
|
||||
expected = value === Foo ? { 'c': Foo.c } : {};
|
||||
|
||||
assert.deepStrictEqual(actual, object);
|
||||
assert.notStrictEqual(actual, object);
|
||||
assert.deepStrictEqual(func(value), expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
lodashStable.each(['cloneWith', 'cloneDeepWith'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isDeep = methodName == 'cloneDeepWith';
|
||||
|
||||
it('`_.' + methodName + '` should provide correct `customizer` arguments', function() {
|
||||
var argsList = [],
|
||||
object = new Foo;
|
||||
|
||||
func(object, function() {
|
||||
var length = arguments.length,
|
||||
args = slice.call(arguments, 0, length - (length > 1 ? 1 : 0));
|
||||
|
||||
argsList.push(args);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(argsList, isDeep ? [[object], [1, 'a', object]] : [[object]]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should handle cloning when `customizer` returns `undefined`', function() {
|
||||
var actual = func({ 'a': { 'b': 'c' } }, noop);
|
||||
assert.deepStrictEqual(actual, { 'a': { 'b': 'c' } });
|
||||
});
|
||||
|
||||
lodashStable.forOwn(uncloneable, function(value, key) {
|
||||
it('`_.' + methodName + '` should work with a `customizer` callback and ' + key, function() {
|
||||
var customizer = function(value) {
|
||||
return lodashStable.isPlainObject(value) ? undefined : value;
|
||||
};
|
||||
|
||||
var actual = func(value, customizer);
|
||||
assert.strictEqual(actual, value);
|
||||
|
||||
var object = { 'a': value, 'b': { 'c': value } };
|
||||
actual = func(object, customizer);
|
||||
|
||||
assert.deepStrictEqual(actual, object);
|
||||
assert.notStrictEqual(actual, object);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
42
test/compact.js
Normal file
42
test/compact.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE, _, falsey } from './utils.js';
|
||||
import compact from '../compact.js';
|
||||
import slice from '../slice.js';
|
||||
|
||||
describe('compact', function() {
|
||||
var largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null);
|
||||
|
||||
it('should filter falsey values', function() {
|
||||
var array = ['0', '1', '2'];
|
||||
assert.deepStrictEqual(compact(falsey.concat(array)), array);
|
||||
});
|
||||
|
||||
it('should work when in-between lazy operators', function() {
|
||||
var actual = _(falsey).thru(slice).compact().thru(slice).value();
|
||||
assert.deepEqual(actual, []);
|
||||
|
||||
actual = _(falsey).thru(slice).push(true, 1).compact().push('a').value();
|
||||
assert.deepEqual(actual, [true, 1, 'a']);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var actual = _(largeArray).slice(1).compact().reverse().take().value();
|
||||
assert.deepEqual(actual, _.take(compact(slice(largeArray, 1)).reverse()));
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence with a custom `_.iteratee`', function() {
|
||||
var iteratee = _.iteratee,
|
||||
pass = false;
|
||||
|
||||
_.iteratee = identity;
|
||||
|
||||
try {
|
||||
var actual = _(largeArray).slice(1).compact().value();
|
||||
pass = lodashStable.isEqual(actual, compact(slice(largeArray, 1)));
|
||||
} catch (e) {console.log(e);}
|
||||
|
||||
assert.ok(pass);
|
||||
_.iteratee = iteratee;
|
||||
});
|
||||
});
|
||||
65
test/concat.js
Normal file
65
test/concat.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import concat from '../concat.js';
|
||||
|
||||
describe('concat', function() {
|
||||
it('should shallow clone `array`', function() {
|
||||
var array = [1, 2, 3],
|
||||
actual = concat(array);
|
||||
|
||||
assert.deepStrictEqual(actual, array);
|
||||
assert.notStrictEqual(actual, array);
|
||||
});
|
||||
|
||||
it('should concat arrays and values', function() {
|
||||
var array = [1],
|
||||
actual = concat(array, 2, [3], [[4]]);
|
||||
|
||||
assert.deepStrictEqual(actual, [1, 2, 3, [4]]);
|
||||
assert.deepStrictEqual(array, [1]);
|
||||
});
|
||||
|
||||
it('should cast non-array `array` values to arrays', function() {
|
||||
var values = [, null, undefined, false, true, 1, NaN, 'a'];
|
||||
|
||||
var expected = lodashStable.map(values, function(value, index) {
|
||||
return index ? [value] : [];
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? concat(value) : concat();
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
expected = lodashStable.map(values, function(value) {
|
||||
return [value, 2, [3]];
|
||||
});
|
||||
|
||||
actual = lodashStable.map(values, function(value) {
|
||||
return concat(value, [2], [[3]]);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should treat sparse arrays as dense', function() {
|
||||
var expected = [],
|
||||
actual = concat(Array(1), Array(1));
|
||||
|
||||
expected.push(undefined, undefined);
|
||||
|
||||
assert.ok('0'in actual);
|
||||
assert.ok('1' in actual);
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return a new wrapped array', function() {
|
||||
var array = [1],
|
||||
wrapped = _(array).concat([2, 3]),
|
||||
actual = wrapped.value();
|
||||
|
||||
assert.deepEqual(array, [1]);
|
||||
assert.deepEqual(actual, [1, 2, 3]);
|
||||
});
|
||||
});
|
||||
65
test/cond.js
Normal file
65
test/cond.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, stubA, stubB, stubC, slice, stubFalse, stubTrue } from './utils.js';
|
||||
|
||||
describe('cond', function() {
|
||||
it('should create a conditional function', function() {
|
||||
var cond = _.cond([
|
||||
[lodashStable.matches({ 'a': 1 }), stubA],
|
||||
[lodashStable.matchesProperty('b', 1), stubB],
|
||||
[lodashStable.property('c'), stubC]
|
||||
]);
|
||||
|
||||
assert.strictEqual(cond({ 'a': 1, 'b': 2, 'c': 3 }), 'a');
|
||||
assert.strictEqual(cond({ 'a': 0, 'b': 1, 'c': 2 }), 'b');
|
||||
assert.strictEqual(cond({ 'a': -1, 'b': 0, 'c': 1 }), 'c');
|
||||
});
|
||||
|
||||
it('should provide arguments to functions', function() {
|
||||
var args1,
|
||||
args2,
|
||||
expected = ['a', 'b', 'c'];
|
||||
|
||||
var cond = _.cond([[
|
||||
function() { args1 || (args1 = slice.call(arguments)); return true; },
|
||||
function() { args2 || (args2 = slice.call(arguments)); }
|
||||
]]);
|
||||
|
||||
cond('a', 'b', 'c');
|
||||
|
||||
assert.deepStrictEqual(args1, expected);
|
||||
assert.deepStrictEqual(args2, expected);
|
||||
});
|
||||
|
||||
it('should work with predicate shorthands', function() {
|
||||
var cond = _.cond([
|
||||
[{ 'a': 1 }, stubA],
|
||||
[['b', 1], stubB],
|
||||
['c', stubC]
|
||||
]);
|
||||
|
||||
assert.strictEqual(cond({ 'a': 1, 'b': 2, 'c': 3 }), 'a');
|
||||
assert.strictEqual(cond({ 'a': 0, 'b': 1, 'c': 2 }), 'b');
|
||||
assert.strictEqual(cond({ 'a': -1, 'b': 0, 'c': 1 }), 'c');
|
||||
});
|
||||
|
||||
it('should return `undefined` when no condition is met', function() {
|
||||
var cond = _.cond([[stubFalse, stubA]]);
|
||||
assert.strictEqual(cond({ 'a': 1 }), undefined);
|
||||
});
|
||||
|
||||
it('should throw a TypeError if `pairs` is not composed of functions', function() {
|
||||
lodashStable.each([false, true], function(value) {
|
||||
assert.throws(function() { _.cond([[stubTrue, value]])(); }, TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
it('should use `this` binding of function for `pairs`', function() {
|
||||
var cond = _.cond([
|
||||
[function(a) { return this[a]; }, function(a, b) { return this[b]; }]
|
||||
]);
|
||||
|
||||
var object = { 'cond': cond, 'a': 1, 'b': 2 };
|
||||
assert.strictEqual(object.cond('a', 'b'), 2);
|
||||
});
|
||||
});
|
||||
153
test/conforms-methods.js
Normal file
153
test/conforms-methods.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, stubFalse, stubTrue, empties } from './utils.js';
|
||||
import conformsTo from '../conformsTo.js';
|
||||
|
||||
describe('conforms methods', function() {
|
||||
lodashStable.each(['conforms', 'conformsTo'], function(methodName) {
|
||||
var isConforms = methodName == 'conforms';
|
||||
|
||||
function conforms(source) {
|
||||
return isConforms ? _.conforms(source) : function(object) {
|
||||
return conformsTo(object, source);
|
||||
};
|
||||
}
|
||||
|
||||
it('`_.' + methodName + '` should check if `object` conforms to `source`', function() {
|
||||
var objects = [
|
||||
{ 'a': 1, 'b': 8 },
|
||||
{ 'a': 2, 'b': 4 },
|
||||
{ 'a': 3, 'b': 16 }
|
||||
];
|
||||
|
||||
var par = conforms({
|
||||
'b': function(value) { return value > 4; }
|
||||
});
|
||||
|
||||
var actual = lodashStable.filter(objects, par);
|
||||
assert.deepStrictEqual(actual, [objects[0], objects[2]]);
|
||||
|
||||
par = conforms({
|
||||
'b': function(value) { return value > 8; },
|
||||
'a': function(value) { return value > 1; }
|
||||
});
|
||||
|
||||
actual = lodashStable.filter(objects, par);
|
||||
assert.deepStrictEqual(actual, [objects[2]]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not match by inherited `source` properties', function() {
|
||||
function Foo() {
|
||||
this.a = function(value) {
|
||||
return value > 1;
|
||||
};
|
||||
}
|
||||
Foo.prototype.b = function(value) {
|
||||
return value > 8;
|
||||
};
|
||||
|
||||
var objects = [
|
||||
{ 'a': 1, 'b': 8 },
|
||||
{ 'a': 2, 'b': 4 },
|
||||
{ 'a': 3, 'b': 16 }
|
||||
];
|
||||
|
||||
var par = conforms(new Foo),
|
||||
actual = lodashStable.filter(objects, par);
|
||||
|
||||
assert.deepStrictEqual(actual, [objects[1], objects[2]]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not invoke `source` predicates for missing `object` properties', function() {
|
||||
var count = 0;
|
||||
|
||||
var par = conforms({
|
||||
'a': function() { count++; return true; }
|
||||
});
|
||||
|
||||
assert.strictEqual(par({}), false);
|
||||
assert.strictEqual(count, 0);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a function for `object`', function() {
|
||||
function Foo() {}
|
||||
Foo.a = 1;
|
||||
|
||||
function Bar() {}
|
||||
Bar.a = 2;
|
||||
|
||||
var par = conforms({
|
||||
'a': function(value) { return value > 1; }
|
||||
});
|
||||
|
||||
assert.strictEqual(par(Foo), false);
|
||||
assert.strictEqual(par(Bar), true);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a function for `source`', function() {
|
||||
function Foo() {}
|
||||
Foo.a = function(value) { return value > 1; };
|
||||
|
||||
var objects = [{ 'a': 1 }, { 'a': 2 }],
|
||||
actual = lodashStable.filter(objects, conforms(Foo));
|
||||
|
||||
assert.deepStrictEqual(actual, [objects[1]]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a non-plain `object`', function() {
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
}
|
||||
Foo.prototype.b = 2;
|
||||
|
||||
var par = conforms({
|
||||
'b': function(value) { return value > 1; }
|
||||
});
|
||||
|
||||
assert.strictEqual(par(new Foo), true);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `false` when `object` is nullish', function() {
|
||||
var values = [, null, undefined],
|
||||
expected = lodashStable.map(values, stubFalse);
|
||||
|
||||
var par = conforms({
|
||||
'a': function(value) { return value > 1; }
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
try {
|
||||
return index ? par(value) : par();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `true` when comparing an empty `source` to a nullish `object`', function() {
|
||||
var values = [, null, undefined],
|
||||
expected = lodashStable.map(values, stubTrue),
|
||||
par = conforms({});
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
try {
|
||||
return index ? par(value) : par();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `true` when comparing an empty `source`', function() {
|
||||
var object = { 'a': 1 },
|
||||
expected = lodashStable.map(empties, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(empties, function(value) {
|
||||
var par = conforms(value);
|
||||
return par(object);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
15
test/conforms.js
Normal file
15
test/conforms.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import assert from 'assert';
|
||||
import conforms from '../conforms.js';
|
||||
|
||||
describe('conforms', function() {
|
||||
it('should not change behavior if `source` is modified', function() {
|
||||
var object = { 'a': 2 },
|
||||
source = { 'a': function(value) { return value > 1; } },
|
||||
par = conforms(source);
|
||||
|
||||
assert.strictEqual(par(object), true);
|
||||
|
||||
source.a = function(value) { return value < 2; };
|
||||
assert.strictEqual(par(object), true);
|
||||
});
|
||||
});
|
||||
40
test/constant.js
Normal file
40
test/constant.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { empties, _, falsey, stubTrue } from './utils.js';
|
||||
|
||||
describe('constant', function() {
|
||||
it('should create a function that returns `value`', function() {
|
||||
var object = { 'a': 1 },
|
||||
values = Array(2).concat(empties, true, 1, 'a'),
|
||||
constant = _.constant(object);
|
||||
|
||||
var results = lodashStable.map(values, function(value, index) {
|
||||
if (index < 2) {
|
||||
return index ? constant.call({}) : constant();
|
||||
}
|
||||
return constant(value);
|
||||
});
|
||||
|
||||
assert.ok(lodashStable.every(results, function(result) {
|
||||
return result === object;
|
||||
}));
|
||||
});
|
||||
|
||||
it('should work with falsey values', function() {
|
||||
var expected = lodashStable.map(falsey, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(value, index) {
|
||||
var constant = index ? _.constant(value) : _.constant(),
|
||||
result = constant();
|
||||
|
||||
return (result === value) || (result !== result && value !== value);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var wrapped = _(true).constant();
|
||||
assert.ok(wrapped instanceof _);
|
||||
});
|
||||
});
|
||||
66
test/countBy.js
Normal file
66
test/countBy.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE } from './utils.js';
|
||||
import countBy from '../countBy.js';
|
||||
|
||||
describe('countBy', function() {
|
||||
var array = [6.1, 4.2, 6.3];
|
||||
|
||||
it('should transform keys by `iteratee`', function() {
|
||||
var actual = countBy(array, Math.floor);
|
||||
assert.deepStrictEqual(actual, { '4': 1, '6': 2 });
|
||||
});
|
||||
|
||||
it('should use `_.identity` when `iteratee` is nullish', function() {
|
||||
var array = [4, 6, 6],
|
||||
values = [, null, undefined],
|
||||
expected = lodashStable.map(values, lodashStable.constant({ '4': 1, '6': 2 }));
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? countBy(array, value) : countBy(array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with `_.property` shorthands', function() {
|
||||
var actual = countBy(['one', 'two', 'three'], 'length');
|
||||
assert.deepStrictEqual(actual, { '3': 2, '5': 1 });
|
||||
});
|
||||
|
||||
it('should only add values to own, not inherited, properties', function() {
|
||||
var actual = countBy(array, function(n) {
|
||||
return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual.constructor, 1);
|
||||
assert.deepStrictEqual(actual.hasOwnProperty, 2);
|
||||
});
|
||||
|
||||
it('should work with a number for `iteratee`', function() {
|
||||
var array = [
|
||||
[1, 'a'],
|
||||
[2, 'a'],
|
||||
[2, 'b']
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(countBy(array, 0), { '1': 1, '2': 2 });
|
||||
assert.deepStrictEqual(countBy(array, 1), { 'a': 2, 'b': 1 });
|
||||
});
|
||||
|
||||
it('should work with an object for `collection`', function() {
|
||||
var actual = countBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor);
|
||||
assert.deepStrictEqual(actual, { '4': 1, '6': 2 });
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(LARGE_ARRAY_SIZE).concat(
|
||||
lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE),
|
||||
lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE)
|
||||
);
|
||||
|
||||
var actual = _(array).countBy().map(square).filter(isEven).take().value();
|
||||
|
||||
assert.deepEqual(actual, _.take(_.filter(_.map(countBy(array), square), isEven)));
|
||||
});
|
||||
});
|
||||
88
test/create.js
Normal file
88
test/create.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, stubObject, primitives, stubTrue } from './utils.js';
|
||||
import create from '../create.js';
|
||||
import keys from '../keys.js';
|
||||
|
||||
describe('create', function() {
|
||||
function Shape() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
}
|
||||
|
||||
function Circle() {
|
||||
Shape.call(this);
|
||||
}
|
||||
|
||||
it('should create an object that inherits from the given `prototype` object', function() {
|
||||
Circle.prototype = create(Shape.prototype);
|
||||
Circle.prototype.constructor = Circle;
|
||||
|
||||
var actual = new Circle;
|
||||
|
||||
assert.ok(actual instanceof Circle);
|
||||
assert.ok(actual instanceof Shape);
|
||||
assert.notStrictEqual(Circle.prototype, Shape.prototype);
|
||||
});
|
||||
|
||||
it('should assign `properties` to the created object', function() {
|
||||
var expected = { 'constructor': Circle, 'radius': 0 };
|
||||
Circle.prototype = create(Shape.prototype, expected);
|
||||
|
||||
var actual = new Circle;
|
||||
|
||||
assert.ok(actual instanceof Circle);
|
||||
assert.ok(actual instanceof Shape);
|
||||
assert.deepStrictEqual(Circle.prototype, expected);
|
||||
});
|
||||
|
||||
it('should assign own properties', function() {
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
this.c = 3;
|
||||
}
|
||||
Foo.prototype.b = 2;
|
||||
|
||||
assert.deepStrictEqual(create({}, new Foo), { 'a': 1, 'c': 3 });
|
||||
});
|
||||
|
||||
it('should assign properties that shadow those of `prototype`', function() {
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
}
|
||||
var object = create(new Foo, { 'a': 1 });
|
||||
assert.deepStrictEqual(lodashStable.keys(object), ['a']);
|
||||
});
|
||||
|
||||
it('should accept a falsey `prototype`', function() {
|
||||
var expected = lodashStable.map(falsey, stubObject);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(prototype, index) {
|
||||
return index ? create(prototype) : create();
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should ignore a primitive `prototype` and use an empty object instead', function() {
|
||||
var expected = lodashStable.map(primitives, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(primitives, function(value, index) {
|
||||
return lodashStable.isPlainObject(index ? create(value) : create());
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [{ 'a': 1 }, { 'a': 1 }, { 'a': 1 }],
|
||||
expected = lodashStable.map(array, stubTrue),
|
||||
objects = lodashStable.map(array, create);
|
||||
|
||||
var actual = lodashStable.map(objects, function(object) {
|
||||
return object.a === 1 && !keys(object).length;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
52
test/curry-methods.js
Normal file
52
test/curry-methods.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, slice } from './utils.js';
|
||||
import curry from '../curry.js';
|
||||
|
||||
describe('curry methods', function() {
|
||||
lodashStable.each(['curry', 'curryRight'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
fn = function(a, b) { return slice.call(arguments); },
|
||||
isCurry = methodName == 'curry';
|
||||
|
||||
it('`_.' + methodName + '` should not error on functions with the same name as lodash methods', function() {
|
||||
function run(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
var curried = func(run);
|
||||
|
||||
try {
|
||||
var actual = curried(1)(2);
|
||||
} catch (e) {}
|
||||
|
||||
assert.strictEqual(actual, 3);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work for function names that shadow those on `Object.prototype`', function() {
|
||||
var curried = curry(function hasOwnProperty(a, b, c) {
|
||||
return [a, b, c];
|
||||
});
|
||||
|
||||
var expected = [1, 2, 3];
|
||||
|
||||
assert.deepStrictEqual(curried(1)(2)(3), expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [fn, fn, fn],
|
||||
object = { 'a': fn, 'b': fn, 'c': fn };
|
||||
|
||||
lodashStable.each([array, object], function(collection) {
|
||||
var curries = lodashStable.map(collection, func),
|
||||
expected = lodashStable.map(collection, lodashStable.constant(isCurry ? ['a', 'b'] : ['b', 'a']));
|
||||
|
||||
var actual = lodashStable.map(curries, function(curried) {
|
||||
return curried('a')('b');
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
135
test/curry.js
Normal file
135
test/curry.js
Normal file
@@ -0,0 +1,135 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { slice, stubArray } from './utils.js';
|
||||
import curry from '../curry.js';
|
||||
import placeholder from '../placeholder.js';
|
||||
import bind from '../bind.js';
|
||||
import partial from '../partial.js';
|
||||
import partialRight from '../partialRight.js';
|
||||
|
||||
describe('curry', function() {
|
||||
function fn(a, b, c, d) {
|
||||
return slice.call(arguments);
|
||||
}
|
||||
|
||||
it('should curry based on the number of arguments given', function() {
|
||||
var curried = curry(fn),
|
||||
expected = [1, 2, 3, 4];
|
||||
|
||||
assert.deepStrictEqual(curried(1)(2)(3)(4), expected);
|
||||
assert.deepStrictEqual(curried(1, 2)(3, 4), expected);
|
||||
assert.deepStrictEqual(curried(1, 2, 3, 4), expected);
|
||||
});
|
||||
|
||||
it('should allow specifying `arity`', function() {
|
||||
var curried = curry(fn, 3),
|
||||
expected = [1, 2, 3];
|
||||
|
||||
assert.deepStrictEqual(curried(1)(2, 3), expected);
|
||||
assert.deepStrictEqual(curried(1, 2)(3), expected);
|
||||
assert.deepStrictEqual(curried(1, 2, 3), expected);
|
||||
});
|
||||
|
||||
it('should coerce `arity` to an integer', function() {
|
||||
var values = ['0', 0.6, 'xyz'],
|
||||
expected = lodashStable.map(values, stubArray);
|
||||
|
||||
var actual = lodashStable.map(values, function(arity) {
|
||||
return curry(fn, arity)();
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
assert.deepStrictEqual(curry(fn, '2')(1)(2), [1, 2]);
|
||||
});
|
||||
|
||||
it('should support placeholders', function() {
|
||||
var curried = curry(fn),
|
||||
ph = curried.placeholder;
|
||||
|
||||
assert.deepStrictEqual(curried(1)(ph, 3)(ph, 4)(2), [1, 2, 3, 4]);
|
||||
assert.deepStrictEqual(curried(ph, 2)(1)(ph, 4)(3), [1, 2, 3, 4]);
|
||||
assert.deepStrictEqual(curried(ph, ph, 3)(ph, 2)(ph, 4)(1), [1, 2, 3, 4]);
|
||||
assert.deepStrictEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), [1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
it('should persist placeholders', function() {
|
||||
var curried = curry(fn),
|
||||
ph = curried.placeholder,
|
||||
actual = curried(ph, ph, ph, 'd')('a')(ph)('b')('c');
|
||||
|
||||
assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd']);
|
||||
});
|
||||
|
||||
it('should use `_.placeholder` when set', function() {
|
||||
var curried = curry(fn),
|
||||
_ph = placeholder = {},
|
||||
ph = curried.placeholder;
|
||||
|
||||
assert.deepEqual(curried(1)(_ph, 3)(ph, 4), [1, ph, 3, 4]);
|
||||
delete placeholder;
|
||||
});
|
||||
|
||||
it('should provide additional arguments after reaching the target arity', function() {
|
||||
var curried = curry(fn, 3);
|
||||
assert.deepStrictEqual(curried(1)(2, 3, 4), [1, 2, 3, 4]);
|
||||
assert.deepStrictEqual(curried(1, 2)(3, 4, 5), [1, 2, 3, 4, 5]);
|
||||
assert.deepStrictEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
it('should create a function with a `length` of `0`', function() {
|
||||
lodashStable.times(2, function(index) {
|
||||
var curried = index ? curry(fn, 4) : curry(fn);
|
||||
assert.strictEqual(curried.length, 0);
|
||||
assert.strictEqual(curried(1).length, 0);
|
||||
assert.strictEqual(curried(1, 2).length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should ensure `new curried` is an instance of `func`', function() {
|
||||
function Foo(value) {
|
||||
return value && object;
|
||||
}
|
||||
|
||||
var curried = curry(Foo),
|
||||
object = {};
|
||||
|
||||
assert.ok(new curried(false) instanceof Foo);
|
||||
assert.strictEqual(new curried(true), object);
|
||||
});
|
||||
|
||||
it('should use `this` binding of function', function() {
|
||||
var fn = function(a, b, c) {
|
||||
var value = this || {};
|
||||
return [value[a], value[b], value[c]];
|
||||
};
|
||||
|
||||
var object = { 'a': 1, 'b': 2, 'c': 3 },
|
||||
expected = [1, 2, 3];
|
||||
|
||||
assert.deepStrictEqual(curry(bind(fn, object), 3)('a')('b')('c'), expected);
|
||||
assert.deepStrictEqual(curry(bind(fn, object), 3)('a', 'b')('c'), expected);
|
||||
assert.deepStrictEqual(curry(bind(fn, object), 3)('a', 'b', 'c'), expected);
|
||||
|
||||
assert.deepStrictEqual(bind(curry(fn), object)('a')('b')('c'), Array(3));
|
||||
assert.deepStrictEqual(bind(curry(fn), object)('a', 'b')('c'), Array(3));
|
||||
assert.deepStrictEqual(bind(curry(fn), object)('a', 'b', 'c'), expected);
|
||||
|
||||
object.curried = curry(fn);
|
||||
assert.deepStrictEqual(object.curried('a')('b')('c'), Array(3));
|
||||
assert.deepStrictEqual(object.curried('a', 'b')('c'), Array(3));
|
||||
assert.deepStrictEqual(object.curried('a', 'b', 'c'), expected);
|
||||
});
|
||||
|
||||
it('should work with partialed methods', function() {
|
||||
var curried = curry(fn),
|
||||
expected = [1, 2, 3, 4];
|
||||
|
||||
var a = partial(curried, 1),
|
||||
b = bind(a, null, 2),
|
||||
c = partialRight(b, 4),
|
||||
d = partialRight(b(3), 4);
|
||||
|
||||
assert.deepStrictEqual(c(3), expected);
|
||||
assert.deepStrictEqual(d(), expected);
|
||||
});
|
||||
});
|
||||
136
test/curryRight.js
Normal file
136
test/curryRight.js
Normal file
@@ -0,0 +1,136 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { slice, stubArray } from './utils.js';
|
||||
import curryRight from '../curryRight.js';
|
||||
import placeholder from '../placeholder.js';
|
||||
import bind from '../bind.js';
|
||||
import partialRight from '../partialRight.js';
|
||||
import partial from '../partial.js';
|
||||
|
||||
describe('curryRight', function() {
|
||||
function fn(a, b, c, d) {
|
||||
return slice.call(arguments);
|
||||
}
|
||||
|
||||
it('should curry based on the number of arguments given', function() {
|
||||
var curried = curryRight(fn),
|
||||
expected = [1, 2, 3, 4];
|
||||
|
||||
assert.deepStrictEqual(curried(4)(3)(2)(1), expected);
|
||||
assert.deepStrictEqual(curried(3, 4)(1, 2), expected);
|
||||
assert.deepStrictEqual(curried(1, 2, 3, 4), expected);
|
||||
});
|
||||
|
||||
it('should allow specifying `arity`', function() {
|
||||
var curried = curryRight(fn, 3),
|
||||
expected = [1, 2, 3];
|
||||
|
||||
assert.deepStrictEqual(curried(3)(1, 2), expected);
|
||||
assert.deepStrictEqual(curried(2, 3)(1), expected);
|
||||
assert.deepStrictEqual(curried(1, 2, 3), expected);
|
||||
});
|
||||
|
||||
it('should coerce `arity` to an integer', function() {
|
||||
var values = ['0', 0.6, 'xyz'],
|
||||
expected = lodashStable.map(values, stubArray);
|
||||
|
||||
var actual = lodashStable.map(values, function(arity) {
|
||||
return curryRight(fn, arity)();
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
assert.deepStrictEqual(curryRight(fn, '2')(1)(2), [2, 1]);
|
||||
});
|
||||
|
||||
it('should support placeholders', function() {
|
||||
var curried = curryRight(fn),
|
||||
expected = [1, 2, 3, 4],
|
||||
ph = curried.placeholder;
|
||||
|
||||
assert.deepStrictEqual(curried(4)(2, ph)(1, ph)(3), expected);
|
||||
assert.deepStrictEqual(curried(3, ph)(4)(1, ph)(2), expected);
|
||||
assert.deepStrictEqual(curried(ph, ph, 4)(ph, 3)(ph, 2)(1), expected);
|
||||
assert.deepStrictEqual(curried(ph, ph, ph, 4)(ph, ph, 3)(ph, 2)(1), expected);
|
||||
});
|
||||
|
||||
it('should persist placeholders', function() {
|
||||
var curried = curryRight(fn),
|
||||
ph = curried.placeholder,
|
||||
actual = curried('a', ph, ph, ph)('b')(ph)('c')('d');
|
||||
|
||||
assert.deepStrictEqual(actual, ['a', 'b', 'c', 'd']);
|
||||
});
|
||||
|
||||
it('should use `_.placeholder` when set', function() {
|
||||
var curried = curryRight(fn),
|
||||
_ph = placeholder = {},
|
||||
ph = curried.placeholder;
|
||||
|
||||
assert.deepEqual(curried(4)(2, _ph)(1, ph), [1, 2, ph, 4]);
|
||||
delete placeholder;
|
||||
});
|
||||
|
||||
it('should provide additional arguments after reaching the target arity', function() {
|
||||
var curried = curryRight(fn, 3);
|
||||
assert.deepStrictEqual(curried(4)(1, 2, 3), [1, 2, 3, 4]);
|
||||
assert.deepStrictEqual(curried(4, 5)(1, 2, 3), [1, 2, 3, 4, 5]);
|
||||
assert.deepStrictEqual(curried(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
it('should create a function with a `length` of `0`', function() {
|
||||
lodashStable.times(2, function(index) {
|
||||
var curried = index ? curryRight(fn, 4) : curryRight(fn);
|
||||
assert.strictEqual(curried.length, 0);
|
||||
assert.strictEqual(curried(4).length, 0);
|
||||
assert.strictEqual(curried(3, 4).length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should ensure `new curried` is an instance of `func`', function() {
|
||||
function Foo(value) {
|
||||
return value && object;
|
||||
}
|
||||
|
||||
var curried = curryRight(Foo),
|
||||
object = {};
|
||||
|
||||
assert.ok(new curried(false) instanceof Foo);
|
||||
assert.strictEqual(new curried(true), object);
|
||||
});
|
||||
|
||||
it('should use `this` binding of function', function() {
|
||||
var fn = function(a, b, c) {
|
||||
var value = this || {};
|
||||
return [value[a], value[b], value[c]];
|
||||
};
|
||||
|
||||
var object = { 'a': 1, 'b': 2, 'c': 3 },
|
||||
expected = [1, 2, 3];
|
||||
|
||||
assert.deepStrictEqual(curryRight(bind(fn, object), 3)('c')('b')('a'), expected);
|
||||
assert.deepStrictEqual(curryRight(bind(fn, object), 3)('b', 'c')('a'), expected);
|
||||
assert.deepStrictEqual(curryRight(bind(fn, object), 3)('a', 'b', 'c'), expected);
|
||||
|
||||
assert.deepStrictEqual(bind(curryRight(fn), object)('c')('b')('a'), Array(3));
|
||||
assert.deepStrictEqual(bind(curryRight(fn), object)('b', 'c')('a'), Array(3));
|
||||
assert.deepStrictEqual(bind(curryRight(fn), object)('a', 'b', 'c'), expected);
|
||||
|
||||
object.curried = curryRight(fn);
|
||||
assert.deepStrictEqual(object.curried('c')('b')('a'), Array(3));
|
||||
assert.deepStrictEqual(object.curried('b', 'c')('a'), Array(3));
|
||||
assert.deepStrictEqual(object.curried('a', 'b', 'c'), expected);
|
||||
});
|
||||
|
||||
it('should work with partialed methods', function() {
|
||||
var curried = curryRight(fn),
|
||||
expected = [1, 2, 3, 4];
|
||||
|
||||
var a = partialRight(curried, 4),
|
||||
b = partialRight(a, 3),
|
||||
c = bind(b, null, 1),
|
||||
d = partial(b(2), 1);
|
||||
|
||||
assert.deepStrictEqual(c(2), expected);
|
||||
assert.deepStrictEqual(d(), expected);
|
||||
});
|
||||
});
|
||||
270
test/custom-_.iteratee-methods.js
Normal file
270
test/custom-_.iteratee-methods.js
Normal file
@@ -0,0 +1,270 @@
|
||||
import assert from 'assert';
|
||||
import partial from '../partial.js';
|
||||
import property from '../property.js';
|
||||
import iteratee from '../iteratee.js';
|
||||
|
||||
describe('custom `_.iteratee` methods', function() {
|
||||
var array = ['one', 'two', 'three'],
|
||||
getPropA = partial(property, 'a'),
|
||||
getPropB = partial(property, 'b'),
|
||||
getLength = partial(property, 'length'),
|
||||
iteratee = iteratee;
|
||||
|
||||
var getSum = function() {
|
||||
return function(result, object) {
|
||||
return result + object.a;
|
||||
};
|
||||
};
|
||||
|
||||
var objects = [
|
||||
{ 'a': 0, 'b': 0 },
|
||||
{ 'a': 1, 'b': 0 },
|
||||
{ 'a': 1, 'b': 1 }
|
||||
];
|
||||
|
||||
it('`_.countBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getLength;
|
||||
assert.deepEqual(_.countBy(array), { '3': 2, '5': 1 });
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.differenceBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.differenceBy(objects, [objects[1]]), [objects[0]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.dropRightWhile` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.dropRightWhile(objects), objects.slice(0, 2));
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.dropWhile` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2));
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.every` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.every(objects.slice(1)), true);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.filter` should use `_.iteratee` internally', function() {
|
||||
var objects = [{ 'a': 0 }, { 'a': 1 }];
|
||||
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.filter(objects), [objects[1]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.find` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.find(objects), objects[1]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.findIndex` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.findIndex(objects), 1);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.findLast` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.findLast(objects), objects[2]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.findLastIndex` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.findLastIndex(objects), 2);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.findKey` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.strictEqual(_.findKey(objects), '2');
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.findLastKey` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.strictEqual(_.findLastKey(objects), '2');
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.groupBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getLength;
|
||||
assert.deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] });
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.intersectionBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.intersectionBy(objects, [objects[2]]), [objects[1]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.keyBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getLength;
|
||||
assert.deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' });
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.map` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.map(objects), [0, 1, 1]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.mapKeys` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.mapKeys({ 'a': { 'b': 2 } }), { '2': { 'b': 2 } });
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.mapValues` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.mapValues({ 'a': { 'b': 2 } }), { 'a': 2 });
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.maxBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.maxBy(objects), objects[2]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.meanBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.meanBy(objects), 2 / 3);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.minBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.minBy(objects), objects[0]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.partition` should use `_.iteratee` internally', function() {
|
||||
var objects = [{ 'a': 1 }, { 'a': 1 }, { 'b': 2 }];
|
||||
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.partition(objects), [objects.slice(0, 2), objects.slice(2)]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.pullAllBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.pullAllBy(objects.slice(), [{ 'a': 1, 'b': 0 }]), [objects[0]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.reduce` should use `_.iteratee` internally', function() {
|
||||
iteratee = getSum;
|
||||
assert.strictEqual(_.reduce(objects, undefined, 0), 2);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.reduceRight` should use `_.iteratee` internally', function() {
|
||||
iteratee = getSum;
|
||||
assert.strictEqual(_.reduceRight(objects, undefined, 0), 2);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.reject` should use `_.iteratee` internally', function() {
|
||||
var objects = [{ 'a': 0 }, { 'a': 1 }];
|
||||
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.reject(objects), [objects[0]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.remove` should use `_.iteratee` internally', function() {
|
||||
var objects = [{ 'a': 0 }, { 'a': 1 }];
|
||||
|
||||
iteratee = getPropA;
|
||||
_.remove(objects);
|
||||
assert.deepEqual(objects, [{ 'a': 0 }]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.some` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.strictEqual(_.some(objects), true);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.sortBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.sortedIndexBy` should use `_.iteratee` internally', function() {
|
||||
var objects = [{ 'a': 30 }, { 'a': 50 }];
|
||||
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.sortedIndexBy(objects, { 'a': 40 }), 1);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.sortedLastIndexBy` should use `_.iteratee` internally', function() {
|
||||
var objects = [{ 'a': 30 }, { 'a': 50 }];
|
||||
|
||||
iteratee = getPropA;
|
||||
assert.strictEqual(_.sortedLastIndexBy(objects, { 'a': 40 }), 1);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.sumBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.strictEqual(_.sumBy(objects), 1);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.takeRightWhile` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.takeRightWhile(objects), objects.slice(2));
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.takeWhile` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2));
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.transform` should use `_.iteratee` internally', function() {
|
||||
iteratee = function() {
|
||||
return function(result, object) {
|
||||
result.sum += object.a;
|
||||
};
|
||||
};
|
||||
|
||||
assert.deepEqual(_.transform(objects, undefined, { 'sum': 0 }), { 'sum': 2 });
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.uniqBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.uniqBy(objects), [objects[0], objects[2]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.unionBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropB;
|
||||
assert.deepEqual(_.unionBy(objects.slice(0, 1), [objects[2]]), [objects[0], objects[2]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
|
||||
it('`_.xorBy` should use `_.iteratee` internally', function() {
|
||||
iteratee = getPropA;
|
||||
assert.deepEqual(_.xorBy(objects, objects.slice(1)), [objects[0]]);
|
||||
iteratee = iteratee;
|
||||
});
|
||||
});
|
||||
167
test/debounce-and-throttle.js
Normal file
167
test/debounce-and-throttle.js
Normal file
@@ -0,0 +1,167 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, noop, push, isModularize } from './utils.js';
|
||||
import runInContext from '../runInContext.js';
|
||||
|
||||
describe('debounce and throttle', function() {
|
||||
lodashStable.each(['debounce', 'throttle'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isDebounce = methodName == 'debounce';
|
||||
|
||||
it('`_.' + methodName + '` should not error for non-object `options` values', function() {
|
||||
func(noop, 32, 1);
|
||||
assert.ok(true);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should use a default `wait` of `0`', function(done) {
|
||||
var callCount = 0,
|
||||
funced = func(function() { callCount++; });
|
||||
|
||||
funced();
|
||||
|
||||
setTimeout(function() {
|
||||
funced();
|
||||
assert.strictEqual(callCount, isDebounce ? 1 : 2);
|
||||
done();
|
||||
}, 32);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should invoke `func` with the correct `this` binding', function(done) {
|
||||
var actual = [],
|
||||
object = { 'funced': func(function() { actual.push(this); }, 32) },
|
||||
expected = lodashStable.times(isDebounce ? 1 : 2, lodashStable.constant(object));
|
||||
|
||||
object.funced();
|
||||
if (!isDebounce) {
|
||||
object.funced();
|
||||
}
|
||||
setTimeout(function() {
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` supports recursive calls', function(done) {
|
||||
var actual = [],
|
||||
args = lodashStable.map(['a', 'b', 'c'], function(chr) { return [{}, chr]; }),
|
||||
expected = args.slice(),
|
||||
queue = args.slice();
|
||||
|
||||
var funced = func(function() {
|
||||
var current = [this];
|
||||
push.apply(current, arguments);
|
||||
actual.push(current);
|
||||
|
||||
var next = queue.shift();
|
||||
if (next) {
|
||||
funced.call(next[0], next[1]);
|
||||
}
|
||||
}, 32);
|
||||
|
||||
var next = queue.shift();
|
||||
funced.call(next[0], next[1]);
|
||||
assert.deepStrictEqual(actual, expected.slice(0, isDebounce ? 0 : 1));
|
||||
|
||||
setTimeout(function() {
|
||||
assert.deepStrictEqual(actual, expected.slice(0, actual.length));
|
||||
done();
|
||||
}, 256);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work if the system time is set backwards', function(done) {
|
||||
if (!isModularize) {
|
||||
var callCount = 0,
|
||||
dateCount = 0;
|
||||
|
||||
var lodash = runInContext({
|
||||
'Date': {
|
||||
'now': function() {
|
||||
return ++dateCount == 4
|
||||
? +new Date(2012, 3, 23, 23, 27, 18)
|
||||
: +new Date;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var funced = lodash[methodName](function() {
|
||||
callCount++;
|
||||
}, 32);
|
||||
|
||||
funced();
|
||||
|
||||
setTimeout(function() {
|
||||
funced();
|
||||
assert.strictEqual(callCount, isDebounce ? 1 : 2);
|
||||
done();
|
||||
}, 64);
|
||||
}
|
||||
else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should support cancelling delayed calls', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var funced = func(function() {
|
||||
callCount++;
|
||||
}, 32, { 'leading': false });
|
||||
|
||||
funced();
|
||||
funced.cancel();
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 0);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should reset `lastCalled` after cancelling', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var funced = func(function() {
|
||||
return ++callCount;
|
||||
}, 32, { 'leading': true });
|
||||
|
||||
assert.strictEqual(funced(), 1);
|
||||
funced.cancel();
|
||||
|
||||
assert.strictEqual(funced(), 2);
|
||||
funced();
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 3);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should support flushing delayed calls', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var funced = func(function() {
|
||||
return ++callCount;
|
||||
}, 32, { 'leading': false });
|
||||
|
||||
funced();
|
||||
assert.strictEqual(funced.flush(), 1);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 1);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should noop `cancel` and `flush` when nothing is queued', function(done) {
|
||||
var callCount = 0,
|
||||
funced = func(function() { callCount++; }, 32);
|
||||
|
||||
funced.cancel();
|
||||
assert.strictEqual(funced.flush(), undefined);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 0);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
});
|
||||
});
|
||||
250
test/debounce.test.js
Normal file
250
test/debounce.test.js
Normal file
@@ -0,0 +1,250 @@
|
||||
import assert from 'assert';
|
||||
import { identity, argv, isPhantom, push } from './utils.js';
|
||||
import debounce from '../debounce.js';
|
||||
|
||||
describe('debounce', function() {
|
||||
it('should debounce a function', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var debounced = debounce(function(value) {
|
||||
++callCount;
|
||||
return value;
|
||||
}, 32);
|
||||
|
||||
var results = [debounced('a'), debounced('b'), debounced('c')];
|
||||
assert.deepStrictEqual(results, [undefined, undefined, undefined]);
|
||||
assert.strictEqual(callCount, 0);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 1);
|
||||
|
||||
var results = [debounced('d'), debounced('e'), debounced('f')];
|
||||
assert.deepStrictEqual(results, ['c', 'c', 'c']);
|
||||
assert.strictEqual(callCount, 1);
|
||||
}, 128);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 2);
|
||||
done();
|
||||
}, 256);
|
||||
});
|
||||
|
||||
it('subsequent debounced calls return the last `func` result', function(done) {
|
||||
var debounced = debounce(identity, 32);
|
||||
debounced('a');
|
||||
|
||||
setTimeout(function() {
|
||||
assert.notStrictEqual(debounced('b'), 'b');
|
||||
}, 64);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.notStrictEqual(debounced('c'), 'c');
|
||||
done();
|
||||
}, 128);
|
||||
});
|
||||
|
||||
it('should not immediately call `func` when `wait` is `0`', function(done) {
|
||||
var callCount = 0,
|
||||
debounced = debounce(function() { ++callCount; }, 0);
|
||||
|
||||
debounced();
|
||||
debounced();
|
||||
assert.strictEqual(callCount, 0);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 1);
|
||||
done();
|
||||
}, 5);
|
||||
});
|
||||
|
||||
it('should apply default options', function(done) {
|
||||
var callCount = 0,
|
||||
debounced = debounce(function() { callCount++; }, 32, {});
|
||||
|
||||
debounced();
|
||||
assert.strictEqual(callCount, 0);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 1);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('should support a `leading` option', function(done) {
|
||||
var callCounts = [0, 0];
|
||||
|
||||
var withLeading = debounce(function() {
|
||||
callCounts[0]++;
|
||||
}, 32, { 'leading': true });
|
||||
|
||||
var withLeadingAndTrailing = debounce(function() {
|
||||
callCounts[1]++;
|
||||
}, 32, { 'leading': true });
|
||||
|
||||
withLeading();
|
||||
assert.strictEqual(callCounts[0], 1);
|
||||
|
||||
withLeadingAndTrailing();
|
||||
withLeadingAndTrailing();
|
||||
assert.strictEqual(callCounts[1], 1);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.deepStrictEqual(callCounts, [1, 2]);
|
||||
|
||||
withLeading();
|
||||
assert.strictEqual(callCounts[0], 2);
|
||||
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('subsequent leading debounced calls return the last `func` result', function(done) {
|
||||
var debounced = debounce(identity, 32, { 'leading': true, 'trailing': false }),
|
||||
results = [debounced('a'), debounced('b')];
|
||||
|
||||
assert.deepStrictEqual(results, ['a', 'a']);
|
||||
|
||||
setTimeout(function() {
|
||||
var results = [debounced('c'), debounced('d')];
|
||||
assert.deepStrictEqual(results, ['c', 'c']);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('should support a `trailing` option', function(done) {
|
||||
var withCount = 0,
|
||||
withoutCount = 0;
|
||||
|
||||
var withTrailing = debounce(function() {
|
||||
withCount++;
|
||||
}, 32, { 'trailing': true });
|
||||
|
||||
var withoutTrailing = debounce(function() {
|
||||
withoutCount++;
|
||||
}, 32, { 'trailing': false });
|
||||
|
||||
withTrailing();
|
||||
assert.strictEqual(withCount, 0);
|
||||
|
||||
withoutTrailing();
|
||||
assert.strictEqual(withoutCount, 0);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(withCount, 1);
|
||||
assert.strictEqual(withoutCount, 0);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('should support a `maxWait` option', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var debounced = debounce(function(value) {
|
||||
++callCount;
|
||||
return value;
|
||||
}, 32, { 'maxWait': 64 });
|
||||
|
||||
debounced();
|
||||
debounced();
|
||||
assert.strictEqual(callCount, 0);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 1);
|
||||
debounced();
|
||||
debounced();
|
||||
assert.strictEqual(callCount, 1);
|
||||
}, 128);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 2);
|
||||
done();
|
||||
}, 256);
|
||||
});
|
||||
|
||||
it('should support `maxWait` in a tight loop', function(done) {
|
||||
var limit = (argv || isPhantom) ? 1000 : 320,
|
||||
withCount = 0,
|
||||
withoutCount = 0;
|
||||
|
||||
var withMaxWait = debounce(function() {
|
||||
withCount++;
|
||||
}, 64, { 'maxWait': 128 });
|
||||
|
||||
var withoutMaxWait = debounce(function() {
|
||||
withoutCount++;
|
||||
}, 96);
|
||||
|
||||
var start = +new Date;
|
||||
while ((new Date - start) < limit) {
|
||||
withMaxWait();
|
||||
withoutMaxWait();
|
||||
}
|
||||
var actual = [Boolean(withoutCount), Boolean(withCount)];
|
||||
setTimeout(function() {
|
||||
assert.deepStrictEqual(actual, [false, true]);
|
||||
done();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
it('should queue a trailing call for subsequent debounced calls after `maxWait`', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var debounced = debounce(function() {
|
||||
++callCount;
|
||||
}, 200, { 'maxWait': 200 });
|
||||
|
||||
debounced();
|
||||
|
||||
setTimeout(debounced, 190);
|
||||
setTimeout(debounced, 200);
|
||||
setTimeout(debounced, 210);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 2);
|
||||
done();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
it('should cancel `maxDelayed` when `delayed` is invoked', function(done) {
|
||||
var callCount = 0;
|
||||
|
||||
var debounced = debounce(function() {
|
||||
callCount++;
|
||||
}, 32, { 'maxWait': 64 });
|
||||
|
||||
debounced();
|
||||
|
||||
setTimeout(function() {
|
||||
debounced();
|
||||
assert.strictEqual(callCount, 1);
|
||||
}, 128);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 2);
|
||||
done();
|
||||
}, 192);
|
||||
});
|
||||
|
||||
it('should invoke the trailing call with the correct arguments and `this` binding', function(done) {
|
||||
var actual,
|
||||
callCount = 0,
|
||||
object = {};
|
||||
|
||||
var debounced = debounce(function(value) {
|
||||
actual = [this];
|
||||
push.apply(actual, arguments);
|
||||
return ++callCount != 2;
|
||||
}, 32, { 'leading': true, 'maxWait': 64 });
|
||||
|
||||
while (true) {
|
||||
if (!debounced.call(object, 'a')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
setTimeout(function() {
|
||||
assert.strictEqual(callCount, 2);
|
||||
assert.deepStrictEqual(actual, [object, 'a']);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
});
|
||||
28
test/deburr.test.js
Normal file
28
test/deburr.test.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { burredLetters, deburredLetters, comboMarks } from './utils.js';
|
||||
import deburr from '../deburr.js';
|
||||
|
||||
describe('deburr', function() {
|
||||
it('should convert Latin Unicode letters to basic Latin', function() {
|
||||
var actual = lodashStable.map(burredLetters, deburr);
|
||||
assert.deepStrictEqual(actual, deburredLetters);
|
||||
});
|
||||
|
||||
it('should not deburr Latin mathematical operators', function() {
|
||||
var operators = ['\xd7', '\xf7'],
|
||||
actual = lodashStable.map(operators, deburr);
|
||||
|
||||
assert.deepStrictEqual(actual, operators);
|
||||
});
|
||||
|
||||
it('should deburr combining diacritical marks', function() {
|
||||
var expected = lodashStable.map(comboMarks, lodashStable.constant('ei'));
|
||||
|
||||
var actual = lodashStable.map(comboMarks, function(chr) {
|
||||
return deburr('e' + chr + 'i');
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
18
test/defaultTo.test.js
Normal file
18
test/defaultTo.test.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey } from './utils.js';
|
||||
import defaultTo from '../defaultTo.js';
|
||||
|
||||
describe('defaultTo', function() {
|
||||
it('should return a default value if `value` is `NaN` or nullish', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return (value == null || value !== value) ? 1 : value;
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(value) {
|
||||
return defaultTo(value, 1);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
66
test/defaults.test.js
Normal file
66
test/defaults.test.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { objectProto } from './utils.js';
|
||||
import defaults from '../defaults.js';
|
||||
|
||||
describe('defaults', function() {
|
||||
it('should assign source properties if missing on `object`', function() {
|
||||
var actual = defaults({ 'a': 1 }, { 'a': 2, 'b': 2 });
|
||||
assert.deepStrictEqual(actual, { 'a': 1, 'b': 2 });
|
||||
});
|
||||
|
||||
it('should accept multiple sources', function() {
|
||||
var expected = { 'a': 1, 'b': 2, 'c': 3 },
|
||||
actual = defaults({ 'a': 1, 'b': 2 }, { 'b': 3 }, { 'c': 3 });
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
actual = defaults({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 3 }, { 'c': 2 });
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should not overwrite `null` values', function() {
|
||||
var actual = defaults({ 'a': null }, { 'a': 1 });
|
||||
assert.strictEqual(actual.a, null);
|
||||
});
|
||||
|
||||
it('should overwrite `undefined` values', function() {
|
||||
var actual = defaults({ 'a': undefined }, { 'a': 1 });
|
||||
assert.strictEqual(actual.a, 1);
|
||||
});
|
||||
|
||||
it('should assign `undefined` values', function() {
|
||||
var source = { 'a': undefined, 'b': 1 },
|
||||
actual = defaults({}, source);
|
||||
|
||||
assert.deepStrictEqual(actual, { 'a': undefined, 'b': 1 });
|
||||
});
|
||||
|
||||
it('should assign properties that shadow those on `Object.prototype`', function() {
|
||||
var object = {
|
||||
'constructor': objectProto.constructor,
|
||||
'hasOwnProperty': objectProto.hasOwnProperty,
|
||||
'isPrototypeOf': objectProto.isPrototypeOf,
|
||||
'propertyIsEnumerable': objectProto.propertyIsEnumerable,
|
||||
'toLocaleString': objectProto.toLocaleString,
|
||||
'toString': objectProto.toString,
|
||||
'valueOf': objectProto.valueOf
|
||||
};
|
||||
|
||||
var source = {
|
||||
'constructor': 1,
|
||||
'hasOwnProperty': 2,
|
||||
'isPrototypeOf': 3,
|
||||
'propertyIsEnumerable': 4,
|
||||
'toLocaleString': 5,
|
||||
'toString': 6,
|
||||
'valueOf': 7
|
||||
};
|
||||
|
||||
var expected = lodashStable.clone(source);
|
||||
assert.deepStrictEqual(defaults({}, source), expected);
|
||||
|
||||
expected = lodashStable.clone(object);
|
||||
assert.deepStrictEqual(defaults({}, object, source), expected);
|
||||
});
|
||||
});
|
||||
101
test/defaultsDeep.js
Normal file
101
test/defaultsDeep.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { noop } from './utils.js';
|
||||
import defaultsDeep from '../defaultsDeep.js';
|
||||
|
||||
describe('defaultsDeep', function() {
|
||||
it('should deep assign source properties if missing on `object`', function() {
|
||||
var object = { 'a': { 'b': 2 }, 'd': 4 },
|
||||
source = { 'a': { 'b': 3, 'c': 3 }, 'e': 5 },
|
||||
expected = { 'a': { 'b': 2, 'c': 3 }, 'd': 4, 'e': 5 };
|
||||
|
||||
assert.deepStrictEqual(defaultsDeep(object, source), expected);
|
||||
});
|
||||
|
||||
it('should accept multiple sources', function() {
|
||||
var source1 = { 'a': { 'b': 3 } },
|
||||
source2 = { 'a': { 'c': 3 } },
|
||||
source3 = { 'a': { 'b': 3, 'c': 3 } },
|
||||
source4 = { 'a': { 'c': 4 } },
|
||||
expected = { 'a': { 'b': 2, 'c': 3 } };
|
||||
|
||||
assert.deepStrictEqual(defaultsDeep({ 'a': { 'b': 2 } }, source1, source2), expected);
|
||||
assert.deepStrictEqual(defaultsDeep({ 'a': { 'b': 2 } }, source3, source4), expected);
|
||||
});
|
||||
|
||||
it('should not overwrite `null` values', function() {
|
||||
var object = { 'a': { 'b': null } },
|
||||
source = { 'a': { 'b': 2 } },
|
||||
actual = defaultsDeep(object, source);
|
||||
|
||||
assert.strictEqual(actual.a.b, null);
|
||||
});
|
||||
|
||||
it('should not overwrite regexp values', function() {
|
||||
var object = { 'a': { 'b': /x/ } },
|
||||
source = { 'a': { 'b': /y/ } },
|
||||
actual = defaultsDeep(object, source);
|
||||
|
||||
assert.deepStrictEqual(actual.a.b, /x/);
|
||||
});
|
||||
|
||||
it('should not convert function properties to objects', function() {
|
||||
var actual = defaultsDeep({}, { 'a': noop });
|
||||
assert.strictEqual(actual.a, noop);
|
||||
|
||||
actual = defaultsDeep({}, { 'a': { 'b': noop } });
|
||||
assert.strictEqual(actual.a.b, noop);
|
||||
});
|
||||
|
||||
it('should overwrite `undefined` values', function() {
|
||||
var object = { 'a': { 'b': undefined } },
|
||||
source = { 'a': { 'b': 2 } },
|
||||
actual = defaultsDeep(object, source);
|
||||
|
||||
assert.strictEqual(actual.a.b, 2);
|
||||
});
|
||||
|
||||
it('should assign `undefined` values', function() {
|
||||
var source = { 'a': undefined, 'b': { 'c': undefined, 'd': 1 } },
|
||||
expected = lodashStable.cloneDeep(source),
|
||||
actual = defaultsDeep({}, source);
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should merge sources containing circular references', function() {
|
||||
var object = {
|
||||
'foo': { 'b': { 'c': { 'd': {} } } },
|
||||
'bar': { 'a': 2 }
|
||||
};
|
||||
|
||||
var source = {
|
||||
'foo': { 'b': { 'c': { 'd': {} } } },
|
||||
'bar': {}
|
||||
};
|
||||
|
||||
object.foo.b.c.d = object;
|
||||
source.foo.b.c.d = source;
|
||||
source.bar.b = source.foo.b;
|
||||
|
||||
var actual = defaultsDeep(object, source);
|
||||
|
||||
assert.strictEqual(actual.bar.b, actual.foo.b);
|
||||
assert.strictEqual(actual.foo.b.c.d, actual.foo.b.c.d.foo.b.c.d);
|
||||
});
|
||||
|
||||
it('should not modify sources', function() {
|
||||
var source1 = { 'a': 1, 'b': { 'c': 2 } },
|
||||
source2 = { 'b': { 'c': 3, 'd': 3 } },
|
||||
actual = defaultsDeep({}, source1, source2);
|
||||
|
||||
assert.deepStrictEqual(actual, { 'a': 1, 'b': { 'c': 2, 'd': 3 } });
|
||||
assert.deepStrictEqual(source1, { 'a': 1, 'b': { 'c': 2 } });
|
||||
assert.deepStrictEqual(source2, { 'b': { 'c': 3, 'd': 3 } });
|
||||
});
|
||||
|
||||
it('should not attempt a merge of a string into an array', function() {
|
||||
var actual = defaultsDeep({ 'a': ['abc'] }, { 'a': 'abc' });
|
||||
assert.deepStrictEqual(actual.a, ['abc']);
|
||||
});
|
||||
});
|
||||
40
test/defer.test.js
Normal file
40
test/defer.test.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import defer from '../defer.js';
|
||||
|
||||
describe('defer', function() {
|
||||
it('should defer `func` execution', function(done) {
|
||||
var pass = false;
|
||||
defer(function() { pass = true; });
|
||||
|
||||
setTimeout(function() {
|
||||
assert.ok(pass);
|
||||
done();
|
||||
}, 32);
|
||||
});
|
||||
|
||||
it('should provide additional arguments to `func`', function(done) {
|
||||
var args;
|
||||
|
||||
defer(function() {
|
||||
args = slice.call(arguments);
|
||||
}, 1, 2);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.deepStrictEqual(args, [1, 2]);
|
||||
done();
|
||||
}, 32);
|
||||
});
|
||||
|
||||
it('should be cancelable', function(done) {
|
||||
var pass = true,
|
||||
timerId = defer(function() { pass = false; });
|
||||
|
||||
clearTimeout(timerId);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.ok(pass);
|
||||
done();
|
||||
}, 32);
|
||||
});
|
||||
});
|
||||
67
test/delay.js
Normal file
67
test/delay.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import delay from '../delay.js';
|
||||
|
||||
describe('delay', function() {
|
||||
it('should delay `func` execution', function(done) {
|
||||
var pass = false;
|
||||
delay(function() { pass = true; }, 32);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.ok(!pass);
|
||||
}, 1);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.ok(pass);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('should provide additional arguments to `func`', function(done) {
|
||||
var args;
|
||||
|
||||
delay(function() {
|
||||
args = slice.call(arguments);
|
||||
}, 32, 1, 2);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.deepStrictEqual(args, [1, 2]);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('should use a default `wait` of `0`', function(done) {
|
||||
var pass = false;
|
||||
delay(function() { pass = true; });
|
||||
|
||||
assert.ok(!pass);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.ok(pass);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('should be cancelable', function(done) {
|
||||
var pass = true,
|
||||
timerId = delay(function() { pass = false; }, 32);
|
||||
|
||||
clearTimeout(timerId);
|
||||
|
||||
setTimeout(function() {
|
||||
assert.ok(pass);
|
||||
done();
|
||||
}, 64);
|
||||
});
|
||||
|
||||
it('should work with mocked `setTimeout`', function() {
|
||||
var pass = false,
|
||||
setTimeout = root.setTimeout;
|
||||
|
||||
setProperty(root, 'setTimeout', function(func) { func(); });
|
||||
delay(function() { pass = true; }, 32);
|
||||
setProperty(root, 'setTimeout', setTimeout);
|
||||
|
||||
assert.ok(pass);
|
||||
});
|
||||
});
|
||||
85
test/difference-methods.js
Normal file
85
test/difference-methods.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, LARGE_ARRAY_SIZE, stubOne, stubNaN, args } from './utils.js';
|
||||
|
||||
describe('difference methods', function() {
|
||||
lodashStable.each(['difference', 'differenceBy', 'differenceWith'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should return the difference of two arrays', function() {
|
||||
var actual = func([2, 1], [2, 3]);
|
||||
assert.deepStrictEqual(actual, [1]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return the difference of multiple arrays', function() {
|
||||
var actual = func([2, 1, 2, 3], [3, 4], [3, 2]);
|
||||
assert.deepStrictEqual(actual, [1]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat `-0` as `0`', function() {
|
||||
var array = [-0, 0];
|
||||
|
||||
var actual = lodashStable.map(array, function(value) {
|
||||
return func(array, [value]);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [[], []]);
|
||||
|
||||
actual = lodashStable.map(func([-0, 1], [1]), lodashStable.toString);
|
||||
assert.deepStrictEqual(actual, ['0']);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should match `NaN`', function() {
|
||||
assert.deepStrictEqual(func([1, NaN, 3], [NaN, 5, NaN]), [1, 3]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays', function() {
|
||||
var array1 = lodashStable.range(LARGE_ARRAY_SIZE + 1),
|
||||
array2 = lodashStable.range(LARGE_ARRAY_SIZE),
|
||||
a = {},
|
||||
b = {},
|
||||
c = {};
|
||||
|
||||
array1.push(a, b, c);
|
||||
array2.push(b, c, a);
|
||||
|
||||
assert.deepStrictEqual(func(array1, array2), [LARGE_ARRAY_SIZE]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function() {
|
||||
var array = [-0, 0];
|
||||
|
||||
var actual = lodashStable.map(array, function(value) {
|
||||
var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(value));
|
||||
return func(array, largeArray);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [[], []]);
|
||||
|
||||
var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne);
|
||||
actual = lodashStable.map(func([-0, 1], largeArray), lodashStable.toString);
|
||||
assert.deepStrictEqual(actual, ['0']);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays of `NaN`', function() {
|
||||
var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN);
|
||||
assert.deepStrictEqual(func([1, NaN, 3], largeArray), [1, 3]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays of objects', function() {
|
||||
var object1 = {},
|
||||
object2 = {},
|
||||
largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object1));
|
||||
|
||||
assert.deepStrictEqual(func([object1, object2], largeArray), [object2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should ignore values that are not array-like', function() {
|
||||
var array = [1, null, 3];
|
||||
|
||||
assert.deepStrictEqual(func(args, 3, { '0': 1 }), [1, 2, 3]);
|
||||
assert.deepStrictEqual(func(null, array, 1), []);
|
||||
assert.deepStrictEqual(func(array, args, null), [null]);
|
||||
});
|
||||
});
|
||||
});
|
||||
23
test/differenceBy.js
Normal file
23
test/differenceBy.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import differenceBy from '../differenceBy.js';
|
||||
|
||||
describe('differenceBy', function() {
|
||||
it('should accept an `iteratee`', function() {
|
||||
var actual = differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
|
||||
assert.deepStrictEqual(actual, [1.2]);
|
||||
|
||||
actual = differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
|
||||
assert.deepStrictEqual(actual, [{ 'x': 2 }]);
|
||||
});
|
||||
|
||||
it('should provide correct `iteratee` arguments', function() {
|
||||
var args;
|
||||
|
||||
differenceBy([2.1, 1.2], [2.3, 3.4], function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(args, [2.3]);
|
||||
});
|
||||
});
|
||||
26
test/differenceWith.test.js
Normal file
26
test/differenceWith.test.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE, stubOne } from './utils.js';
|
||||
import differenceWith from '../differenceWith.js';
|
||||
|
||||
describe('differenceWith', function() {
|
||||
it('should work with a `comparator`', function() {
|
||||
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }],
|
||||
actual = differenceWith(objects, [{ 'x': 1, 'y': 2 }], lodashStable.isEqual);
|
||||
|
||||
assert.deepStrictEqual(actual, [objects[1]]);
|
||||
});
|
||||
|
||||
it('should preserve the sign of `0`', function() {
|
||||
var array = [-0, 1],
|
||||
largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne),
|
||||
others = [[1], largeArray],
|
||||
expected = lodashStable.map(others, lodashStable.constant(['-0']));
|
||||
|
||||
var actual = lodashStable.map(others, function(other) {
|
||||
return lodashStable.map(differenceWith(array, other, lodashStable.eq), lodashStable.toString);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
15
test/divide.test.js
Normal file
15
test/divide.test.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import assert from 'assert';
|
||||
import divide from '../divide.js';
|
||||
|
||||
describe('divide', function() {
|
||||
it('should divide two numbers', function() {
|
||||
assert.strictEqual(divide(6, 4), 1.5);
|
||||
assert.strictEqual(divide(-6, 4), -1.5);
|
||||
assert.strictEqual(divide(-6, -4), 1.5);
|
||||
});
|
||||
|
||||
it('should coerce arguments to numbers', function() {
|
||||
assert.strictEqual(divide('6', '4'), 1.5);
|
||||
assert.deepStrictEqual(divide('x', 'y'), NaN);
|
||||
});
|
||||
});
|
||||
69
test/drop.js
Normal file
69
test/drop.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils.js';
|
||||
import drop from '../drop.js';
|
||||
|
||||
describe('drop', function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
it('should drop the first two elements', function() {
|
||||
assert.deepStrictEqual(drop(array, 2), [3]);
|
||||
});
|
||||
|
||||
it('should treat falsey `n` values, except `undefined`, as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return value === undefined ? [2, 3] : array;
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(n) {
|
||||
return drop(array, n);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return all elements when `n` < `1`', function() {
|
||||
lodashStable.each([0, -1, -Infinity], function(n) {
|
||||
assert.deepStrictEqual(drop(array, n), array);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an empty array when `n` >= `length`', function() {
|
||||
lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
|
||||
assert.deepStrictEqual(drop(array, n), []);
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce `n` to an integer', function() {
|
||||
assert.deepStrictEqual(drop(array, 1.6), [2, 3]);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
|
||||
actual = lodashStable.map(array, drop);
|
||||
|
||||
assert.deepStrictEqual(actual, [[2, 3], [5, 6], [8, 9]]);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1),
|
||||
predicate = function(value) { values.push(value); return isEven(value); },
|
||||
values = [],
|
||||
actual = _(array).drop(2).drop().value();
|
||||
|
||||
assert.deepEqual(actual, array.slice(3));
|
||||
|
||||
actual = _(array).filter(predicate).drop(2).drop().value();
|
||||
assert.deepEqual(values, array);
|
||||
assert.deepEqual(actual, drop(drop(_.filter(array, predicate), 2)));
|
||||
|
||||
actual = _(array).drop(2).dropRight().drop().dropRight(2).value();
|
||||
assert.deepEqual(actual, _.dropRight(drop(_.dropRight(drop(array, 2))), 2));
|
||||
|
||||
values = [];
|
||||
|
||||
actual = _(array).drop().filter(predicate).drop(2).dropRight().drop().dropRight(2).value();
|
||||
assert.deepEqual(values, array.slice(1));
|
||||
assert.deepEqual(actual, _.dropRight(drop(_.dropRight(drop(_.filter(drop(array), predicate), 2))), 2));
|
||||
});
|
||||
});
|
||||
69
test/dropRight.js
Normal file
69
test/dropRight.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils.js';
|
||||
import dropRight from '../dropRight.js';
|
||||
|
||||
describe('dropRight', function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
it('should drop the last two elements', function() {
|
||||
assert.deepStrictEqual(dropRight(array, 2), [1]);
|
||||
});
|
||||
|
||||
it('should treat falsey `n` values, except `undefined`, as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return value === undefined ? [1, 2] : array;
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(n) {
|
||||
return dropRight(array, n);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return all elements when `n` < `1`', function() {
|
||||
lodashStable.each([0, -1, -Infinity], function(n) {
|
||||
assert.deepStrictEqual(dropRight(array, n), array);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an empty array when `n` >= `length`', function() {
|
||||
lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(n) {
|
||||
assert.deepStrictEqual(dropRight(array, n), []);
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce `n` to an integer', function() {
|
||||
assert.deepStrictEqual(dropRight(array, 1.6), [1, 2]);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
|
||||
actual = lodashStable.map(array, dropRight);
|
||||
|
||||
assert.deepStrictEqual(actual, [[1, 2], [4, 5], [7, 8]]);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1),
|
||||
predicate = function(value) { values.push(value); return isEven(value); },
|
||||
values = [],
|
||||
actual = _(array).dropRight(2).dropRight().value();
|
||||
|
||||
assert.deepEqual(actual, array.slice(0, -3));
|
||||
|
||||
actual = _(array).filter(predicate).dropRight(2).dropRight().value();
|
||||
assert.deepEqual(values, array);
|
||||
assert.deepEqual(actual, dropRight(dropRight(_.filter(array, predicate), 2)));
|
||||
|
||||
actual = _(array).dropRight(2).drop().dropRight().drop(2).value();
|
||||
assert.deepEqual(actual, _.drop(dropRight(_.drop(dropRight(array, 2))), 2));
|
||||
|
||||
values = [];
|
||||
|
||||
actual = _(array).dropRight().filter(predicate).dropRight(2).drop().dropRight().drop(2).value();
|
||||
assert.deepEqual(values, array.slice(0, -1));
|
||||
assert.deepEqual(actual, _.drop(dropRight(_.drop(dropRight(_.filter(dropRight(array), predicate), 2))), 2));
|
||||
});
|
||||
});
|
||||
52
test/dropRightWhile.js
Normal file
52
test/dropRightWhile.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import dropRightWhile from '../dropRightWhile.js';
|
||||
|
||||
describe('dropRightWhile', function() {
|
||||
var array = [1, 2, 3, 4];
|
||||
|
||||
var objects = [
|
||||
{ 'a': 0, 'b': 0 },
|
||||
{ 'a': 1, 'b': 1 },
|
||||
{ 'a': 2, 'b': 2 }
|
||||
];
|
||||
|
||||
it('should drop elements while `predicate` returns truthy', function() {
|
||||
var actual = dropRightWhile(array, function(n) {
|
||||
return n > 2;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [1, 2]);
|
||||
});
|
||||
|
||||
it('should provide correct `predicate` arguments', function() {
|
||||
var args;
|
||||
|
||||
dropRightWhile(array, function() {
|
||||
args = slice.call(arguments);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(args, [4, 3, array]);
|
||||
});
|
||||
|
||||
it('should work with `_.matches` shorthands', function() {
|
||||
assert.deepStrictEqual(dropRightWhile(objects, { 'b': 2 }), objects.slice(0, 2));
|
||||
});
|
||||
|
||||
it('should work with `_.matchesProperty` shorthands', function() {
|
||||
assert.deepStrictEqual(dropRightWhile(objects, ['b', 2]), objects.slice(0, 2));
|
||||
});
|
||||
|
||||
it('should work with `_.property` shorthands', function() {
|
||||
assert.deepStrictEqual(dropRightWhile(objects, 'b'), objects.slice(0, 1));
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var wrapped = _(array).dropRightWhile(function(n) {
|
||||
return n > 2;
|
||||
});
|
||||
|
||||
assert.ok(wrapped instanceof _);
|
||||
assert.deepEqual(wrapped.value(), [1, 2]);
|
||||
});
|
||||
});
|
||||
67
test/dropWhile.js
Normal file
67
test/dropWhile.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { slice, LARGE_ARRAY_SIZE } from './utils.js';
|
||||
import dropWhile from '../dropWhile.js';
|
||||
|
||||
describe('dropWhile', function() {
|
||||
var array = [1, 2, 3, 4];
|
||||
|
||||
var objects = [
|
||||
{ 'a': 2, 'b': 2 },
|
||||
{ 'a': 1, 'b': 1 },
|
||||
{ 'a': 0, 'b': 0 }
|
||||
];
|
||||
|
||||
it('should drop elements while `predicate` returns truthy', function() {
|
||||
var actual = dropWhile(array, function(n) {
|
||||
return n < 3;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [3, 4]);
|
||||
});
|
||||
|
||||
it('should provide correct `predicate` arguments', function() {
|
||||
var args;
|
||||
|
||||
dropWhile(array, function() {
|
||||
args = slice.call(arguments);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(args, [1, 0, array]);
|
||||
});
|
||||
|
||||
it('should work with `_.matches` shorthands', function() {
|
||||
assert.deepStrictEqual(dropWhile(objects, { 'b': 2 }), objects.slice(1));
|
||||
});
|
||||
|
||||
it('should work with `_.matchesProperty` shorthands', function() {
|
||||
assert.deepStrictEqual(dropWhile(objects, ['b', 2]), objects.slice(1));
|
||||
});
|
||||
|
||||
it('should work with `_.property` shorthands', function() {
|
||||
assert.deepStrictEqual(dropWhile(objects, 'b'), objects.slice(2));
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3),
|
||||
predicate = function(n) { return n < 3; },
|
||||
expected = dropWhile(array, predicate),
|
||||
wrapped = _(array).dropWhile(predicate);
|
||||
|
||||
assert.deepEqual(wrapped.value(), expected);
|
||||
assert.deepEqual(wrapped.reverse().value(), expected.slice().reverse());
|
||||
assert.strictEqual(wrapped.last(), _.last(expected));
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence with `drop`', function() {
|
||||
var array = lodashStable.range(1, LARGE_ARRAY_SIZE + 3);
|
||||
|
||||
var actual = _(array)
|
||||
.dropWhile(function(n) { return n == 1; })
|
||||
.drop()
|
||||
.dropWhile(function(n) { return n == 3; })
|
||||
.value();
|
||||
|
||||
assert.deepEqual(actual, array.slice(3));
|
||||
});
|
||||
});
|
||||
49
test/endsWith.test.js
Normal file
49
test/endsWith.test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { MAX_SAFE_INTEGER, falsey, stubTrue } from './utils.js';
|
||||
import endsWith from '../endsWith.js';
|
||||
|
||||
describe('endsWith', function() {
|
||||
var string = 'abc';
|
||||
|
||||
it('should return `true` if a string ends with `target`', function() {
|
||||
assert.strictEqual(endsWith(string, 'c'), true);
|
||||
});
|
||||
|
||||
it('should return `false` if a string does not end with `target`', function() {
|
||||
assert.strictEqual(endsWith(string, 'b'), false);
|
||||
});
|
||||
|
||||
it('should work with a `position`', function() {
|
||||
assert.strictEqual(endsWith(string, 'b', 2), true);
|
||||
});
|
||||
|
||||
it('should work with `position` >= `length`', function() {
|
||||
lodashStable.each([3, 5, MAX_SAFE_INTEGER, Infinity], function(position) {
|
||||
assert.strictEqual(endsWith(string, 'c', position), true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should treat falsey `position` values, except `undefined`, as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(position) {
|
||||
return endsWith(string, position === undefined ? 'c' : '', position);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should treat a negative `position` as `0`', function() {
|
||||
lodashStable.each([-1, -3, -Infinity], function(position) {
|
||||
assert.ok(lodashStable.every(string, function(chr) {
|
||||
return !endsWith(string, chr, position);
|
||||
}));
|
||||
assert.strictEqual(endsWith(string, '', position), true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce `position` to an integer', function() {
|
||||
assert.strictEqual(endsWith(string, 'ab', 2.2), true);
|
||||
});
|
||||
});
|
||||
21
test/eq.test.js
Normal file
21
test/eq.test.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import assert from 'assert';
|
||||
import eq from '../eq.js';
|
||||
|
||||
describe('eq', function() {
|
||||
it('should perform a `SameValueZero` comparison of two values', function() {
|
||||
assert.strictEqual(eq(), true);
|
||||
assert.strictEqual(eq(undefined), true);
|
||||
assert.strictEqual(eq(0, -0), true);
|
||||
assert.strictEqual(eq(NaN, NaN), true);
|
||||
assert.strictEqual(eq(1, 1), true);
|
||||
|
||||
assert.strictEqual(eq(null, undefined), false);
|
||||
assert.strictEqual(eq(1, Object(1)), false);
|
||||
assert.strictEqual(eq(1, '1'), false);
|
||||
assert.strictEqual(eq(1, '1'), false);
|
||||
|
||||
var object = { 'a': 1 };
|
||||
assert.strictEqual(eq(object, object), true);
|
||||
assert.strictEqual(eq(object, { 'a': 1 }), false);
|
||||
});
|
||||
});
|
||||
30
test/escape.js
Normal file
30
test/escape.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import escape from '../escape.js';
|
||||
import unescape from '../unescape.js';
|
||||
|
||||
describe('escape', function() {
|
||||
var escaped = '&<>"'/',
|
||||
unescaped = '&<>"\'/';
|
||||
|
||||
escaped += escaped;
|
||||
unescaped += unescaped;
|
||||
|
||||
it('should escape values', function() {
|
||||
assert.strictEqual(escape(unescaped), escaped);
|
||||
});
|
||||
|
||||
it('should handle strings with nothing to escape', function() {
|
||||
assert.strictEqual(escape('abc'), 'abc');
|
||||
});
|
||||
|
||||
it('should escape the same characters unescaped by `_.unescape`', function() {
|
||||
assert.strictEqual(escape(unescape(escaped)), escaped);
|
||||
});
|
||||
|
||||
lodashStable.each(['`', '/'], function(chr) {
|
||||
it('should not escape the "' + chr + '" character', function() {
|
||||
assert.strictEqual(escape(chr), chr);
|
||||
});
|
||||
});
|
||||
});
|
||||
28
test/escapeRegExp.js
Normal file
28
test/escapeRegExp.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { stubString } from './utils.js';
|
||||
import escapeRegExp from '../escapeRegExp.js';
|
||||
|
||||
describe('escapeRegExp', function() {
|
||||
var escaped = '\\^\\$\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\',
|
||||
unescaped = '^$.*+?()[]{}|\\';
|
||||
|
||||
it('should escape values', function() {
|
||||
assert.strictEqual(escapeRegExp(unescaped + unescaped), escaped + escaped);
|
||||
});
|
||||
|
||||
it('should handle strings with nothing to escape', function() {
|
||||
assert.strictEqual(escapeRegExp('abc'), 'abc');
|
||||
});
|
||||
|
||||
it('should return an empty string for empty values', function() {
|
||||
var values = [, null, undefined, ''],
|
||||
expected = lodashStable.map(values, stubString);
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? escapeRegExp(value) : escapeRegExp();
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
74
test/every.js
Normal file
74
test/every.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { identity, empties, stubTrue, stubFalse } from './utils.js';
|
||||
import every from '../every.js';
|
||||
|
||||
describe('every', function() {
|
||||
it('should return `true` if `predicate` returns truthy for all elements', function() {
|
||||
assert.strictEqual(lodashStable.every([true, 1, 'a'], identity), true);
|
||||
});
|
||||
|
||||
it('should return `true` for empty collections', function() {
|
||||
var expected = lodashStable.map(empties, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(empties, function(value) {
|
||||
try {
|
||||
return every(value, identity);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should return `false` as soon as `predicate` returns falsey', function() {
|
||||
var count = 0;
|
||||
|
||||
assert.strictEqual(every([true, null, true], function(value) {
|
||||
count++;
|
||||
return value;
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(count, 2);
|
||||
});
|
||||
|
||||
it('should work with collections of `undefined` values (test in IE < 9)', function() {
|
||||
assert.strictEqual(every([undefined, undefined, undefined], identity), false);
|
||||
});
|
||||
|
||||
it('should use `_.identity` when `predicate` is nullish', function() {
|
||||
var values = [, null, undefined],
|
||||
expected = lodashStable.map(values, stubFalse);
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
var array = [0];
|
||||
return index ? every(array, value) : every(array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
|
||||
expected = lodashStable.map(values, stubTrue);
|
||||
actual = lodashStable.map(values, function(value, index) {
|
||||
var array = [1];
|
||||
return index ? every(array, value) : every(array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with `_.property` shorthands', function() {
|
||||
var objects = [{ 'a': 0, 'b': 1 }, { 'a': 1, 'b': 2 }];
|
||||
assert.strictEqual(every(objects, 'a'), false);
|
||||
assert.strictEqual(every(objects, 'b'), true);
|
||||
});
|
||||
|
||||
it('should work with `_.matches` shorthands', function() {
|
||||
var objects = [{ 'a': 0, 'b': 0 }, { 'a': 0, 'b': 1 }];
|
||||
assert.strictEqual(every(objects, { 'a': 0 }), true);
|
||||
assert.strictEqual(every(objects, { 'b': 1 }), false);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var actual = lodashStable.map([[1]], every);
|
||||
assert.deepStrictEqual(actual, [true]);
|
||||
});
|
||||
});
|
||||
37
test/exit-early.js
Normal file
37
test/exit-early.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _ } from './utils.js';
|
||||
|
||||
describe('exit early', function() {
|
||||
lodashStable.each(['_baseEach', 'forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'transform'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` can exit early when iterating arrays', function() {
|
||||
if (func) {
|
||||
var array = [1, 2, 3],
|
||||
values = [];
|
||||
|
||||
func(array, function(value, other) {
|
||||
values.push(lodashStable.isArray(value) ? other : value);
|
||||
return false;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(values, [lodashStable.endsWith(methodName, 'Right') ? 3 : 1]);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` can exit early when iterating objects', function() {
|
||||
if (func) {
|
||||
var object = { 'a': 1, 'b': 2, 'c': 3 },
|
||||
values = [];
|
||||
|
||||
func(object, function(value, other) {
|
||||
values.push(lodashStable.isArray(value) ? other : value);
|
||||
return false;
|
||||
});
|
||||
|
||||
assert.strictEqual(values.length, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
64
test/extremum-methods.js
Normal file
64
test/extremum-methods.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _ } from './utils.js';
|
||||
|
||||
describe('extremum methods', function() {
|
||||
lodashStable.each(['max', 'maxBy', 'min', 'minBy'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isMax = /^max/.test(methodName);
|
||||
|
||||
it('`_.' + methodName + '` should work with Date objects', function() {
|
||||
var curr = new Date,
|
||||
past = new Date(0);
|
||||
|
||||
assert.strictEqual(func([curr, past]), isMax ? curr : past);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with extremely large arrays', function() {
|
||||
var array = lodashStable.range(0, 5e5);
|
||||
assert.strictEqual(func(array), isMax ? 499999 : 0);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work when chaining on an array with only one value', function() {
|
||||
var actual = _([40])[methodName]();
|
||||
assert.strictEqual(actual, 40);
|
||||
});
|
||||
});
|
||||
|
||||
lodashStable.each(['maxBy', 'minBy'], function(methodName) {
|
||||
var array = [1, 2, 3],
|
||||
func = _[methodName],
|
||||
isMax = methodName == 'maxBy';
|
||||
|
||||
it('`_.' + methodName + '` should work with an `iteratee`', function() {
|
||||
var actual = func(array, function(n) {
|
||||
return -n;
|
||||
});
|
||||
|
||||
assert.strictEqual(actual, isMax ? 1 : 3);
|
||||
});
|
||||
|
||||
it('should work with `_.property` shorthands', function() {
|
||||
var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }],
|
||||
actual = func(objects, 'a');
|
||||
|
||||
assert.deepStrictEqual(actual, objects[isMax ? 1 : 2]);
|
||||
|
||||
var arrays = [[2], [3], [1]];
|
||||
actual = func(arrays, 0);
|
||||
|
||||
assert.deepStrictEqual(actual, arrays[isMax ? 1 : 2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work when `iteratee` returns +/-Infinity', function() {
|
||||
var value = isMax ? -Infinity : Infinity,
|
||||
object = { 'a': value };
|
||||
|
||||
var actual = func([object, { 'a': value }], function(object) {
|
||||
return object.a;
|
||||
});
|
||||
|
||||
assert.strictEqual(actual, object);
|
||||
});
|
||||
});
|
||||
});
|
||||
128
test/fill.js
Normal file
128
test/fill.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey } from './utils.js';
|
||||
import fill from '../fill.js';
|
||||
|
||||
describe('fill', function() {
|
||||
it('should use a default `start` of `0` and a default `end` of `length`', function() {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a'), ['a', 'a', 'a']);
|
||||
});
|
||||
|
||||
it('should use `undefined` for `value` if not given', function() {
|
||||
var array = [1, 2, 3],
|
||||
actual = fill(array);
|
||||
|
||||
assert.deepStrictEqual(actual, Array(3));
|
||||
assert.ok(lodashStable.every(actual, function(value, index) {
|
||||
return index in actual;
|
||||
}));
|
||||
});
|
||||
|
||||
it('should work with a positive `start`', function() {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', 1), [1, 'a', 'a']);
|
||||
});
|
||||
|
||||
it('should work with a `start` >= `length`', function() {
|
||||
lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(start) {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', start), [1, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should treat falsey `start` values as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, lodashStable.constant(['a', 'a', 'a']));
|
||||
|
||||
var actual = lodashStable.map(falsey, function(start) {
|
||||
var array = [1, 2, 3];
|
||||
return fill(array, 'a', start);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with a negative `start`', function() {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', -1), [1, 2, 'a']);
|
||||
});
|
||||
|
||||
it('should work with a negative `start` <= negative `length`', function() {
|
||||
lodashStable.each([-3, -4, -Infinity], function(start) {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', start), ['a', 'a', 'a']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with `start` >= `end`', function() {
|
||||
lodashStable.each([2, 3], function(start) {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', start, 2), [1, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with a positive `end`', function() {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', 0, 1), ['a', 2, 3]);
|
||||
});
|
||||
|
||||
it('should work with a `end` >= `length`', function() {
|
||||
lodashStable.each([3, 4, Math.pow(2, 32), Infinity], function(end) {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', 0, end), ['a', 'a', 'a']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should treat falsey `end` values, except `undefined`, as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return value === undefined ? ['a', 'a', 'a'] : [1, 2, 3];
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(end) {
|
||||
var array = [1, 2, 3];
|
||||
return fill(array, 'a', 0, end);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with a negative `end`', function() {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', 0, -1), ['a', 'a', 3]);
|
||||
});
|
||||
|
||||
it('should work with a negative `end` <= negative `length`', function() {
|
||||
lodashStable.each([-3, -4, -Infinity], function(end) {
|
||||
var array = [1, 2, 3];
|
||||
assert.deepStrictEqual(fill(array, 'a', 0, end), [1, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce `start` and `end` to integers', function() {
|
||||
var positions = [[0.1, 1.6], ['0', 1], [0, '1'], ['1'], [NaN, 1], [1, NaN]];
|
||||
|
||||
var actual = lodashStable.map(positions, function(pos) {
|
||||
var array = [1, 2, 3];
|
||||
return fill.apply(_, [array, 'a'].concat(pos));
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [['a', 2, 3], ['a', 2, 3], ['a', 2, 3], [1, 'a', 'a'], ['a', 2, 3], [1, 2, 3]]);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [[1, 2], [3, 4]],
|
||||
actual = lodashStable.map(array, fill);
|
||||
|
||||
assert.deepStrictEqual(actual, [[0, 0], [1, 1]]);
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var array = [1, 2, 3],
|
||||
wrapped = _(array).fill('a'),
|
||||
actual = wrapped.value();
|
||||
|
||||
assert.ok(wrapped instanceof _);
|
||||
assert.strictEqual(actual, array);
|
||||
assert.deepEqual(actual, ['a', 'a', 'a']);
|
||||
});
|
||||
});
|
||||
100
test/filter-methods.js
Normal file
100
test/filter-methods.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, LARGE_ARRAY_SIZE, isEven, square } from './utils.js';
|
||||
|
||||
describe('filter methods', function() {
|
||||
lodashStable.each(['filter', 'reject'], function(methodName) {
|
||||
var array = [1, 2, 3, 4],
|
||||
func = _[methodName],
|
||||
isFilter = methodName == 'filter',
|
||||
objects = [{ 'a': 0 }, { 'a': 1 }];
|
||||
|
||||
it('`_.' + methodName + '` should not modify the resulting value from within `predicate`', function() {
|
||||
var actual = func([0], function(value, index, array) {
|
||||
array[index] = 1;
|
||||
return isFilter;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, [0]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `_.property` shorthands', function() {
|
||||
assert.deepStrictEqual(func(objects, 'a'), [objects[isFilter ? 1 : 0]]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `_.matches` shorthands', function() {
|
||||
assert.deepStrictEqual(func(objects, objects[1]), [objects[isFilter ? 1 : 0]]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not modify wrapped values', function() {
|
||||
var wrapped = _(array);
|
||||
|
||||
var actual = wrapped[methodName](function(n) {
|
||||
return n < 3;
|
||||
});
|
||||
|
||||
assert.deepEqual(actual.value(), isFilter ? [1, 2] : [3, 4]);
|
||||
|
||||
actual = wrapped[methodName](function(n) {
|
||||
return n > 2;
|
||||
});
|
||||
|
||||
assert.deepEqual(actual.value(), isFilter ? [3, 4] : [1, 2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(LARGE_ARRAY_SIZE + 1),
|
||||
predicate = function(value) { return isFilter ? isEven(value) : !isEven(value); };
|
||||
|
||||
var object = lodashStable.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) {
|
||||
return ['key' + index, index];
|
||||
}));
|
||||
|
||||
var actual = _(array).slice(1).map(square)[methodName](predicate).value();
|
||||
assert.deepEqual(actual, _[methodName](lodashStable.map(array.slice(1), square), predicate));
|
||||
|
||||
actual = _(object).mapValues(square)[methodName](predicate).value();
|
||||
assert.deepEqual(actual, _[methodName](lodashStable.mapValues(object, square), predicate));
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should provide correct `predicate` arguments in a lazy sequence', function() {
|
||||
var args,
|
||||
array = lodashStable.range(LARGE_ARRAY_SIZE + 1),
|
||||
expected = [1, 0, lodashStable.map(array.slice(1), square)];
|
||||
|
||||
_(array).slice(1)[methodName](function(value, index, array) {
|
||||
args || (args = slice.call(arguments));
|
||||
}).value();
|
||||
|
||||
assert.deepEqual(args, [1, 0, array.slice(1)]);
|
||||
|
||||
args = undefined;
|
||||
_(array).slice(1).map(square)[methodName](function(value, index, array) {
|
||||
args || (args = slice.call(arguments));
|
||||
}).value();
|
||||
|
||||
assert.deepEqual(args, expected);
|
||||
|
||||
args = undefined;
|
||||
_(array).slice(1).map(square)[methodName](function(value, index) {
|
||||
args || (args = slice.call(arguments));
|
||||
}).value();
|
||||
|
||||
assert.deepEqual(args, expected);
|
||||
|
||||
args = undefined;
|
||||
_(array).slice(1).map(square)[methodName](function(value) {
|
||||
args || (args = slice.call(arguments));
|
||||
}).value();
|
||||
|
||||
assert.deepEqual(args, [1]);
|
||||
|
||||
args = undefined;
|
||||
_(array).slice(1).map(square)[methodName](function() {
|
||||
args || (args = slice.call(arguments));
|
||||
}).value();
|
||||
|
||||
assert.deepEqual(args, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
11
test/filter.test.js
Normal file
11
test/filter.test.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import assert from 'assert';
|
||||
import { isEven } from './utils.js';
|
||||
import filter from '../filter.js';
|
||||
|
||||
describe('filter', function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
it('should return elements `predicate` returns truthy for', function() {
|
||||
assert.deepStrictEqual(filter(array, isEven), [2]);
|
||||
});
|
||||
});
|
||||
22
test/find-and-findLast.js
Normal file
22
test/find-and-findLast.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE, square, isEven } from './utils.js';
|
||||
|
||||
describe('find and findLast', function() {
|
||||
lodashStable.each(['find', 'findLast'], function(methodName) {
|
||||
var isFind = methodName == 'find';
|
||||
|
||||
it('`_.' + methodName + '` should support shortcut fusion', function() {
|
||||
var findCount = 0,
|
||||
mapCount = 0,
|
||||
array = lodashStable.range(1, LARGE_ARRAY_SIZE + 1),
|
||||
iteratee = function(value) { mapCount++; return square(value); },
|
||||
predicate = function(value) { findCount++; return isEven(value); },
|
||||
actual = _(array).map(iteratee)[methodName](predicate);
|
||||
|
||||
assert.strictEqual(findCount, isFind ? 2 : 1);
|
||||
assert.strictEqual(mapCount, isFind ? 2 : 1);
|
||||
assert.strictEqual(actual, isFind ? 4 : square(LARGE_ARRAY_SIZE));
|
||||
});
|
||||
});
|
||||
});
|
||||
103
test/find-and-includes.js
Normal file
103
test/find-and-includes.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, identity, args, falsey } from './utils.js';
|
||||
|
||||
describe('find and includes', function() {
|
||||
lodashStable.each(['includes', 'find'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isIncludes = methodName == 'includes',
|
||||
resolve = methodName == 'find' ? lodashStable.curry(lodashStable.eq) : identity;
|
||||
|
||||
lodashStable.each({
|
||||
'an `arguments` object': args,
|
||||
'an array': [1, 2, 3]
|
||||
},
|
||||
function(collection, key) {
|
||||
var values = lodashStable.toArray(collection);
|
||||
|
||||
it('`_.' + methodName + '` should work with ' + key + ' and a positive `fromIndex`', function() {
|
||||
var expected = [
|
||||
isIncludes || values[2],
|
||||
isIncludes ? false : undefined
|
||||
];
|
||||
|
||||
var actual = [
|
||||
func(collection, resolve(values[2]), 2),
|
||||
func(collection, resolve(values[1]), 2)
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with ' + key + ' and a `fromIndex` >= `length`', function() {
|
||||
var indexes = [4, 6, Math.pow(2, 32), Infinity];
|
||||
|
||||
var expected = lodashStable.map(indexes, function() {
|
||||
var result = isIncludes ? false : undefined;
|
||||
return [result, result, result];
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(indexes, function(fromIndex) {
|
||||
return [
|
||||
func(collection, resolve(1), fromIndex),
|
||||
func(collection, resolve(undefined), fromIndex),
|
||||
func(collection, resolve(''), fromIndex)
|
||||
];
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with ' + key + ' and treat falsey `fromIndex` values as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, lodashStable.constant(isIncludes || values[0]));
|
||||
|
||||
var actual = lodashStable.map(falsey, function(fromIndex) {
|
||||
return func(collection, resolve(values[0]), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with ' + key + ' and coerce `fromIndex` to an integer', function() {
|
||||
var expected = [
|
||||
isIncludes || values[0],
|
||||
isIncludes || values[0],
|
||||
isIncludes ? false : undefined
|
||||
];
|
||||
|
||||
var actual = [
|
||||
func(collection, resolve(values[0]), 0.1),
|
||||
func(collection, resolve(values[0]), NaN),
|
||||
func(collection, resolve(values[0]), '1')
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with ' + key + ' and a negative `fromIndex`', function() {
|
||||
var expected = [
|
||||
isIncludes || values[2],
|
||||
isIncludes ? false : undefined
|
||||
];
|
||||
|
||||
var actual = [
|
||||
func(collection, resolve(values[2]), -1),
|
||||
func(collection, resolve(values[1]), -1)
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with ' + key + ' and a negative `fromIndex` <= `-length`', function() {
|
||||
var indexes = [-4, -6, -Infinity],
|
||||
expected = lodashStable.map(indexes, lodashStable.constant(isIncludes || values[0]));
|
||||
|
||||
var actual = lodashStable.map(indexes, function(fromIndex) {
|
||||
return func(collection, resolve(values[0]), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
139
test/find-methods.js
Normal file
139
test/find-methods.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, empties, LARGE_ARRAY_SIZE, slice } from './utils.js';
|
||||
import each from '../each.js';
|
||||
|
||||
describe('find methods', function() {
|
||||
lodashStable.each(['find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', 'findLastKey'], function(methodName) {
|
||||
var array = [1, 2, 3, 4],
|
||||
func = _[methodName];
|
||||
|
||||
var objects = [
|
||||
{ 'a': 0, 'b': 0 },
|
||||
{ 'a': 1, 'b': 1 },
|
||||
{ 'a': 2, 'b': 2 }
|
||||
];
|
||||
|
||||
var expected = ({
|
||||
'find': [objects[1], undefined, objects[2]],
|
||||
'findIndex': [1, -1, 2],
|
||||
'findKey': ['1', undefined, '2'],
|
||||
'findLast': [objects[2], undefined, objects[2]],
|
||||
'findLastIndex': [2, -1, 2],
|
||||
'findLastKey': ['2', undefined, '2']
|
||||
})[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should return the found value', function() {
|
||||
assert.strictEqual(func(objects, function(object) { return object.a; }), expected[0]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `' + expected[1] + '` if value is not found', function() {
|
||||
assert.strictEqual(func(objects, function(object) { return object.a === 3; }), expected[1]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `_.matches` shorthands', function() {
|
||||
assert.strictEqual(func(objects, { 'b': 2 }), expected[2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `_.matchesProperty` shorthands', function() {
|
||||
assert.strictEqual(func(objects, ['b', 2]), expected[2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `_.property` shorthands', function() {
|
||||
assert.strictEqual(func(objects, 'b'), expected[0]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `' + expected[1] + '` for empty collections', function() {
|
||||
var emptyValues = lodashStable.endsWith(methodName, 'Index') ? lodashStable.reject(empties, lodashStable.isPlainObject) : empties,
|
||||
expecting = lodashStable.map(emptyValues, lodashStable.constant(expected[1]));
|
||||
|
||||
var actual = lodashStable.map(emptyValues, function(value) {
|
||||
try {
|
||||
return func(value, { 'a': 3 });
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expecting);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return an unwrapped value when implicitly chaining', function() {
|
||||
var expected = ({
|
||||
'find': 1,
|
||||
'findIndex': 0,
|
||||
'findKey': '0',
|
||||
'findLast': 4,
|
||||
'findLastIndex': 3,
|
||||
'findLastKey': '3'
|
||||
})[methodName];
|
||||
|
||||
assert.strictEqual(_(array)[methodName](), expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return a wrapped value when explicitly chaining', function() {
|
||||
assert.ok(_(array).chain()[methodName]() instanceof _);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not execute immediately when explicitly chaining', function() {
|
||||
var wrapped = _(array).chain()[methodName]();
|
||||
assert.strictEqual(wrapped.__wrapped__, array);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work in a lazy sequence', function() {
|
||||
var largeArray = lodashStable.range(1, LARGE_ARRAY_SIZE + 1),
|
||||
smallArray = array;
|
||||
|
||||
lodashStable.times(2, function(index) {
|
||||
var array = index ? largeArray : smallArray,
|
||||
wrapped = _(array).filter(isEven);
|
||||
|
||||
assert.strictEqual(wrapped[methodName](), func(lodashStable.filter(array, isEven)));
|
||||
});
|
||||
});
|
||||
}),
|
||||
function() {
|
||||
each(['find', 'findIndex', 'findLast', 'findLastIndex'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should provide correct `predicate` arguments for arrays', function() {
|
||||
var args,
|
||||
array = ['a'];
|
||||
|
||||
func(array, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(args, ['a', 0, array]);
|
||||
});
|
||||
});
|
||||
|
||||
each(['find', 'findKey', 'findLast', 'findLastKey'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should work with an object for `collection`', function() {
|
||||
var actual = func({ 'a': 1, 'b': 2, 'c': 3 }, function(n) {
|
||||
return n < 3;
|
||||
});
|
||||
|
||||
var expected = ({
|
||||
'find': 1,
|
||||
'findKey': 'a',
|
||||
'findLast': 2,
|
||||
'findLastKey': 'b'
|
||||
})[methodName];
|
||||
|
||||
assert.strictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should provide correct `predicate` arguments for objects', function() {
|
||||
var args,
|
||||
object = { 'a': 1 };
|
||||
|
||||
func(object, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(args, [1, 'a', object]);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
63
test/findIndex-and-indexOf.js
Normal file
63
test/findIndex-and-indexOf.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, identity, stubZero, falsey } from './utils.js';
|
||||
|
||||
describe('findIndex and indexOf', function() {
|
||||
lodashStable.each(['findIndex', 'indexOf'], function(methodName) {
|
||||
var array = [1, 2, 3, 1, 2, 3],
|
||||
func = _[methodName],
|
||||
resolve = methodName == 'findIndex' ? lodashStable.curry(lodashStable.eq) : identity;
|
||||
|
||||
it('`_.' + methodName + '` should return the index of the first matched value', function() {
|
||||
assert.strictEqual(func(array, resolve(3)), 2);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a positive `fromIndex`', function() {
|
||||
assert.strictEqual(func(array, resolve(1), 2), 3);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a `fromIndex` >= `length`', function() {
|
||||
var values = [6, 8, Math.pow(2, 32), Infinity],
|
||||
expected = lodashStable.map(values, lodashStable.constant([-1, -1, -1]));
|
||||
|
||||
var actual = lodashStable.map(values, function(fromIndex) {
|
||||
return [
|
||||
func(array, resolve(undefined), fromIndex),
|
||||
func(array, resolve(1), fromIndex),
|
||||
func(array, resolve(''), fromIndex)
|
||||
];
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a negative `fromIndex`', function() {
|
||||
assert.strictEqual(func(array, resolve(2), -3), 4);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a negative `fromIndex` <= `-length`', function() {
|
||||
var values = [-6, -8, -Infinity],
|
||||
expected = lodashStable.map(values, stubZero);
|
||||
|
||||
var actual = lodashStable.map(values, function(fromIndex) {
|
||||
return func(array, resolve(1), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat falsey `fromIndex` values as `0`', function() {
|
||||
var expected = lodashStable.map(falsey, stubZero);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(fromIndex) {
|
||||
return func(array, resolve(1), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should coerce `fromIndex` to an integer', function() {
|
||||
assert.strictEqual(func(array, resolve(2), 1.2), 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
99
test/findLast.js
Normal file
99
test/findLast.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { args, falsey } from './utils.js';
|
||||
import findLast from '../findLast.js';
|
||||
|
||||
describe('findLast', function() {
|
||||
var resolve = lodashStable.curry(lodashStable.eq);
|
||||
|
||||
lodashStable.each({
|
||||
'an `arguments` object': args,
|
||||
'an array': [1, 2, 3]
|
||||
},
|
||||
function(collection, key) {
|
||||
var values = lodashStable.toArray(collection);
|
||||
|
||||
it('should work with ' + key + ' and a positive `fromIndex`', function() {
|
||||
var expected = [
|
||||
values[1],
|
||||
undefined
|
||||
];
|
||||
|
||||
var actual = [
|
||||
findLast(collection, resolve(values[1]), 1),
|
||||
findLast(collection, resolve(values[2]), 1)
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and a `fromIndex` >= `length`', function() {
|
||||
var indexes = [4, 6, Math.pow(2, 32), Infinity];
|
||||
|
||||
var expected = lodashStable.map(indexes, lodashStable.constant([values[0], undefined, undefined]));
|
||||
|
||||
var actual = lodashStable.map(indexes, function(fromIndex) {
|
||||
return [
|
||||
findLast(collection, resolve(1), fromIndex),
|
||||
findLast(collection, resolve(undefined), fromIndex),
|
||||
findLast(collection, resolve(''), fromIndex)
|
||||
];
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and treat falsey `fromIndex` values correctly', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return value === undefined ? values[3] : undefined;
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(fromIndex) {
|
||||
return findLast(collection, resolve(values[3]), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and coerce `fromIndex` to an integer', function() {
|
||||
var expected = [
|
||||
values[0],
|
||||
values[0],
|
||||
undefined
|
||||
];
|
||||
|
||||
var actual = [
|
||||
findLast(collection, resolve(values[0]), 0.1),
|
||||
findLast(collection, resolve(values[0]), NaN),
|
||||
findLast(collection, resolve(values[2]), '1')
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and a negative `fromIndex`', function() {
|
||||
var expected = [
|
||||
values[1],
|
||||
undefined
|
||||
];
|
||||
|
||||
var actual = [
|
||||
findLast(collection, resolve(values[1]), -2),
|
||||
findLast(collection, resolve(values[2]), -2)
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and a negative `fromIndex` <= `-length`', function() {
|
||||
var indexes = [-4, -6, -Infinity],
|
||||
expected = lodashStable.map(indexes, lodashStable.constant(values[0]));
|
||||
|
||||
var actual = lodashStable.map(indexes, function(fromIndex) {
|
||||
return findLast(collection, resolve(values[0]), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
65
test/findLastIndex-and-lastIndexOf.js
Normal file
65
test/findLastIndex-and-lastIndexOf.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, identity, stubZero, falsey } from './utils.js';
|
||||
|
||||
describe('findLastIndex and lastIndexOf', function() {
|
||||
lodashStable.each(['findLastIndex', 'lastIndexOf'], function(methodName) {
|
||||
var array = [1, 2, 3, 1, 2, 3],
|
||||
func = _[methodName],
|
||||
resolve = methodName == 'findLastIndex' ? lodashStable.curry(lodashStable.eq) : identity;
|
||||
|
||||
it('`_.' + methodName + '` should return the index of the last matched value', function() {
|
||||
assert.strictEqual(func(array, resolve(3)), 5);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a positive `fromIndex`', function() {
|
||||
assert.strictEqual(func(array, resolve(1), 2), 0);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a `fromIndex` >= `length`', function() {
|
||||
var values = [6, 8, Math.pow(2, 32), Infinity],
|
||||
expected = lodashStable.map(values, lodashStable.constant([-1, 3, -1]));
|
||||
|
||||
var actual = lodashStable.map(values, function(fromIndex) {
|
||||
return [
|
||||
func(array, resolve(undefined), fromIndex),
|
||||
func(array, resolve(1), fromIndex),
|
||||
func(array, resolve(''), fromIndex)
|
||||
];
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a negative `fromIndex`', function() {
|
||||
assert.strictEqual(func(array, resolve(2), -3), 1);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a negative `fromIndex` <= `-length`', function() {
|
||||
var values = [-6, -8, -Infinity],
|
||||
expected = lodashStable.map(values, stubZero);
|
||||
|
||||
var actual = lodashStable.map(values, function(fromIndex) {
|
||||
return func(array, resolve(1), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat falsey `fromIndex` values correctly', function() {
|
||||
var expected = lodashStable.map(falsey, function(value) {
|
||||
return value === undefined ? 5 : -1;
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(falsey, function(fromIndex) {
|
||||
return func(array, resolve(3), fromIndex);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should coerce `fromIndex` to an integer', function() {
|
||||
assert.strictEqual(func(array, resolve(2), 4.2), 4);
|
||||
});
|
||||
});
|
||||
});
|
||||
72
test/flatMap-methods.js
Normal file
72
test/flatMap-methods.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, identity, falsey, stubArray } from './utils.js';
|
||||
|
||||
describe('flatMap methods', function() {
|
||||
lodashStable.each(['flatMap', 'flatMapDeep', 'flatMapDepth'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
array = [1, 2, 3, 4];
|
||||
|
||||
function duplicate(n) {
|
||||
return [n, n];
|
||||
}
|
||||
|
||||
it('`_.' + methodName + '` should map values in `array` to a new flattened array', function() {
|
||||
var actual = func(array, duplicate),
|
||||
expected = lodashStable.flatten(lodashStable.map(array, duplicate));
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `_.property` shorthands', function() {
|
||||
var objects = [{ 'a': [1, 2] }, { 'a': [3, 4] }];
|
||||
assert.deepStrictEqual(func(objects, 'a'), array);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should iterate over own string keyed properties of objects', function() {
|
||||
function Foo() {
|
||||
this.a = [1, 2];
|
||||
}
|
||||
Foo.prototype.b = [3, 4];
|
||||
|
||||
var actual = func(new Foo, identity);
|
||||
assert.deepStrictEqual(actual, [1, 2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should use `_.identity` when `iteratee` is nullish', function() {
|
||||
var array = [[1, 2], [3, 4]],
|
||||
object = { 'a': [1, 2], 'b': [3, 4] },
|
||||
values = [, null, undefined],
|
||||
expected = lodashStable.map(values, lodashStable.constant([1, 2, 3, 4]));
|
||||
|
||||
lodashStable.each([array, object], function(collection) {
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? func(collection, value) : func(collection);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should accept a falsey `collection`', function() {
|
||||
var expected = lodashStable.map(falsey, stubArray);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(collection, index) {
|
||||
try {
|
||||
return index ? func(collection) : func();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat number values for `collection` as empty', function() {
|
||||
assert.deepStrictEqual(func(1), []);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with objects with non-number length properties', function() {
|
||||
var object = { 'length': [1, 2] };
|
||||
assert.deepStrictEqual(func(object, identity), [1, 2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
33
test/flatMapDepth.js
Normal file
33
test/flatMapDepth.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { identity } from './utils.js';
|
||||
import flatMapDepth from '../flatMapDepth.js';
|
||||
|
||||
describe('flatMapDepth', function() {
|
||||
var array = [1, [2, [3, [4]], 5]];
|
||||
|
||||
it('should use a default `depth` of `1`', function() {
|
||||
assert.deepStrictEqual(flatMapDepth(array, identity), [1, 2, [3, [4]], 5]);
|
||||
});
|
||||
|
||||
it('should use `_.identity` when `iteratee` is nullish', function() {
|
||||
var values = [, null, undefined],
|
||||
expected = lodashStable.map(values, lodashStable.constant([1, 2, [3, [4]], 5]));
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? flatMapDepth(array, value) : flatMapDepth(array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should treat a `depth` of < `1` as a shallow clone', function() {
|
||||
lodashStable.each([-1, 0], function(depth) {
|
||||
assert.deepStrictEqual(flatMapDepth(array, identity, depth), [1, [2, [3, [4]], 5]]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce `depth` to an integer', function() {
|
||||
assert.deepStrictEqual(flatMapDepth(array, identity, 2.2), [1, 2, 3, [4], 5]);
|
||||
});
|
||||
});
|
||||
106
test/flatten-methods.js
Normal file
106
test/flatten-methods.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { args, _ } from './utils.js';
|
||||
import flatten from '../flatten.js';
|
||||
import flattenDeep from '../flattenDeep.js';
|
||||
import flattenDepth from '../flattenDepth.js';
|
||||
|
||||
describe('flatten methods', function() {
|
||||
var array = [1, [2, [3, [4]], 5]],
|
||||
methodNames = ['flatten', 'flattenDeep', 'flattenDepth'];
|
||||
|
||||
it('should flatten `arguments` objects', function() {
|
||||
var array = [args, [args]];
|
||||
|
||||
assert.deepStrictEqual(flatten(array), [1, 2, 3, args]);
|
||||
assert.deepStrictEqual(flattenDeep(array), [1, 2, 3, 1, 2, 3]);
|
||||
assert.deepStrictEqual(flattenDepth(array, 2), [1, 2, 3, 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should treat sparse arrays as dense', function() {
|
||||
var array = [[1, 2, 3], Array(3)],
|
||||
expected = [1, 2, 3];
|
||||
|
||||
expected.push(undefined, undefined, undefined);
|
||||
|
||||
lodashStable.each(methodNames, function(methodName) {
|
||||
var actual = _[methodName](array);
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
assert.ok('4' in actual);
|
||||
});
|
||||
});
|
||||
|
||||
it('should flatten objects with a truthy `Symbol.isConcatSpreadable` value', function() {
|
||||
if (Symbol && Symbol.isConcatSpreadable) {
|
||||
var object = { '0': 'a', 'length': 1 },
|
||||
array = [object],
|
||||
expected = lodashStable.map(methodNames, lodashStable.constant(['a']));
|
||||
|
||||
object[Symbol.isConcatSpreadable] = true;
|
||||
|
||||
var actual = lodashStable.map(methodNames, function(methodName) {
|
||||
return _[methodName](array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
}
|
||||
});
|
||||
|
||||
it('should work with extremely large arrays', function() {
|
||||
lodashStable.times(3, function(index) {
|
||||
var expected = Array(5e5);
|
||||
try {
|
||||
var func = flatten;
|
||||
if (index == 1) {
|
||||
func = flattenDeep;
|
||||
} else if (index == 2) {
|
||||
func = flattenDepth;
|
||||
}
|
||||
assert.deepStrictEqual(func([expected]), expected);
|
||||
} catch (e) {
|
||||
assert.ok(false, e.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with empty arrays', function() {
|
||||
var array = [[], [[]], [[], [[[]]]]];
|
||||
|
||||
assert.deepStrictEqual(flatten(array), [[], [], [[[]]]]);
|
||||
assert.deepStrictEqual(flattenDeep(array), []);
|
||||
assert.deepStrictEqual(flattenDepth(array, 2), [[[]]]);
|
||||
});
|
||||
|
||||
it('should support flattening of nested arrays', function() {
|
||||
assert.deepStrictEqual(flatten(array), [1, 2, [3, [4]], 5]);
|
||||
assert.deepStrictEqual(flattenDeep(array), [1, 2, 3, 4, 5]);
|
||||
assert.deepStrictEqual(flattenDepth(array, 2), [1, 2, 3, [4], 5]);
|
||||
});
|
||||
|
||||
it('should return an empty array for non array-like objects', function() {
|
||||
var expected = [],
|
||||
nonArray = { '0': 'a' };
|
||||
|
||||
assert.deepStrictEqual(flatten(nonArray), expected);
|
||||
assert.deepStrictEqual(flattenDeep(nonArray), expected);
|
||||
assert.deepStrictEqual(flattenDepth(nonArray, 2), expected);
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var wrapped = _(array),
|
||||
actual = wrapped.flatten();
|
||||
|
||||
assert.ok(actual instanceof _);
|
||||
assert.deepEqual(actual.value(), [1, 2, [3, [4]], 5]);
|
||||
|
||||
actual = wrapped.flattenDeep();
|
||||
|
||||
assert.ok(actual instanceof _);
|
||||
assert.deepEqual(actual.value(), [1, 2, 3, 4, 5]);
|
||||
|
||||
actual = wrapped.flattenDepth(2);
|
||||
|
||||
assert.ok(actual instanceof _);
|
||||
assert.deepEqual(actual.value(), [1, 2, 3, [4], 5]);
|
||||
});
|
||||
});
|
||||
21
test/flattenDepth.js
Normal file
21
test/flattenDepth.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import flattenDepth from '../flattenDepth.js';
|
||||
|
||||
describe('flattenDepth', function() {
|
||||
var array = [1, [2, [3, [4]], 5]];
|
||||
|
||||
it('should use a default `depth` of `1`', function() {
|
||||
assert.deepStrictEqual(flattenDepth(array), [1, 2, [3, [4]], 5]);
|
||||
});
|
||||
|
||||
it('should treat a `depth` of < `1` as a shallow clone', function() {
|
||||
lodashStable.each([-1, 0], function(depth) {
|
||||
assert.deepStrictEqual(flattenDepth(array, depth), [1, [2, [3, [4]], 5]]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should coerce `depth` to an integer', function() {
|
||||
assert.deepStrictEqual(flattenDepth(array, 2.2), [1, 2, 3, [4], 5]);
|
||||
});
|
||||
});
|
||||
14
test/flip.test.js
Normal file
14
test/flip.test.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import flip from '../flip.js';
|
||||
|
||||
describe('flip', function() {
|
||||
function fn() {
|
||||
return slice.call(arguments);
|
||||
}
|
||||
|
||||
it('should flip arguments provided to `func`', function() {
|
||||
var flipped = flip(fn);
|
||||
assert.deepStrictEqual(flipped('a', 'b', 'c', 'd'), ['d', 'c', 'b', 'a']);
|
||||
});
|
||||
});
|
||||
108
test/flow-methods.js
Normal file
108
test/flow-methods.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, add, square, noop, identity, LARGE_ARRAY_SIZE, isEven, isNpm } from './utils.js';
|
||||
import times from '../times.js';
|
||||
import curry from '../curry.js';
|
||||
import head from '../head.js';
|
||||
import filter from '../filter.js';
|
||||
import rearg from '../rearg.js';
|
||||
import ary from '../ary.js';
|
||||
import map from '../map.js';
|
||||
import take from '../take.js';
|
||||
import compact from '../compact.js';
|
||||
import uniq from '../uniq.js';
|
||||
|
||||
describe('flow methods', function() {
|
||||
lodashStable.each(['flow', 'flowRight'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isFlow = methodName == 'flow';
|
||||
|
||||
it('`_.' + methodName + '` should supply each function with the return value of the previous', function() {
|
||||
var fixed = function(n) { return n.toFixed(1); },
|
||||
combined = isFlow ? func(add, square, fixed) : func(fixed, square, add);
|
||||
|
||||
assert.strictEqual(combined(1, 2), '9.0');
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return a new function', function() {
|
||||
assert.notStrictEqual(func(noop), noop);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return an identity function when no arguments are given', function() {
|
||||
times(2, function(index) {
|
||||
try {
|
||||
var combined = index ? func([]) : func();
|
||||
assert.strictEqual(combined('a'), 'a');
|
||||
} catch (e) {
|
||||
assert.ok(false, e.message);
|
||||
}
|
||||
assert.strictEqual(combined.length, 0);
|
||||
assert.notStrictEqual(combined, identity);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a curried function and `_.head`', function() {
|
||||
var curried = curry(identity);
|
||||
|
||||
var combined = isFlow
|
||||
? func(head, curried)
|
||||
: func(curried, head);
|
||||
|
||||
assert.strictEqual(combined([1]), 1);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should support shortcut fusion', function() {
|
||||
var filterCount,
|
||||
mapCount,
|
||||
array = lodashStable.range(LARGE_ARRAY_SIZE),
|
||||
iteratee = function(value) { mapCount++; return square(value); },
|
||||
predicate = function(value) { filterCount++; return isEven(value); };
|
||||
|
||||
lodashStable.times(2, function(index) {
|
||||
var filter1 = filter,
|
||||
filter2 = curry(rearg(ary(filter, 2), 1, 0), 2),
|
||||
filter3 = (filter = index ? filter2 : filter1, filter2(predicate));
|
||||
|
||||
var map1 = map,
|
||||
map2 = curry(rearg(ary(map, 2), 1, 0), 2),
|
||||
map3 = (map = index ? map2 : map1, map2(iteratee));
|
||||
|
||||
var take1 = take,
|
||||
take2 = curry(rearg(ary(take, 2), 1, 0), 2),
|
||||
take3 = (take = index ? take2 : take1, take2(2));
|
||||
|
||||
var combined = isFlow
|
||||
? func(map3, filter3, compact, take3)
|
||||
: func(take3, compact, filter3, map3);
|
||||
|
||||
filterCount = mapCount = 0;
|
||||
assert.deepStrictEqual(combined(array), [4, 16]);
|
||||
|
||||
if (!isNpm && WeakMap && WeakMap.name) {
|
||||
assert.strictEqual(filterCount, 5, 'filterCount');
|
||||
assert.strictEqual(mapCount, 5, 'mapCount');
|
||||
}
|
||||
filter = filter1;
|
||||
map = map1;
|
||||
take = take1;
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with curried functions with placeholders', function() {
|
||||
var curried = curry(ary(map, 2), 2),
|
||||
getProp = curried(curried.placeholder, 'a'),
|
||||
objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }];
|
||||
|
||||
var combined = isFlow
|
||||
? func(getProp, uniq)
|
||||
: func(uniq, getProp);
|
||||
|
||||
assert.deepStrictEqual(combined(objects), [1, 2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return a wrapped value when chaining', function() {
|
||||
var wrapped = _(noop)[methodName]();
|
||||
assert.ok(wrapped instanceof _);
|
||||
});
|
||||
});
|
||||
});
|
||||
9
test/forEach.test.js
Normal file
9
test/forEach.test.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import assert from 'assert';
|
||||
import each from '../each.js';
|
||||
import forEach from '../forEach.js';
|
||||
|
||||
describe('forEach', function() {
|
||||
it('should be aliased', function() {
|
||||
assert.strictEqual(each, forEach);
|
||||
});
|
||||
});
|
||||
9
test/forEachRight.test.js
Normal file
9
test/forEachRight.test.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import assert from 'assert';
|
||||
import eachRight from '../eachRight.js';
|
||||
import forEachRight from '../forEachRight.js';
|
||||
|
||||
describe('forEachRight', function() {
|
||||
it('should be aliased', function() {
|
||||
assert.strictEqual(eachRight, forEachRight);
|
||||
});
|
||||
});
|
||||
20
test/forIn-methods.js
Normal file
20
test/forIn-methods.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _ } from './utils.js';
|
||||
|
||||
describe('forIn methods', function() {
|
||||
lodashStable.each(['forIn', 'forInRight'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` iterates over inherited string keyed properties', function() {
|
||||
function Foo() {
|
||||
this.a = 1;
|
||||
}
|
||||
Foo.prototype.b = 2;
|
||||
|
||||
var keys = [];
|
||||
func(new Foo, function(value, key) { keys.push(key); });
|
||||
assert.deepStrictEqual(keys.sort(), ['a', 'b']);
|
||||
});
|
||||
});
|
||||
});
|
||||
17
test/forOwn-methods.js
Normal file
17
test/forOwn-methods.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _ } from './utils.js';
|
||||
|
||||
describe('forOwn methods', function() {
|
||||
lodashStable.each(['forOwn', 'forOwnRight'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should iterate over `length` properties', function() {
|
||||
var object = { '0': 'zero', '1': 'one', 'length': 2 },
|
||||
props = [];
|
||||
|
||||
func(object, function(value, prop) { props.push(prop); });
|
||||
assert.deepStrictEqual(props.sort(), ['0', '1', 'length']);
|
||||
});
|
||||
});
|
||||
});
|
||||
47
test/fromPairs.js
Normal file
47
test/fromPairs.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, stubObject, LARGE_ARRAY_SIZE } from './utils.js';
|
||||
import fromPairs from '../fromPairs.js';
|
||||
import toPairs from '../toPairs.js';
|
||||
|
||||
describe('fromPairs', function() {
|
||||
it('should accept a two dimensional array', function() {
|
||||
var array = [['a', 1], ['b', 2]],
|
||||
object = { 'a': 1, 'b': 2 },
|
||||
actual = fromPairs(array);
|
||||
|
||||
assert.deepStrictEqual(actual, object);
|
||||
});
|
||||
|
||||
it('should accept a falsey `array`', function() {
|
||||
var expected = lodashStable.map(falsey, stubObject);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(array, index) {
|
||||
try {
|
||||
return index ? fromPairs(array) : fromPairs();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should not support deep paths', function() {
|
||||
var actual = fromPairs([['a.b', 1]]);
|
||||
assert.deepStrictEqual(actual, { 'a.b': 1 });
|
||||
});
|
||||
|
||||
it('should support consuming the return value of `_.toPairs`', function() {
|
||||
var object = { 'a.b': 1 };
|
||||
assert.deepStrictEqual(fromPairs(toPairs(object)), object);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) {
|
||||
return ['key' + index, index];
|
||||
});
|
||||
|
||||
var actual = _(array).fromPairs().map(square).filter(isEven).take().value();
|
||||
|
||||
assert.deepEqual(actual, _.take(_.filter(_.map(fromPairs(array), square), isEven)));
|
||||
});
|
||||
});
|
||||
22
test/functions.test.js
Normal file
22
test/functions.test.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import assert from 'assert';
|
||||
import { identity, noop } from './utils.js';
|
||||
import functions from '../functions.js';
|
||||
|
||||
describe('functions', function() {
|
||||
it('should return the function names of an object', function() {
|
||||
var object = { 'a': 'a', 'b': identity, 'c': /x/, 'd': noop },
|
||||
actual = functions(object).sort();
|
||||
|
||||
assert.deepStrictEqual(actual, ['b', 'd']);
|
||||
});
|
||||
|
||||
it('should not include inherited functions', function() {
|
||||
function Foo() {
|
||||
this.a = identity;
|
||||
this.b = 'b';
|
||||
}
|
||||
Foo.prototype.c = noop;
|
||||
|
||||
assert.deepStrictEqual(functions(new Foo), ['a']);
|
||||
});
|
||||
});
|
||||
148
test/get-and-result.js
Normal file
148
test/get-and-result.js
Normal file
@@ -0,0 +1,148 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, symbol, noop, numberProto, empties } from './utils.js';
|
||||
|
||||
describe('get and result', function() {
|
||||
lodashStable.each(['get', 'result'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should get string keyed property values', function() {
|
||||
var object = { 'a': 1 };
|
||||
|
||||
lodashStable.each(['a', ['a']], function(path) {
|
||||
assert.strictEqual(func(object, path), 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should preserve the sign of `0`', function() {
|
||||
var object = { '-0': 'a', '0': 'b' },
|
||||
props = [-0, Object(-0), 0, Object(0)];
|
||||
|
||||
var actual = lodashStable.map(props, function(key) {
|
||||
return func(object, key);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should get symbol keyed property values', function() {
|
||||
if (Symbol) {
|
||||
var object = {};
|
||||
object[symbol] = 1;
|
||||
|
||||
assert.strictEqual(func(object, symbol), 1);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should get deep property values', function() {
|
||||
var object = { 'a': { 'b': 2 } };
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
assert.strictEqual(func(object, path), 2);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should get a key over a path', function() {
|
||||
var object = { 'a.b': 1, 'a': { 'b': 2 } };
|
||||
|
||||
lodashStable.each(['a.b', ['a.b']], function(path) {
|
||||
assert.strictEqual(func(object, path), 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not coerce array paths to strings', function() {
|
||||
var object = { 'a,b,c': 3, 'a': { 'b': { 'c': 4 } } };
|
||||
assert.strictEqual(func(object, ['a', 'b', 'c']), 4);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not ignore empty brackets', function() {
|
||||
var object = { 'a': { '': 1 } };
|
||||
assert.strictEqual(func(object, 'a[]'), 1);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should handle empty paths', function() {
|
||||
lodashStable.each([['', ''], [[], ['']]], function(pair) {
|
||||
assert.strictEqual(func({}, pair[0]), undefined);
|
||||
assert.strictEqual(func({ '': 3 }, pair[1]), 3);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should handle complex paths', function() {
|
||||
var object = { 'a': { '-1.23': { '["b"]': { 'c': { "['d']": { '\ne\n': { 'f': { 'g': 8 } } } } } } } };
|
||||
|
||||
var paths = [
|
||||
'a[-1.23]["[\\"b\\"]"].c[\'[\\\'d\\\']\'][\ne\n][f].g',
|
||||
['a', '-1.23', '["b"]', 'c', "['d']", '\ne\n', 'f', 'g']
|
||||
];
|
||||
|
||||
lodashStable.each(paths, function(path) {
|
||||
assert.strictEqual(func(object, path), 8);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `undefined` when `object` is nullish', function() {
|
||||
lodashStable.each(['constructor', ['constructor']], function(path) {
|
||||
assert.strictEqual(func(null, path), undefined);
|
||||
assert.strictEqual(func(undefined, path), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `undefined` for deep paths when `object` is nullish', function() {
|
||||
var values = [null, undefined],
|
||||
expected = lodashStable.map(values, noop),
|
||||
paths = ['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']];
|
||||
|
||||
lodashStable.each(paths, function(path) {
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return func(value, path);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `undefined` if parts of `path` are missing', function() {
|
||||
var object = { 'a': [, null] };
|
||||
|
||||
lodashStable.each(['a[1].b.c', ['a', '1', 'b', 'c']], function(path) {
|
||||
assert.strictEqual(func(object, path), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should be able to return `null` values', function() {
|
||||
var object = { 'a': { 'b': null } };
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
assert.strictEqual(func(object, path), null);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should follow `path` over non-plain objects', function() {
|
||||
var paths = ['a.b', ['a', 'b']];
|
||||
|
||||
lodashStable.each(paths, function(path) {
|
||||
numberProto.a = { 'b': 2 };
|
||||
assert.strictEqual(func(0, path), 2);
|
||||
delete numberProto.a;
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return the default value for `undefined` values', function() {
|
||||
var object = { 'a': {} },
|
||||
values = empties.concat(true, new Date, 1, /x/, 'a'),
|
||||
expected = lodashStable.map(values, function(value) { return [value, value]; });
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return [func(object, path, value), func(null, path, value)];
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return the default value when `path` is empty', function() {
|
||||
assert.strictEqual(func({}, [], 'a'), 'a');
|
||||
});
|
||||
});
|
||||
});
|
||||
68
test/groupBy.js
Normal file
68
test/groupBy.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE } from './utils.js';
|
||||
import groupBy from '../groupBy.js';
|
||||
|
||||
describe('groupBy', function() {
|
||||
var array = [6.1, 4.2, 6.3];
|
||||
|
||||
it('should transform keys by `iteratee`', function() {
|
||||
var actual = groupBy(array, Math.floor);
|
||||
assert.deepStrictEqual(actual, { '4': [4.2], '6': [6.1, 6.3] });
|
||||
});
|
||||
|
||||
it('should use `_.identity` when `iteratee` is nullish', function() {
|
||||
var array = [6, 4, 6],
|
||||
values = [, null, undefined],
|
||||
expected = lodashStable.map(values, lodashStable.constant({ '4': [4], '6': [6, 6] }));
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? groupBy(array, value) : groupBy(array);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with `_.property` shorthands', function() {
|
||||
var actual = groupBy(['one', 'two', 'three'], 'length');
|
||||
assert.deepStrictEqual(actual, { '3': ['one', 'two'], '5': ['three'] });
|
||||
});
|
||||
|
||||
it('should only add values to own, not inherited, properties', function() {
|
||||
var actual = groupBy(array, function(n) {
|
||||
return Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual.constructor, [4.2]);
|
||||
assert.deepStrictEqual(actual.hasOwnProperty, [6.1, 6.3]);
|
||||
});
|
||||
|
||||
it('should work with a number for `iteratee`', function() {
|
||||
var array = [
|
||||
[1, 'a'],
|
||||
[2, 'a'],
|
||||
[2, 'b']
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(groupBy(array, 0), { '1': [[1, 'a']], '2': [[2, 'a'], [2, 'b']] });
|
||||
assert.deepStrictEqual(groupBy(array, 1), { 'a': [[1, 'a'], [2, 'a']], 'b': [[2, 'b']] });
|
||||
});
|
||||
|
||||
it('should work with an object for `collection`', function() {
|
||||
var actual = groupBy({ 'a': 6.1, 'b': 4.2, 'c': 6.3 }, Math.floor);
|
||||
assert.deepStrictEqual(actual, { '4': [4.2], '6': [6.1, 6.3] });
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(LARGE_ARRAY_SIZE).concat(
|
||||
lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 2), LARGE_ARRAY_SIZE),
|
||||
lodashStable.range(Math.floor(LARGE_ARRAY_SIZE / 1.5), LARGE_ARRAY_SIZE)
|
||||
);
|
||||
|
||||
var iteratee = function(value) { value.push(value[0]); return value; },
|
||||
predicate = function(value) { return isEven(value[0]); },
|
||||
actual = _(array).groupBy().map(iteratee).filter(predicate).take().value();
|
||||
|
||||
assert.deepEqual(actual, _.take(_.filter(lodashStable.map(groupBy(array), iteratee), predicate)));
|
||||
});
|
||||
});
|
||||
16
test/gt.test.js
Normal file
16
test/gt.test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import assert from 'assert';
|
||||
import gt from '../gt.js';
|
||||
|
||||
describe('gt', function() {
|
||||
it('should return `true` if `value` > `other`', function() {
|
||||
assert.strictEqual(gt(3, 1), true);
|
||||
assert.strictEqual(gt('def', 'abc'), true);
|
||||
});
|
||||
|
||||
it('should return `false` if `value` is <= `other`', function() {
|
||||
assert.strictEqual(gt(1, 3), false);
|
||||
assert.strictEqual(gt(3, 3), false);
|
||||
assert.strictEqual(gt('abc', 'def'), false);
|
||||
assert.strictEqual(gt('def', 'def'), false);
|
||||
});
|
||||
});
|
||||
16
test/gte.test.js
Normal file
16
test/gte.test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import assert from 'assert';
|
||||
import gte from '../gte.js';
|
||||
|
||||
describe('gte', function() {
|
||||
it('should return `true` if `value` >= `other`', function() {
|
||||
assert.strictEqual(gte(3, 1), true);
|
||||
assert.strictEqual(gte(3, 3), true);
|
||||
assert.strictEqual(gte('def', 'abc'), true);
|
||||
assert.strictEqual(gte('def', 'def'), true);
|
||||
});
|
||||
|
||||
it('should return `false` if `value` is less than `other`', function() {
|
||||
assert.strictEqual(gte(1, 3), false);
|
||||
assert.strictEqual(gte('abc', 'def'), false);
|
||||
});
|
||||
});
|
||||
205
test/has-methods.js
Normal file
205
test/has-methods.js
Normal file
@@ -0,0 +1,205 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, toArgs, stubTrue, args, symbol, defineProperty, stubFalse } from './utils.js';
|
||||
|
||||
describe('has methods', function() {
|
||||
lodashStable.each(['has', 'hasIn'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isHas = methodName == 'has',
|
||||
sparseArgs = toArgs([1]),
|
||||
sparseArray = Array(1),
|
||||
sparseString = Object('a');
|
||||
|
||||
delete sparseArgs[0];
|
||||
delete sparseString[0];
|
||||
|
||||
it('`_.' + methodName + '` should check for own properties', function() {
|
||||
var object = { 'a': 1 };
|
||||
|
||||
lodashStable.each(['a', ['a']], function(path) {
|
||||
assert.strictEqual(func(object, path), true);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not use the `hasOwnProperty` method of `object`', function() {
|
||||
var object = { 'hasOwnProperty': null, 'a': 1 };
|
||||
assert.strictEqual(func(object, 'a'), true);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should support deep paths', function() {
|
||||
var object = { 'a': { 'b': 2 } };
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
assert.strictEqual(func(object, path), true);
|
||||
});
|
||||
|
||||
lodashStable.each(['a.a', ['a', 'a']], function(path) {
|
||||
assert.strictEqual(func(object, path), false);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should coerce `path` to a string', function() {
|
||||
function fn() {}
|
||||
fn.toString = lodashStable.constant('fn');
|
||||
|
||||
var object = { 'null': 1 , 'undefined': 2, 'fn': 3, '[object Object]': 4 },
|
||||
paths = [null, undefined, fn, {}],
|
||||
expected = lodashStable.map(paths, stubTrue);
|
||||
|
||||
lodashStable.times(2, function(index) {
|
||||
var actual = lodashStable.map(paths, function(path) {
|
||||
return func(object, index ? [path] : path);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `arguments` objects', function() {
|
||||
assert.strictEqual(func(args, 1), true);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a non-string `path`', function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
lodashStable.each([1, [1]], function(path) {
|
||||
assert.strictEqual(func(array, path), true);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should preserve the sign of `0`', function() {
|
||||
var object = { '-0': 'a', '0': 'b' },
|
||||
props = [-0, Object(-0), 0, Object(0)],
|
||||
expected = lodashStable.map(props, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(props, function(key) {
|
||||
return func(object, key);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a symbol `path`', function() {
|
||||
function Foo() {}
|
||||
|
||||
if (Symbol) {
|
||||
Foo.prototype[symbol] = 1;
|
||||
|
||||
var symbol2 = Symbol('b');
|
||||
defineProperty(Foo.prototype, symbol2, {
|
||||
'configurable': true,
|
||||
'enumerable': false,
|
||||
'writable': true,
|
||||
'value': 2
|
||||
});
|
||||
|
||||
var object = isHas ? Foo.prototype : new Foo;
|
||||
assert.strictEqual(func(object, symbol), true);
|
||||
assert.strictEqual(func(object, symbol2), true);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should check for a key over a path', function() {
|
||||
var object = { 'a.b': 1 };
|
||||
|
||||
lodashStable.each(['a.b', ['a.b']], function(path) {
|
||||
assert.strictEqual(func(object, path), true);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `true` for indexes of sparse values', function() {
|
||||
var values = [sparseArgs, sparseArray, sparseString],
|
||||
expected = lodashStable.map(values, stubTrue);
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return func(value, 0);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `true` for indexes of sparse values with deep paths', function() {
|
||||
var values = [sparseArgs, sparseArray, sparseString],
|
||||
expected = lodashStable.map(values, lodashStable.constant([true, true]));
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return lodashStable.map(['a[0]', ['a', '0']], function(path) {
|
||||
return func({ 'a': value }, path);
|
||||
});
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for inherited properties', function() {
|
||||
function Foo() {}
|
||||
Foo.prototype.a = 1;
|
||||
|
||||
lodashStable.each(['a', ['a']], function(path) {
|
||||
assert.strictEqual(func(new Foo, path), !isHas);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `' + (isHas ? 'false' : 'true') + '` for nested inherited properties', function() {
|
||||
function Foo() {}
|
||||
Foo.prototype.a = { 'b': 1 };
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
assert.strictEqual(func(new Foo, path), !isHas);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `false` when `object` is nullish', function() {
|
||||
var values = [null, undefined],
|
||||
expected = lodashStable.map(values, stubFalse);
|
||||
|
||||
lodashStable.each(['constructor', ['constructor']], function(path) {
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return func(value, path);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `false` for deep paths when `object` is nullish', function() {
|
||||
var values = [null, undefined],
|
||||
expected = lodashStable.map(values, stubFalse);
|
||||
|
||||
lodashStable.each(['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']], function(path) {
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return func(value, path);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `false` for nullish values of nested objects', function() {
|
||||
var values = [, null, undefined],
|
||||
expected = lodashStable.map(values, stubFalse);
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
var object = index ? { 'a': value } : {};
|
||||
return func(object, path);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `false` over sparse values of deep paths', function() {
|
||||
var values = [sparseArgs, sparseArray, sparseString],
|
||||
expected = lodashStable.map(values, lodashStable.constant([false, false]));
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return lodashStable.map(['a[0].b', ['a', '0', 'b']], function(path) {
|
||||
return func({ 'a': value }, path);
|
||||
});
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
62
test/head.js
Normal file
62
test/head.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { arrayProto, LARGE_ARRAY_SIZE } from './utils.js';
|
||||
import head from '../head.js';
|
||||
import first from '../first.js';
|
||||
|
||||
describe('head', function() {
|
||||
var array = [1, 2, 3, 4];
|
||||
|
||||
it('should return the first element', function() {
|
||||
assert.strictEqual(head(array), 1);
|
||||
});
|
||||
|
||||
it('should return `undefined` when querying empty arrays', function() {
|
||||
arrayProto[0] = 1;
|
||||
assert.strictEqual(head([]), undefined);
|
||||
arrayProto.length = 0;
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
|
||||
actual = lodashStable.map(array, head);
|
||||
|
||||
assert.deepStrictEqual(actual, [1, 4, 7]);
|
||||
});
|
||||
|
||||
it('should be aliased', function() {
|
||||
assert.strictEqual(first, head);
|
||||
});
|
||||
|
||||
it('should return an unwrapped value when implicitly chaining', function() {
|
||||
var wrapped = _(array);
|
||||
assert.strictEqual(wrapped.head(), 1);
|
||||
assert.strictEqual(wrapped.first(), 1);
|
||||
});
|
||||
|
||||
it('should return a wrapped value when explicitly chaining', function() {
|
||||
var wrapped = _(array).chain();
|
||||
assert.ok(wrapped.head() instanceof _);
|
||||
assert.ok(wrapped.first() instanceof _);
|
||||
});
|
||||
|
||||
it('should not execute immediately when explicitly chaining', function() {
|
||||
var wrapped = _(array).chain();
|
||||
assert.strictEqual(wrapped.head().__wrapped__, array);
|
||||
assert.strictEqual(wrapped.first().__wrapped__, array);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var largeArray = lodashStable.range(LARGE_ARRAY_SIZE),
|
||||
smallArray = array;
|
||||
|
||||
lodashStable.each(['head', 'first'], function(methodName) {
|
||||
lodashStable.times(2, function(index) {
|
||||
var array = index ? largeArray : smallArray,
|
||||
actual = _(array).filter(isEven)[methodName]();
|
||||
|
||||
assert.strictEqual(actual, _[methodName](_.filter(array, isEven)));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
9
test/identity.js
Normal file
9
test/identity.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import assert from 'assert';
|
||||
import identity from '../identity.js';
|
||||
|
||||
describe('identity', function() {
|
||||
it('should return the first argument given', function() {
|
||||
var object = { 'name': 'fred' };
|
||||
assert.strictEqual(identity(object), object);
|
||||
});
|
||||
});
|
||||
54
test/inRange.js
Normal file
54
test/inRange.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, stubTrue } from './utils.js';
|
||||
import inRange from '../inRange.js';
|
||||
|
||||
describe('inRange', function() {
|
||||
it('should work with an `end`', function() {
|
||||
assert.strictEqual(inRange(3, 5), true);
|
||||
assert.strictEqual(inRange(5, 5), false);
|
||||
assert.strictEqual(inRange(6, 5), false);
|
||||
});
|
||||
|
||||
it('should work with a `start` and `end`', function() {
|
||||
assert.strictEqual(inRange(1, 1, 5), true);
|
||||
assert.strictEqual(inRange(3, 1, 5), true);
|
||||
assert.strictEqual(inRange(0, 1, 5), false);
|
||||
assert.strictEqual(inRange(5, 1, 5), false);
|
||||
});
|
||||
|
||||
it('should treat falsey `start` as `0`', function() {
|
||||
lodashStable.each(falsey, function(value, index) {
|
||||
if (index) {
|
||||
assert.strictEqual(inRange(0, value), false);
|
||||
assert.strictEqual(inRange(0, value, 1), true);
|
||||
} else {
|
||||
assert.strictEqual(inRange(0), false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should swap `start` and `end` when `start` > `end`', function() {
|
||||
assert.strictEqual(inRange(2, 5, 1), true);
|
||||
assert.strictEqual(inRange(-3, -2, -6), true);
|
||||
});
|
||||
|
||||
it('should work with a floating point `n` value', function() {
|
||||
assert.strictEqual(inRange(0.5, 5), true);
|
||||
assert.strictEqual(inRange(1.2, 1, 5), true);
|
||||
assert.strictEqual(inRange(5.2, 5), false);
|
||||
assert.strictEqual(inRange(0.5, 1, 5), false);
|
||||
});
|
||||
|
||||
it('should coerce arguments to finite numbers', function() {
|
||||
var actual = [
|
||||
inRange(0, '1'),
|
||||
inRange(0, '0', 1),
|
||||
inRange(0, 0, '1'),
|
||||
inRange(0, NaN, 1),
|
||||
inRange(-1, -1, NaN)
|
||||
];
|
||||
|
||||
assert.deepStrictEqual(actual, lodashStable.map(actual, stubTrue));
|
||||
});
|
||||
});
|
||||
95
test/includes.js
Normal file
95
test/includes.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { empties, stubFalse } from './utils.js';
|
||||
import includes from '../includes.js';
|
||||
|
||||
describe('includes', function() {
|
||||
(function() {
|
||||
lodashStable.each({
|
||||
'an `arguments` object': arguments,
|
||||
'an array': [1, 2, 3, 4],
|
||||
'an object': { 'a': 1, 'b': 2, 'c': 3, 'd': 4 },
|
||||
'a string': '1234'
|
||||
},
|
||||
function(collection, key) {
|
||||
it('should work with ' + key + ' and return `true` for matched values', function() {
|
||||
assert.strictEqual(includes(collection, 3), true);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and return `false` for unmatched values', function() {
|
||||
assert.strictEqual(includes(collection, 5), false);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and floor `position` values', function() {
|
||||
assert.strictEqual(includes(collection, 2, 1.2), true);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and return an unwrapped value implicitly when chaining', function() {
|
||||
assert.strictEqual(_(collection).includes(3), true);
|
||||
});
|
||||
|
||||
it('should work with ' + key + ' and return a wrapped value when explicitly chaining', function() {
|
||||
assert.ok(_(collection).chain().includes(3) instanceof _);
|
||||
});
|
||||
});
|
||||
|
||||
lodashStable.each({
|
||||
'literal': 'abc',
|
||||
'object': Object('abc')
|
||||
},
|
||||
function(collection, key) {
|
||||
it('should work with a string ' + key + ' for `collection`', function() {
|
||||
assert.strictEqual(includes(collection, 'bc'), true);
|
||||
assert.strictEqual(includes(collection, 'd'), false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return `false` for empty collections', function() {
|
||||
var expected = lodashStable.map(empties, stubFalse);
|
||||
|
||||
var actual = lodashStable.map(empties, function(value) {
|
||||
try {
|
||||
return includes(value);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should work with a string and a `fromIndex` >= `length`', function() {
|
||||
var string = '1234',
|
||||
length = string.length,
|
||||
indexes = [4, 6, Math.pow(2, 32), Infinity];
|
||||
|
||||
var expected = lodashStable.map(indexes, function(index) {
|
||||
return [false, false, index == length];
|
||||
});
|
||||
|
||||
var actual = lodashStable.map(indexes, function(fromIndex) {
|
||||
return [
|
||||
includes(string, 1, fromIndex),
|
||||
includes(string, undefined, fromIndex),
|
||||
includes(string, '', fromIndex)
|
||||
];
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should match `NaN`', function() {
|
||||
assert.strictEqual(includes([1, NaN, 3], NaN), true);
|
||||
});
|
||||
|
||||
it('should match `-0` as `0`', function() {
|
||||
assert.strictEqual(includes([-0], 0), true);
|
||||
assert.strictEqual(includes([0], -0), true);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.every`', function() {
|
||||
var array = [2, 3, 1],
|
||||
values = [1, 2, 3];
|
||||
|
||||
assert.ok(lodashStable.every(values, lodashStable.partial(includes, array)));
|
||||
});
|
||||
})(1, 2, 3, 4);
|
||||
});
|
||||
63
test/indexOf-methods.js
Normal file
63
test/indexOf-methods.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, falsey } from './utils.js';
|
||||
|
||||
describe('indexOf methods', function() {
|
||||
lodashStable.each(['indexOf', 'lastIndexOf', 'sortedIndexOf', 'sortedLastIndexOf'], function(methodName) {
|
||||
var func = _[methodName],
|
||||
isIndexOf = !/last/i.test(methodName),
|
||||
isSorted = /^sorted/.test(methodName);
|
||||
|
||||
it('`_.' + methodName + '` should accept a falsey `array`', function() {
|
||||
var expected = lodashStable.map(falsey, lodashStable.constant(-1));
|
||||
|
||||
var actual = lodashStable.map(falsey, function(array, index) {
|
||||
try {
|
||||
return index ? func(array) : func();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return `-1` for an unmatched value', function() {
|
||||
var array = [1, 2, 3],
|
||||
empty = [];
|
||||
|
||||
assert.strictEqual(func(array, 4), -1);
|
||||
assert.strictEqual(func(array, 4, true), -1);
|
||||
assert.strictEqual(func(array, undefined, true), -1);
|
||||
|
||||
assert.strictEqual(func(empty, undefined), -1);
|
||||
assert.strictEqual(func(empty, undefined, true), -1);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should not match values on empty arrays', function() {
|
||||
var array = [];
|
||||
array[-1] = 0;
|
||||
|
||||
assert.strictEqual(func(array, undefined), -1);
|
||||
assert.strictEqual(func(array, 0, true), -1);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should match `NaN`', function() {
|
||||
var array = isSorted
|
||||
? [1, 2, NaN, NaN]
|
||||
: [1, NaN, 3, NaN, 5, NaN];
|
||||
|
||||
if (isSorted) {
|
||||
assert.strictEqual(func(array, NaN, true), isIndexOf ? 2 : 3);
|
||||
}
|
||||
else {
|
||||
assert.strictEqual(func(array, NaN), isIndexOf ? 1 : 5);
|
||||
assert.strictEqual(func(array, NaN, 2), isIndexOf ? 3 : 1);
|
||||
assert.strictEqual(func(array, NaN, -2), isIndexOf ? 5 : 3);
|
||||
}
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should match `-0` as `0`', function() {
|
||||
assert.strictEqual(func([-0], 0), 0);
|
||||
assert.strictEqual(func([0], -0), 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
61
test/initial.js
Normal file
61
test/initial.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { falsey, stubArray, LARGE_ARRAY_SIZE } from './utils.js';
|
||||
import initial from '../initial.js';
|
||||
|
||||
describe('initial', function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
it('should accept a falsey `array`', function() {
|
||||
var expected = lodashStable.map(falsey, stubArray);
|
||||
|
||||
var actual = lodashStable.map(falsey, function(array, index) {
|
||||
try {
|
||||
return index ? initial(array) : initial();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should exclude last element', function() {
|
||||
assert.deepStrictEqual(initial(array), [1, 2]);
|
||||
});
|
||||
|
||||
it('should return an empty when querying empty arrays', function() {
|
||||
assert.deepStrictEqual(initial([]), []);
|
||||
});
|
||||
|
||||
it('should work as an iteratee for methods like `_.map`', function() {
|
||||
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
|
||||
actual = lodashStable.map(array, initial);
|
||||
|
||||
assert.deepStrictEqual(actual, [[1, 2], [4, 5], [7, 8]]);
|
||||
});
|
||||
|
||||
it('should work in a lazy sequence', function() {
|
||||
var array = lodashStable.range(LARGE_ARRAY_SIZE),
|
||||
values = [];
|
||||
|
||||
var actual = _(array).initial().filter(function(value) {
|
||||
values.push(value);
|
||||
return false;
|
||||
})
|
||||
.value();
|
||||
|
||||
assert.deepEqual(actual, []);
|
||||
assert.deepEqual(values, initial(array));
|
||||
|
||||
values = [];
|
||||
|
||||
actual = _(array).filter(function(value) {
|
||||
values.push(value);
|
||||
return isEven(value);
|
||||
})
|
||||
.initial()
|
||||
.value();
|
||||
|
||||
assert.deepEqual(actual, initial(lodashStable.filter(array, isEven)));
|
||||
assert.deepEqual(values, array);
|
||||
});
|
||||
});
|
||||
91
test/intersection-methods.js
Normal file
91
test/intersection-methods.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { _, args, LARGE_ARRAY_SIZE, stubNaN } from './utils.js';
|
||||
|
||||
describe('intersection methods', function() {
|
||||
lodashStable.each(['intersection', 'intersectionBy', 'intersectionWith'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
|
||||
it('`_.' + methodName + '` should return the intersection of two arrays', function() {
|
||||
var actual = func([2, 1], [2, 3]);
|
||||
assert.deepStrictEqual(actual, [2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return the intersection of multiple arrays', function() {
|
||||
var actual = func([2, 1, 2, 3], [3, 4], [3, 2]);
|
||||
assert.deepStrictEqual(actual, [3]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return an array of unique values', function() {
|
||||
var actual = func([1, 1, 3, 2, 2], [5, 2, 2, 1, 4], [2, 1, 1]);
|
||||
assert.deepStrictEqual(actual, [1, 2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with a single array', function() {
|
||||
var actual = func([1, 1, 3, 2, 2]);
|
||||
assert.deepStrictEqual(actual, [1, 3, 2]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with `arguments` objects', function() {
|
||||
var array = [0, 1, null, 3],
|
||||
expected = [1, 3];
|
||||
|
||||
assert.deepStrictEqual(func(array, args), expected);
|
||||
assert.deepStrictEqual(func(args, array), expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat `-0` as `0`', function() {
|
||||
var values = [-0, 0],
|
||||
expected = lodashStable.map(values, lodashStable.constant(['0']));
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
return lodashStable.map(func(values, [value]), lodashStable.toString);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should match `NaN`', function() {
|
||||
var actual = func([1, NaN, 3], [NaN, 5, NaN]);
|
||||
assert.deepStrictEqual(actual, [NaN]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays of `-0` as `0`', function() {
|
||||
var values = [-0, 0],
|
||||
expected = lodashStable.map(values, lodashStable.constant(['0']));
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(value));
|
||||
return lodashStable.map(func(values, largeArray), lodashStable.toString);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays of `NaN`', function() {
|
||||
var largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubNaN);
|
||||
assert.deepStrictEqual(func([1, NaN, 3], largeArray), [NaN]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should work with large arrays of objects', function() {
|
||||
var object = {},
|
||||
largeArray = lodashStable.times(LARGE_ARRAY_SIZE, lodashStable.constant(object));
|
||||
|
||||
assert.deepStrictEqual(func([object], largeArray), [object]);
|
||||
assert.deepStrictEqual(func(lodashStable.range(LARGE_ARRAY_SIZE), [1]), [1]);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should treat values that are not arrays or `arguments` objects as empty', function() {
|
||||
var array = [0, 1, null, 3];
|
||||
assert.deepStrictEqual(func(array, 3, { '0': 1 }, null), []);
|
||||
assert.deepStrictEqual(func(null, array, null, [2, 3]), []);
|
||||
assert.deepStrictEqual(func(array, null, args, null), []);
|
||||
});
|
||||
|
||||
it('`_.' + methodName + '` should return a wrapped value when chaining', function() {
|
||||
var wrapped = _([1, 3, 2])[methodName]([5, 2, 1, 4]);
|
||||
assert.ok(wrapped instanceof _);
|
||||
assert.deepEqual(wrapped.value(), [1, 2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
23
test/intersectionBy.js
Normal file
23
test/intersectionBy.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import assert from 'assert';
|
||||
import { slice } from './utils.js';
|
||||
import intersectionBy from '../intersectionBy.js';
|
||||
|
||||
describe('intersectionBy', function() {
|
||||
it('should accept an `iteratee`', function() {
|
||||
var actual = intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
|
||||
assert.deepStrictEqual(actual, [2.1]);
|
||||
|
||||
actual = intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
|
||||
assert.deepStrictEqual(actual, [{ 'x': 1 }]);
|
||||
});
|
||||
|
||||
it('should provide correct `iteratee` arguments', function() {
|
||||
var args;
|
||||
|
||||
intersectionBy([2.1, 1.2], [2.3, 3.4], function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(args, [2.3]);
|
||||
});
|
||||
});
|
||||
27
test/intersectionWith.test.js
Normal file
27
test/intersectionWith.test.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { LARGE_ARRAY_SIZE, stubZero } from './utils.js';
|
||||
import intersectionWith from '../intersectionWith.js';
|
||||
|
||||
describe('intersectionWith', function() {
|
||||
it('should work with a `comparator`', function() {
|
||||
var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }],
|
||||
others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }],
|
||||
actual = intersectionWith(objects, others, lodashStable.isEqual);
|
||||
|
||||
assert.deepStrictEqual(actual, [objects[0]]);
|
||||
});
|
||||
|
||||
it('should preserve the sign of `0`', function() {
|
||||
var array = [-0],
|
||||
largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubZero),
|
||||
others = [[0], largeArray],
|
||||
expected = lodashStable.map(others, lodashStable.constant(['-0']));
|
||||
|
||||
var actual = lodashStable.map(others, function(other) {
|
||||
return lodashStable.map(intersectionWith(array, other, lodashStable.eq), lodashStable.toString);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
30
test/invert.test.js
Normal file
30
test/invert.test.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import assert from 'assert';
|
||||
import invert from '../invert.js';
|
||||
|
||||
describe('invert', function() {
|
||||
it('should invert an object', function() {
|
||||
var object = { 'a': 1, 'b': 2 },
|
||||
actual = invert(object);
|
||||
|
||||
assert.deepStrictEqual(actual, { '1': 'a', '2': 'b' });
|
||||
assert.deepStrictEqual(invert(actual), { 'a': '1', 'b': '2' });
|
||||
});
|
||||
|
||||
it('should work with values that shadow keys on `Object.prototype`', function() {
|
||||
var object = { 'a': 'hasOwnProperty', 'b': 'constructor' };
|
||||
assert.deepStrictEqual(invert(object), { 'hasOwnProperty': 'a', 'constructor': 'b' });
|
||||
});
|
||||
|
||||
it('should work with an object that has a `length` property', function() {
|
||||
var object = { '0': 'a', '1': 'b', 'length': 2 };
|
||||
assert.deepStrictEqual(invert(object), { 'a': '0', 'b': '1', '2': 'length' });
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var object = { 'a': 1, 'b': 2 },
|
||||
wrapped = _(object).invert();
|
||||
|
||||
assert.ok(wrapped instanceof _);
|
||||
assert.deepEqual(wrapped.value(), { '1': 'a', '2': 'b' });
|
||||
});
|
||||
});
|
||||
42
test/invertBy.js
Normal file
42
test/invertBy.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import invertBy from '../invertBy.js';
|
||||
|
||||
describe('invertBy', function() {
|
||||
var object = { 'a': 1, 'b': 2, 'c': 1 };
|
||||
|
||||
it('should transform keys by `iteratee`', function() {
|
||||
var expected = { 'group1': ['a', 'c'], 'group2': ['b'] };
|
||||
|
||||
var actual = invertBy(object, function(value) {
|
||||
return 'group' + value;
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should use `_.identity` when `iteratee` is nullish', function() {
|
||||
var values = [, null, undefined],
|
||||
expected = lodashStable.map(values, lodashStable.constant({ '1': ['a', 'c'], '2': ['b'] }));
|
||||
|
||||
var actual = lodashStable.map(values, function(value, index) {
|
||||
return index ? invertBy(object, value) : invertBy(object);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should only add multiple values to own, not inherited, properties', function() {
|
||||
var object = { 'a': 'hasOwnProperty', 'b': 'constructor' },
|
||||
expected = { 'hasOwnProperty': ['a'], 'constructor': ['b'] };
|
||||
|
||||
assert.ok(lodashStable.isEqual(invertBy(object), expected));
|
||||
});
|
||||
|
||||
it('should return a wrapped value when chaining', function() {
|
||||
var wrapped = _(object).invertBy();
|
||||
|
||||
assert.ok(wrapped instanceof _);
|
||||
assert.deepEqual(wrapped.value(), { '1': ['a', 'c'], '2': ['b'] });
|
||||
});
|
||||
});
|
||||
71
test/invoke.js
Normal file
71
test/invoke.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import assert from 'assert';
|
||||
import lodashStable from 'lodash';
|
||||
import { noop, stubA, stubB, stubOne } from './utils.js';
|
||||
import invoke from '../invoke.js';
|
||||
|
||||
describe('invoke', function() {
|
||||
it('should invoke a method on `object`', function() {
|
||||
var object = { 'a': lodashStable.constant('A') },
|
||||
actual = invoke(object, 'a');
|
||||
|
||||
assert.strictEqual(actual, 'A');
|
||||
});
|
||||
|
||||
it('should support invoking with arguments', function() {
|
||||
var object = { 'a': function(a, b) { return [a, b]; } },
|
||||
actual = invoke(object, 'a', 1, 2);
|
||||
|
||||
assert.deepStrictEqual(actual, [1, 2]);
|
||||
});
|
||||
|
||||
it('should not error on nullish elements', function() {
|
||||
var values = [null, undefined],
|
||||
expected = lodashStable.map(values, noop);
|
||||
|
||||
var actual = lodashStable.map(values, function(value) {
|
||||
try {
|
||||
return invoke(value, 'a.b', 1, 2);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('should preserve the sign of `0`', function() {
|
||||
var object = { '-0': stubA, '0': stubB },
|
||||
props = [-0, Object(-0), 0, Object(0)];
|
||||
|
||||
var actual = lodashStable.map(props, function(key) {
|
||||
return invoke(object, key);
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(actual, ['a', 'a', 'b', 'b']);
|
||||
});
|
||||
|
||||
it('should support deep paths', function() {
|
||||
var object = { 'a': { 'b': function(a, b) { return [a, b]; } } };
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
var actual = invoke(object, path, 1, 2);
|
||||
assert.deepStrictEqual(actual, [1, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should invoke deep property methods with the correct `this` binding', function() {
|
||||
var object = { 'a': { 'b': function() { return this.c; }, 'c': 1 } };
|
||||
|
||||
lodashStable.each(['a.b', ['a', 'b']], function(path) {
|
||||
assert.deepStrictEqual(invoke(object, path), 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an unwrapped value when implicitly chaining', function() {
|
||||
var object = { 'a': stubOne };
|
||||
assert.strictEqual(_(object).invoke('a'), 1);
|
||||
});
|
||||
|
||||
it('should return a wrapped value when explicitly chaining', function() {
|
||||
var object = { 'a': stubOne };
|
||||
assert.ok(_(object).chain().invoke('a') instanceof _);
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user