wip: migrate to bun

This commit is contained in:
jdalton
2023-09-16 14:47:50 -07:00
parent 2da024c3b4
commit 97d4a2fe19
1052 changed files with 30244 additions and 26856 deletions

22
test/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,22 @@
'use strict';
const path = require('node:path');
module.exports = {
globals: {
describe: 'readonly',
expect: 'readonly',
it: 'readonly',
xdescribe: 'readonly',
xit: 'readonly'
},
overrides: [
{
files: ['**/*.{ts}'],
rules: {
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
},
},
],
};

View File

@@ -1,97 +0,0 @@
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'));
});
});

View File

@@ -0,0 +1,123 @@
import assert from 'node:assert';
import { args, toArgs, identity } from './utils';
import difference from '../src/difference';
import union from '../src/union';
import compact from '../src/compact';
import drop from '../src/drop';
import dropRight from '../src/dropRight';
import dropRightWhile from '../src/dropRightWhile';
import dropWhile from '../src/dropWhile';
import findIndex from '../src/findIndex';
import findLastIndex from '../src/findLastIndex';
import flatten from '../src/flatten';
import head from '../src/head';
import indexOf from '../src/indexOf';
import initial from '../src/initial';
import intersection from '../src/intersection';
import last from '../src/last';
import lastIndexOf from '../src/lastIndexOf';
import sortedIndex from '../src/sortedIndex';
import sortedIndexOf from '../src/sortedIndexOf';
import sortedLastIndex from '../src/sortedLastIndex';
import sortedLastIndexOf from '../src/sortedLastIndexOf';
import tail from '../src/tail';
import take from '../src/take';
import takeRight from '../src/takeRight';
import takeRightWhile from '../src/takeRightWhile';
import takeWhile from '../src/takeWhile';
import uniq from '../src/uniq';
import without from '../src/without';
import zip from '../src/zip';
import xor from '../src/xor';
describe('"Arrays" category methods', () => {
const 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 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 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 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'));
});
});

View File

@@ -0,0 +1,81 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { stubString } from './utils';
import camelCase from '../src/camelCase';
import capitalize from '../src/capitalize';
import escape from '../src/escape';
import kebabCase from '../src/kebabCase';
import lowerCase from '../src/lowerCase';
import lowerFirst from '../src/lowerFirst';
import pad from '../src/pad';
import padEnd from '../src/padEnd';
import padStart from '../src/padStart';
import repeat from '../src/repeat';
import snakeCase from '../src/snakeCase';
import trim from '../src/trim';
import trimStart from '../src/trimStart';
import trimEnd from '../src/trimEnd';
import truncate from '../src/truncate';
import unescape from '../src/unescape';
import upperCase from '../src/upperCase';
import upperFirst from '../src/upperFirst';
const methods = {
camelCase,
capitalize,
escape,
kebabCase,
lowerCase,
lowerFirst,
pad,
padEnd,
padStart,
repeat,
snakeCase,
trim,
trimStart,
trimEnd,
truncate,
unescape,
upperCase,
upperFirst,
};
describe('"Strings" category methods', () => {
const stringMethods = [
'camelCase',
'capitalize',
'escape',
'kebabCase',
'lowerCase',
'lowerFirst',
'pad',
'padEnd',
'padStart',
'repeat',
'snakeCase',
'trim',
'trimEnd',
'trimStart',
'truncate',
'unescape',
'upperCase',
'upperFirst',
];
lodashStable.each(stringMethods, (methodName) => {
const func = methods[methodName];
it(`\`_.${methodName}\` should return an empty string for empty values`, () => {
const values = [, null, undefined, ''],
expected = lodashStable.map(values, stubString);
const actual = lodashStable.map(values, (value, index) =>
index ? func(value) : func(),
);
assert.deepStrictEqual(actual, expected);
});
});
});

View File

@@ -1,83 +0,0 @@
import assert from 'assert';
import lodashStable from 'lodash';
import { stubString } from './utils.js';
import camelCase from '../camelCase.js';
import capitalize from '../capitalize.js';
import escape from '../escape.js';
import kebabCase from '../kebabCase.js';
import lowerCase from '../lowerCase.js';
import lowerFirst from '../lowerFirst.js';
import pad from '../pad.js';
import padEnd from '../padEnd.js';
import padStart from '../padStart.js';
import repeat from '../repeat.js';
import snakeCase from '../snakeCase.js';
import trim from '../trim.js';
import trimStart from '../trimStart.js';
import trimEnd from '../trimEnd.js';
import truncate from '../truncate.js';
import unescape from '../unescape.js';
import upperCase from '../upperCase.js';
import upperFirst from '../upperFirst';
const methods = {
camelCase,
capitalize,
escape,
kebabCase,
lowerCase,
lowerFirst,
pad,
padEnd,
padStart,
repeat,
snakeCase,
trim,
trimStart,
trimEnd,
truncate,
unescape,
upperCase,
upperFirst
}
describe('"Strings" category methods', function() {
var stringMethods = [
'camelCase',
'capitalize',
'escape',
'kebabCase',
'lowerCase',
'lowerFirst',
'pad',
'padEnd',
'padStart',
'repeat',
'snakeCase',
'trim',
'trimEnd',
'trimStart',
'truncate',
'unescape',
'upperCase',
'upperFirst'
];
lodashStable.each(stringMethods, function(methodName) {
var func = methods[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);
});
});
});

View File

@@ -1,87 +0,0 @@
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);
});
});

View File

@@ -0,0 +1,81 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { LARGE_ARRAY_SIZE, isEven, _, create, stubFalse, objectProto, funcProto } from './utils';
import difference from '../src/difference';
import intersection from '../src/intersection';
import uniq from '../src/uniq';
import without from '../src/without';
import groupBy from '../src/groupBy';
import merge from '../src/merge';
describe('`__proto__` property bugs', () => {
it('should work with the "__proto__" key in internal data objects', () => {
const stringLiteral = '__proto__',
stringObject = Object(stringLiteral),
expected = [stringLiteral, stringObject];
const largeArray = lodashStable.times(LARGE_ARRAY_SIZE, (count) =>
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', () => {
const methods = ['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge'];
const source = create(null);
source.__proto__ = [];
const expected = lodashStable.map(methods, stubFalse);
let actual = lodashStable.map(methods, (methodName) => {
const 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', () => {
if (JSON) {
merge({}, JSON.parse('{"__proto__":{"a":1}}'));
const actual = 'a' in objectProto;
delete objectProto.a;
assert.ok(!actual);
}
});
it('should not indirectly merge builtin prototype properties', () => {
merge({}, { toString: { constructor: { prototype: { a: 1 } } } });
let 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', () => {
merge({}, { constructor: { a: 1 } });
const actual = 'a' in Object;
delete Object.a;
assert.ok(!actual);
});
});

15
test/add.spec.ts Normal file
View File

@@ -0,0 +1,15 @@
import assert from 'node:assert';
import add from '../src/add';
describe('add', () => {
it('should add two numbers', () => {
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', () => {
assert.strictEqual(add('6', '4'), '64');
assert.strictEqual(add('x', 'y'), 'xy');
});
});

View File

@@ -1,15 +0,0 @@
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');
});
});

46
test/after.spec.ts Normal file
View File

@@ -0,0 +1,46 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import after from '../src/after';
describe('after', () => {
function testAfter(n, times) {
let count = 0;
lodashStable.times(
times,
after(n, () => {
count++;
}),
);
return count;
}
it('should create a function that invokes `func` after `n` calls', () => {
assert.strictEqual(
testAfter(5, 5),
1,
'after(n) should invoke `func` after being called `n` times',
);
assert.strictEqual(
testAfter(5, 4),
0,
'after(n) should not invoke `func` before being called `n` times',
);
assert.strictEqual(testAfter(0, 0), 0, 'after(0) should not invoke `func` immediately');
assert.strictEqual(testAfter(0, 1), 1, 'after(0) should invoke `func` when called once');
});
it('should coerce `n` values of `NaN` to `0`', () => {
assert.strictEqual(testAfter(NaN, 1), 1);
});
it('should use `this` binding of function', () => {
const afterFn = after(1, function () {
return ++this.count;
}),
object = { after: afterFn, count: 0 };
object.after();
assert.strictEqual(object.after(), 2);
assert.strictEqual(object.count, 2);
});
});

View File

@@ -1,31 +0,0 @@
import assert from 'assert';
import lodashStable from 'lodash';
import after from '../after.js';
describe('after', function() {
function testAfter(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(testAfter(5, 5), 1, 'after(n) should invoke `func` after being called `n` times');
assert.strictEqual(testAfter(5, 4), 0, 'after(n) should not invoke `func` before being called `n` times');
assert.strictEqual(testAfter(0, 0), 0, 'after(0) should not invoke `func` immediately');
assert.strictEqual(testAfter(0, 1), 1, 'after(0) should invoke `func` when called once');
});
it('should coerce `n` values of `NaN` to `0`', function() {
assert.strictEqual(testAfter(NaN, 1), 1);
});
it('should use `this` binding of function', function() {
var afterFn = after(1, function() { return ++this.count; }),
object = { 'after': afterFn, 'count': 0 };
object.after();
assert.strictEqual(object.after(), 2);
assert.strictEqual(object.count, 2);
});
});

View File

@@ -1,91 +0,0 @@
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);
});
});

89
test/ary.spec.ts Normal file
View File

@@ -0,0 +1,89 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { slice, _ } from './utils';
import ary from '../src/ary';
import curry from '../src/curry';
import rearg from '../src/rearg';
describe('ary', () => {
function fn(a, b, c) {
return slice.call(arguments);
}
it('should cap the number of arguments provided to `func`', () => {
const actual = lodashStable.map(['6', '8', '10'], ary(parseInt, 1));
assert.deepStrictEqual(actual, [6, 8, 10]);
const capped = ary(fn, 2);
assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b']);
});
it('should use `func.length` if `n` is not given', () => {
const capped = ary(fn);
assert.deepStrictEqual(capped('a', 'b', 'c', 'd'), ['a', 'b', 'c']);
});
it('should treat a negative `n` as `0`', () => {
const capped = ary(fn, -1);
try {
var actual = capped('a');
} catch (e) {}
assert.deepStrictEqual(actual, []);
});
it('should coerce `n` to an integer', () => {
const values = ['1', 1.6, 'xyz'],
expected = [['a'], ['a'], []];
const actual = lodashStable.map(values, (n) => {
const capped = ary(fn, n);
return capped('a', 'b');
});
assert.deepStrictEqual(actual, expected);
});
it('should not force a minimum argument count', () => {
const args = ['a', 'b', 'c'],
capped = ary(fn, 3);
const expected = lodashStable.map(args, (arg, index) => args.slice(0, index));
const actual = lodashStable.map(expected, (array) => capped.apply(undefined, array));
assert.deepStrictEqual(actual, expected);
});
it('should use `this` binding of function', () => {
const capped = ary(function (a, b) {
return this;
}, 1),
object = { capped: capped };
assert.strictEqual(object.capped(), object);
});
it('should use the existing `ary` if smaller', () => {
const capped = ary(ary(fn, 1), 2);
assert.deepStrictEqual(capped('a', 'b', 'c'), ['a']);
});
it('should work as an iteratee for methods like `_.map`', () => {
const 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', () => {
let 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);
});
});

View File

@@ -1,88 +0,0 @@
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' });
});
});
});

View File

@@ -0,0 +1,106 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, defineProperty, stubOne, noop, stubNaN } from './utils';
describe('assign and assignIn', () => {
lodashStable.each(['assign', 'assignIn'], (methodName) => {
const func = _[methodName];
it(`\`_.${methodName}\` should assign source properties to \`object\``, () => {
assert.deepStrictEqual(func({ a: 1 }, { b: 2 }), { a: 1, b: 2 });
});
it(`\`_.${methodName}\` should accept multiple sources`, () => {
const 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`, () => {
const 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`, () => {
const 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`, () => {
const object = {};
const descriptor = {
configurable: true,
enumerable: true,
set: function () {
throw new Error();
},
};
const 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`, () => {
const array = [1];
array[2] = 3;
assert.deepStrictEqual(func({}, array), { '0': 1, '1': undefined, '2': 3 });
});
it(`\`_.${methodName}\` should assign values of prototype objects`, () => {
function Foo() {}
Foo.prototype.a = 1;
assert.deepStrictEqual(func({}, Foo.prototype), { a: 1 });
});
it(`\`_.${methodName}\` should coerce string sources to objects`, () => {
assert.deepStrictEqual(func({}, 'a'), { '0': 'a' });
});
});
});

View File

@@ -1,9 +0,0 @@
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/assignIn.spec.ts Normal file
View File

@@ -0,0 +1,9 @@
import assert from 'node:assert';
import extend from '../src/extend';
import assignIn from '../src/assignIn';
describe('assignIn', () => {
it('should be aliased', () => {
assert.strictEqual(extend, assignIn);
});
});

View File

@@ -1,9 +0,0 @@
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);
});
});

View File

@@ -0,0 +1,9 @@
import assert from 'node:assert';
import extendWith from '../src/extendWith';
import assignInWith from '../src/assignInWith';
describe('assignInWith', () => {
it('should be aliased', () => {
assert.strictEqual(extendWith, assignInWith);
});
});

View File

@@ -1,22 +0,0 @@
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);
});
});
});

View File

@@ -0,0 +1,22 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, noop } from './utils';
describe('assignWith and assignInWith', () => {
lodashStable.each(['assignWith', 'assignInWith'], (methodName) => {
const func = _[methodName];
it(`\`_.${methodName}\` should work with a \`customizer\` callback`, () => {
const actual = func({ a: 1, b: 2 }, { a: 3, c: 3 }, (a, b) =>
a === undefined ? b : a,
);
assert.deepStrictEqual(actual, { a: 1, b: 2, c: 3 });
});
it(`\`_.${methodName}\` should work with a \`customizer\` that returns \`undefined\``, () => {
const expected = { a: 1 };
assert.deepStrictEqual(func({}, expected, noop), expected);
});
});
});

131
test/at.spec.ts Normal file
View File

@@ -0,0 +1,131 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { empties, stubOne, falsey, args, LARGE_ARRAY_SIZE, square, identity } from './utils';
import at from '../src/at';
describe('at', () => {
const array = ['a', 'b', 'c'],
object = { a: [{ b: { c: 3 } }, 4] };
it('should return the elements corresponding to the specified keys', () => {
const actual = at(array, [0, 2]);
assert.deepStrictEqual(actual, ['a', 'c']);
});
it('should return `undefined` for nonexistent keys', () => {
const actual = at(array, [2, 4, 0]);
assert.deepStrictEqual(actual, ['c', undefined, 'a']);
});
it('should work with non-index keys on array values', () => {
const values = lodashStable
.reject(empties, (value) => value === 0 || lodashStable.isArray(value))
.concat(-1, 1.1);
const array = lodashStable.transform(
values,
(result, value) => {
result[value] = 1;
},
[],
);
const expected = lodashStable.map(values, stubOne),
actual = at(array, values);
assert.deepStrictEqual(actual, expected);
});
it('should return an empty array when no keys are given', () => {
assert.deepStrictEqual(at(array), []);
assert.deepStrictEqual(at(array, [], []), []);
});
it('should accept multiple key arguments', () => {
const 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', () => {
const expected = lodashStable.map(falsey, lodashStable.constant(Array(4).fill(undefined)));
const actual = lodashStable.map(falsey, (object) => {
try {
return at(object, 0, 1, 'pop', 'push');
} catch (e) {}
});
assert.deepStrictEqual(actual, expected);
});
it('should work with an `arguments` object for `object`', () => {
const actual = at(args, [2, 0]);
assert.deepStrictEqual(actual, [3, 1]);
});
it('should work with `arguments` object as secondary arguments', () => {
const actual = at([1, 2, 3, 4, 5], args);
assert.deepStrictEqual(actual, [2, 3, 4]);
});
it('should work with an object for `object`', () => {
const actual = at(object, ['a[0].b.c', 'a[1]']);
assert.deepStrictEqual(actual, [3, 4]);
});
it('should pluck inherited property values', () => {
function Foo() {
this.a = 1;
}
Foo.prototype.b = 2;
const actual = at(new Foo(), 'b');
assert.deepStrictEqual(actual, [2]);
});
it('should work in a lazy sequence', () => {
const largeArray = lodashStable.range(LARGE_ARRAY_SIZE),
smallArray = array;
lodashStable.each([[2], ['2'], [2, 1]], (paths) => {
lodashStable.times(2, (index) => {
const array = index ? largeArray : smallArray,
wrapped = _(array).map(identity).at(paths);
assert.deepEqual(wrapped.value(), at(_.map(array, identity), paths));
});
});
});
it('should support shortcut fusion', () => {
let 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, []], (n, index) => {
count = 0;
let 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', () => {
let paths = ['a[0].b.c', 'a[1]'],
actual = _(object).map(identity).at(paths).value();
assert.deepEqual(actual, at(_.map(object, identity), paths));
const indexObject = { '0': 1 };
actual = _(indexObject).at(0).value();
assert.deepEqual(actual, at(indexObject, 0));
});
});

View File

@@ -1,124 +0,0 @@
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).fill(undefined)));
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));
});
});

73
test/attempt.spec.ts Normal file
View File

@@ -0,0 +1,73 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { slice, errors, stubTrue, CustomError, realm } from './utils';
import attempt from '../src/attempt';
describe('attempt', () => {
it('should return the result of `func`', () => {
assert.strictEqual(attempt(lodashStable.constant('x')), 'x');
});
it('should provide additional arguments to `func`', () => {
const actual = attempt(
function () {
return slice.call(arguments);
},
1,
2,
);
assert.deepStrictEqual(actual, [1, 2]);
});
it('should return the caught error', () => {
const expected = lodashStable.map(errors, stubTrue);
const actual = lodashStable.map(
errors,
(error) =>
attempt(() => {
throw error;
}) === error,
);
assert.deepStrictEqual(actual, expected);
});
it('should coerce errors to error objects', () => {
const actual = attempt(() => {
throw 'x';
});
assert.ok(lodashStable.isEqual(actual, Error('x')));
});
it('should preserve custom errors', () => {
const actual = attempt(() => {
throw new CustomError('x');
});
assert.ok(actual instanceof CustomError);
});
it('should work with an error object from another realm', () => {
if (realm.errors) {
const expected = lodashStable.map(realm.errors, stubTrue);
const actual = lodashStable.map(
realm.errors,
(error) =>
attempt(() => {
throw error;
}) === error,
);
assert.deepStrictEqual(actual, expected);
}
});
it('should return an unwrapped value when implicitly chaining', () => {
assert.strictEqual(_(lodashStable.constant('x')).attempt(), 'x');
});
it('should return a wrapped value when explicitly chaining', () => {
assert.ok(_(lodashStable.constant('x')).chain().attempt() instanceof _);
});
});

View File

@@ -1,55 +0,0 @@
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 _);
});
});

View File

@@ -1,151 +0,0 @@
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);
}
});
});

147
test/basename.spec.ts Normal file
View File

@@ -0,0 +1,147 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import {
basename,
amd,
ui,
Worker,
QUnit,
lodashBizarro,
LARGE_ARRAY_SIZE,
symbol,
setProperty,
} from './utils';
import _VERSION from '../.internal/VERSION';
import VERSION from '../src/VERSION';
describe(basename, () => {
it(`should support loading ${basename} as the "lodash" module`, () => {
if (amd) {
assert.strictEqual((lodashModule || {}).moduleName, 'lodash');
}
});
it(`should support loading ${basename} with the Require.js "shim" configuration option`, () => {
if (amd && lodashStable.includes(ui.loaderPath, 'requirejs')) {
assert.strictEqual((shimmedModule || {}).moduleName, 'shimmed');
}
});
it(`should support loading ${basename} as the "underscore" module`, () => {
if (amd) {
assert.strictEqual((underscoreModule || {}).moduleName, 'underscore');
}
});
it(`should support loading ${basename} in a web worker`, (done) => {
if (Worker) {
const limit = 30000 / QUnit.config.asyncRetries,
start = +new Date();
const attempt = function () {
const 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', () => {
if (lodashBizarro) {
assert.ok(!('_method' in lodashBizarro));
}
});
it('should avoid non-native built-ins', () => {
function message(lodashMethod, nativeMethod) {
return `\`${lodashMethod}\` should avoid overwritten native \`${nativeMethod}\``;
}
function Foo() {
this.a = 1;
}
Foo.prototype.b = 2;
const 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;
}
let 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.
const 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);
}
});
});

View File

@@ -1,31 +0,0 @@
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);
});
});

46
test/before.spec.ts Normal file
View File

@@ -0,0 +1,46 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _ } from './utils';
describe('before', () => {
function before(n, times) {
let count = 0;
lodashStable.times(
times,
_.before(n, () => {
count++;
}),
);
return count;
}
it('should create a function that invokes `func` after `n` calls', () => {
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`', () => {
assert.strictEqual(before(NaN, 1), 0);
});
it('should use `this` binding of function', () => {
const before = _.before(2, function () {
return ++this.count;
}),
object = { before: before, count: 0 };
object.before();
assert.strictEqual(object.before(), 1);
assert.strictEqual(object.count, 1);
});
});

View File

@@ -1,231 +0,0 @@
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']);
});
});

256
test/bind.spec.ts Normal file
View File

@@ -0,0 +1,256 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { push, falsey, stubTrue } from './utils';
import bind from '../src/bind';
import placeholder from '../src/placeholder';
describe('bind', () => {
function fn() {
const result = [this];
push.apply(result, arguments);
return result;
}
it('should bind a function to an object', () => {
const object = {},
bound = bind(fn, object);
assert.deepStrictEqual(bound('a'), [object, 'a']);
});
it('should accept a falsey `thisArg`', () => {
const values = lodashStable.reject(falsey.slice(1), (value) => value == null),
expected = lodashStable.map(values, (value) => [value]);
const actual = lodashStable.map(values, (value) => {
try {
const bound = bind(fn, value);
return bound();
} catch (e) {}
});
assert.ok(
lodashStable.every(actual, (value, index) =>
lodashStable.isEqual(value, expected[index]),
),
);
});
it('should bind a function to nullish values', () => {
let 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, (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 ', () => {
let 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', () => {
const 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', () => {
const _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`', () => {
let 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 Foo() {
return this;
}
const 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 Foo() {
return this;
}
function Bar() {}
const thisArg = { a: 1 },
boundFoo = bind(Foo, thisArg),
boundBar = bind(Bar, thisArg),
count = 9,
expected = lodashStable.times(count, lodashStable.constant([undefined, undefined]));
const actual = lodashStable.times(count, (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 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', () => {
const object = {},
bound = bind(fn, object, 'a');
assert.deepStrictEqual(bound(['b'], 'c'), [object, 'a', ['b'], 'c']);
});
it('should not rebind functions', () => {
const object1 = {},
object2 = {},
object3 = {};
const 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', () => {
let 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', () => {
const createCtor = lodashStable.attempt(Function, '"use strict";return class A{}');
if (typeof createCtor === 'function') {
const bound = bind(createCtor()),
count = 8,
expected = lodashStable.times(count, stubTrue);
const actual = lodashStable.times(count, (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', () => {
const object = {},
bound = _(fn).bind({}, 'a', 'b');
assert.ok(bound instanceof _);
const actual = bound.value()('c');
assert.deepEqual(actual, [object, 'a', 'b', 'c']);
});
});

View File

@@ -1,74 +0,0 @@
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]);
});
});

80
test/bindAll.spec.ts Normal file
View File

@@ -0,0 +1,80 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { args, toArgs, arrayProto } from './utils';
import bindAll from '../src/bindAll';
describe('bindAll', () => {
const args = toArgs(['a']);
const 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', () => {
const object = lodashStable.cloneDeep(source);
bindAll(object, 'a', 'b');
const actual = lodashStable.map(['a', 'b', 'c'], (key) => object[key].call({}));
assert.deepStrictEqual(actual, [1, 2, undefined]);
});
it('should accept arrays of method names', () => {
const object = lodashStable.cloneDeep(source);
bindAll(object, ['a', 'b'], ['c']);
const actual = lodashStable.map(['a', 'b', 'c', 'd'], (key) => object[key].call({}));
assert.deepStrictEqual(actual, [1, 2, 3, undefined]);
});
it('should preserve the sign of `0`', () => {
const props = [-0, Object(-0), 0, Object(0)];
const actual = lodashStable.map(props, (key) => {
const 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`', () => {
const array = ['push', 'pop'];
bindAll(array);
assert.strictEqual(array.pop, arrayProto.pop);
});
it('should work with `arguments` objects as secondary arguments', () => {
const object = lodashStable.cloneDeep(source);
bindAll(object, args);
const actual = lodashStable.map(args, (key) => object[key].call({}));
assert.deepStrictEqual(actual, [1]);
});
});

View File

@@ -1,66 +0,0 @@
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);
});
});

66
test/bindKey.spec.ts Normal file
View File

@@ -0,0 +1,66 @@
import assert from 'node:assert';
import { slice } from './utils';
import bindKey from '../src/bindKey';
describe('bindKey', () => {
it('should work when the target function is overwritten', () => {
const object = {
user: 'fred',
greet: function (greeting) {
return `${this.user} says: ${greeting}`;
},
};
const 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', () => {
const object = {
fn: function () {
return slice.call(arguments);
},
};
const 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', () => {
const object = {
fn: function () {
return slice.call(arguments);
},
};
const _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 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.spec.ts Normal file
View File

@@ -0,0 +1,28 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import camelCase from '../src/camelCase';
describe('camelCase', () => {
it('should work with numbers', () => {
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', () => {
lodashStable.each(['safe HTML', 'safeHTML'], (string) => {
assert.strictEqual(camelCase(string), 'safeHtml');
});
lodashStable.each(['escape HTML entities', 'escapeHTMLEntities'], (string) => {
assert.strictEqual(camelCase(string), 'escapeHtmlEntities');
});
lodashStable.each(['XMLHttpRequest', 'XmlHTTPRequest'], (string) => {
assert.strictEqual(camelCase(string), 'xmlHttpRequest');
});
});
});

View File

@@ -1,28 +0,0 @@
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.spec.ts Normal file
View File

@@ -0,0 +1,10 @@
import assert from 'node:assert';
import capitalize from '../src/capitalize';
describe('capitalize', () => {
it('should capitalize the first character of a string', () => {
assert.strictEqual(capitalize('fred'), 'Fred');
assert.strictEqual(capitalize('Fred'), 'Fred');
assert.strictEqual(capitalize(' fred'), ' fred');
});
});

View File

@@ -1,10 +0,0 @@
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');
});
});

133
test/case-methods.spec.ts Normal file
View File

@@ -0,0 +1,133 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { stubTrue, burredLetters, deburredLetters } from './utils';
import camelCase from '../src/camelCase';
import kebabCase from '../src/kebabCase';
import lowerCase from '../src/lowerCase';
import snakeCase from '../src/snakeCase';
import startCase from '../src/startCase';
import upperCase from '../src/upperCase';
const caseMethods = {
camelCase,
kebabCase,
lowerCase,
snakeCase,
startCase,
upperCase,
};
describe('case methods', () => {
lodashStable.each(['camel', 'kebab', 'lower', 'snake', 'start', 'upper'], (caseName) => {
const methodName = `${caseName}Case`,
func = caseMethods[methodName];
const strings = [
'foo bar',
'Foo bar',
'foo Bar',
'Foo Bar',
'FOO BAR',
'fooBar',
'--foo-bar--',
'__foo_bar__',
];
const 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`, () => {
const actual = lodashStable.map(strings, (string) => {
const 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`, () => {
const actual = lodashStable.map(strings, (string) => {
const expected = caseName == 'start' && string == 'FOO BAR' ? string : converted;
return func(func(string)) === expected;
});
assert.deepStrictEqual(actual, lodashStable.map(strings, stubTrue));
});
it(`\`_.${methodName}\` should remove contraction apostrophes`, () => {
const postfixes = ['d', 'll', 'm', 're', 's', 't', 've'];
lodashStable.each(["'", '\u2019'], (apos) => {
const actual = lodashStable.map(postfixes, (postfix) =>
func(`a b${apos}${postfix} c`),
);
const expected = lodashStable.map(postfixes, (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`, () => {
const actual = lodashStable.map(['\xd7', '\xf7'], func);
assert.deepStrictEqual(actual, ['', '']);
});
it(`\`_.${methodName}\` should coerce \`string\` to a string`, () => {
const string = 'foo bar';
assert.strictEqual(func(Object(string)), converted);
assert.strictEqual(func({ toString: lodashStable.constant(string) }), converted);
});
});
(function () {
it('should get the original value after cycling through all case methods', () => {
const funcs = [
camelCase,
kebabCase,
lowerCase,
snakeCase,
startCase,
lowerCase,
camelCase,
];
const actual = lodashStable.reduce(
funcs,
(result, func) => func(result),
'enable 6h format',
);
assert.strictEqual(actual, 'enable6HFormat');
});
})();
});

View File

@@ -1,105 +0,0 @@
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';
import upperCase from '../upperCase.js';
const caseMethods = {
camelCase,
kebabCase,
lowerCase,
snakeCase,
startCase,
upperCase
};
describe('case methods', function() {
lodashStable.each(['camel', 'kebab', 'lower', 'snake', 'start', 'upper'], function(caseName) {
var methodName = caseName + 'Case',
func = caseMethods[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 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);
});
});
(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.spec.ts Normal file
View File

@@ -0,0 +1,23 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { falsey } from './utils';
import castArray from '../src/castArray';
describe('castArray', () => {
it('should wrap non-array items in an array', () => {
const values = falsey.concat(true, 1, 'a', { a: 1 }),
expected = lodashStable.map(values, (value) => [value]),
actual = lodashStable.map(values, castArray);
assert.deepStrictEqual(actual, expected);
});
it('should return array values by reference', () => {
const array = [1];
assert.strictEqual(castArray(array), array);
});
it('should return an empty array when no arguments are given', () => {
assert.deepStrictEqual(castArray(), []);
});
});

View File

@@ -1,23 +0,0 @@
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(), []);
});
});

View File

@@ -1,74 +0,0 @@
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]);
});
});
});

93
test/chain.spec.ts Normal file
View File

@@ -0,0 +1,93 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { square } from './utils';
import chain from '../src/chain';
describe('chain', () => {
it('should return a wrapped value', () => {
const actual = chain({ a: 0 });
assert.ok(actual instanceof _);
});
it('should return existing wrapped values', () => {
const wrapped = _({ a: 0 });
assert.strictEqual(chain(wrapped), wrapped);
assert.strictEqual(wrapped.chain(), wrapped);
});
it('should enable chaining for methods that return unwrapped values', () => {
const 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', () => {
lodashStable.times(2, (index) => {
let 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);
let actual = wrapped
.chain()
.map((value) => value.split(''))
.flatten()
.reduce((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((n) => n % 2 != 0)
.reject((n) => n % 3 == 0)
.sortBy((n) => -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((value) => {
value.pop();
})
.map(square)
.value();
assert.deepStrictEqual(actual, [25, 16, 9, 4]);
});
});
});

49
test/chunk.spec.ts Normal file
View File

@@ -0,0 +1,49 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { falsey, stubArray } from './utils';
import chunk from '../src/chunk';
describe('chunk', () => {
const array = [0, 1, 2, 3, 4, 5];
it('should return chunked arrays', () => {
const actual = chunk(array, 3);
assert.deepStrictEqual(actual, [
[0, 1, 2],
[3, 4, 5],
]);
});
it('should return the last chunk as remaining elements', () => {
const actual = chunk(array, 4);
assert.deepStrictEqual(actual, [
[0, 1, 2, 3],
[4, 5],
]);
});
it('should treat falsey `size` values, except `undefined`, as `0`', () => {
const expected = lodashStable.map(falsey, (value) =>
value === undefined ? [[0], [1], [2], [3], [4], [5]] : [],
);
const actual = lodashStable.map(falsey, (size, index) =>
index ? chunk(array, size) : chunk(array),
);
assert.deepStrictEqual(actual, expected);
});
it('should ensure the minimum `size` is `0`', () => {
const values = lodashStable.reject(falsey, lodashStable.isUndefined).concat(-1, -Infinity),
expected = lodashStable.map(values, stubArray);
const actual = lodashStable.map(values, (n) => chunk(array, n));
assert.deepStrictEqual(actual, expected);
});
it('should coerce `size` to an integer', () => {
assert.deepStrictEqual(chunk(array, array.length / 4), [[0], [1], [2], [3], [4], [5]]);
});
});

View File

@@ -1,45 +0,0 @@
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]]);
});
});

View File

@@ -1,58 +0,0 @@
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);
});
});

58
test/clamp.spec.ts Normal file
View File

@@ -0,0 +1,58 @@
import assert from 'node:assert';
import clamp from '../src/clamp';
describe('clamp', () => {
it('should work with a `max`', () => {
assert.strictEqual(clamp(5, 3), 3);
assert.strictEqual(clamp(1, 3), 1);
});
it('should clamp negative numbers', () => {
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', () => {
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', () => {
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', () => {
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', () => {
assert.strictEqual(1 / clamp(0, -5, 5), Infinity);
});
it('should clamp to `0`', () => {
assert.strictEqual(1 / clamp(-10, 0, 5), Infinity);
});
it('should not alter `-0` in range', () => {
assert.strictEqual(1 / clamp(-0, -5, 5), -Infinity);
});
it('should clamp to `-0`', () => {
assert.strictEqual(1 / clamp(-10, -0, 5), -Infinity);
});
it('should return `NaN` when `number` is `NaN`', () => {
assert.deepStrictEqual(clamp(NaN, -5, 5), NaN);
});
it('should coerce `min` and `max` of `NaN` to `0`', () => {
assert.deepStrictEqual(clamp(1, -5, NaN), 0);
assert.deepStrictEqual(clamp(-1, NaN, 5), 0);
});
});

View File

@@ -1,429 +0,0 @@
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);
});
});
});
});

446
test/clone-methods.spec.ts Normal file
View File

@@ -0,0 +1,446 @@
import assert from 'node: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';
import cloneDeep from '../src/cloneDeep';
import cloneDeepWith from '../src/cloneDeepWith';
import last from '../src/last';
xdescribe('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);
}
const 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;
const uncloneable = {
'DOM elements': body,
functions: Foo,
'async functions': asyncFunc,
'generator functions': genFunc,
'the `Proxy` constructor': Proxy,
};
lodashStable.each(errors, (error) => {
uncloneable[`${error.name}s`] = error;
});
it('`_.clone` should perform a shallow clone', () => {
const 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', () => {
const object = {
foo: { b: { c: { d: {} } } },
bar: {},
};
object.foo.b.c.d = object;
object.bar.b = object.foo.b;
const 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', () => {
const cyclical = {};
lodashStable.times(LARGE_ARRAY_SIZE + 1, (index) => {
cyclical[`v${index}`] = [index ? cyclical[`v${index - 1}`] : cyclical];
});
const 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`', () => {
let actual;
cloneDeepWith({ a: 1 }, function () {
actual = last(arguments);
});
assert.ok(isNpm ? actual.constructor.name == 'Stack' : actual instanceof mapCaches.Stack);
});
lodashStable.each(['clone', 'cloneDeep'], (methodName) => {
const func = _[methodName],
isDeep = methodName == 'cloneDeep';
lodashStable.forOwn(objects, (object, kind) => {
it(`\`_.${methodName}\` should clone ${kind}`, () => {
const 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`, () => {
if (ArrayBuffer) {
const actual = func(arrayBuffer);
assert.strictEqual(actual.byteLength, arrayBuffer.byteLength);
assert.notStrictEqual(actual, arrayBuffer);
}
});
it(`\`_.${methodName}\` should clone buffers`, () => {
if (Buffer) {
const 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`, () => {
const array = /c/.exec('abcde'),
actual = func(array);
assert.strictEqual(actual.index, 2);
assert.strictEqual(actual.input, 'abcde');
});
it(`\`_.${methodName}\` should clone \`lastIndex\` regexp property`, () => {
const regexp = /c/g;
regexp.exec('abcde');
assert.strictEqual(func(regexp).lastIndex, 3);
});
it(`\`_.${methodName}\` should clone expando properties`, () => {
const values = lodashStable.map([false, true, 1, 'a'], (value) => {
const object = Object(value);
object.a = 1;
return object;
});
const expected = lodashStable.map(values, stubTrue);
const actual = lodashStable.map(values, (value) => func(value).a === 1);
assert.deepStrictEqual(actual, expected);
});
it(`\`_.${methodName}\` should clone prototype objects`, () => {
const actual = func(Foo.prototype);
assert.ok(!(actual instanceof Foo));
assert.deepStrictEqual(actual, { b: 1 });
});
it(`\`_.${methodName}\` should set the \`[[Prototype]]\` of a clone`, () => {
assert.ok(func(new Foo()) instanceof Foo);
});
it(`\`_.${methodName}\` should set the \`[[Prototype]]\` of a clone even when the \`constructor\` is incorrect`, () => {
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]]\``, () => {
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\``, () => {
const object = {
constructor: objectProto.constructor,
hasOwnProperty: objectProto.hasOwnProperty,
isPrototypeOf: objectProto.isPrototypeOf,
propertyIsEnumerable: objectProto.propertyIsEnumerable,
toLocaleString: objectProto.toLocaleString,
toString: objectProto.toString,
valueOf: objectProto.valueOf,
};
const actual = func(object);
assert.deepStrictEqual(actual, object);
assert.notStrictEqual(actual, object);
});
it(`\`_.${methodName}\` should clone symbol properties`, () => {
function Foo() {
this[symbol] = { c: 1 };
}
if (Symbol) {
const symbol2 = Symbol('b');
Foo.prototype[symbol2] = 2;
const symbol3 = Symbol('c');
defineProperty(Foo.prototype, symbol3, {
configurable: true,
enumerable: false,
writable: true,
value: 3,
});
const object = { a: { b: new Foo() } };
object[symbol] = { b: 1 };
const 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`, () => {
if (Symbol) {
assert.strictEqual(func(symbol), symbol);
const 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`, () => {
if (Symbol) {
assert.strictEqual(func(symbol), symbol);
}
});
it(`\`_.${methodName}\` should not error on DOM elements`, () => {
if (document) {
const 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\``, () => {
const props = [];
const objects = lodashStable.transform(
_,
(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);
}
},
[],
);
const expected = lodashStable.map(objects, stubTrue);
const actual = lodashStable.map(objects, (object) => {
const 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\``, () => {
const 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`, () => {
const object = objects.objects,
actual = _(object)[methodName]();
assert.deepEqual(actual, object);
assert.notStrictEqual(actual, object);
});
lodashStable.each(arrayViews, (type) => {
it(`\`_.${methodName}\` should clone ${type} values`, () => {
const Ctor = root[type];
lodashStable.times(2, (index) => {
if (Ctor) {
const 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, (value, key) => {
it(`\`_.${methodName}\` should not clone ${key}`, () => {
if (value) {
const 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'], (methodName) => {
const func = _[methodName],
isDeep = methodName == 'cloneDeepWith';
it(`\`_.${methodName}\` should provide correct \`customizer\` arguments`, () => {
const argsList = [],
object = new Foo();
func(object, function () {
const 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\``, () => {
const actual = func({ a: { b: 'c' } }, noop);
assert.deepStrictEqual(actual, { a: { b: 'c' } });
});
lodashStable.forOwn(uncloneable, (value, key) => {
it(`\`_.${methodName}\` should work with a \`customizer\` callback and ${key}`, () => {
const customizer = function (value) {
return lodashStable.isPlainObject(value) ? undefined : value;
};
let actual = func(value, customizer);
assert.strictEqual(actual, value);
const object = { a: value, b: { c: value } };
actual = func(object, customizer);
assert.deepStrictEqual(actual, object);
assert.notStrictEqual(actual, object);
});
});
});
});

View File

@@ -1,42 +0,0 @@
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;
});
});

44
test/compact.spec.ts Normal file
View File

@@ -0,0 +1,44 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { LARGE_ARRAY_SIZE, _, falsey } from './utils';
import compact from '../src/compact';
import slice from '../src/slice';
describe('compact', () => {
const largeArray = lodashStable.range(LARGE_ARRAY_SIZE).concat(null);
it('should filter falsey values', () => {
const array = ['0', '1', '2'];
assert.deepStrictEqual(compact(falsey.concat(array)), array);
});
it('should work when in-between lazy operators', () => {
let 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', () => {
const 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`', () => {
let iteratee = _.iteratee,
pass = false;
_.iteratee = identity;
try {
const actual = _(largeArray).slice(1).compact().value();
pass = lodashStable.isEqual(actual, compact(slice(largeArray, 1)));
} catch (e) {
console.log(e);
}
assert.ok(pass);
_.iteratee = iteratee;
});
});

View File

@@ -1,65 +0,0 @@
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]);
});
});

57
test/concat.spec.ts Normal file
View File

@@ -0,0 +1,57 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import concat from '../src/concat';
describe('concat', () => {
it('should shallow clone `array`', () => {
const array = [1, 2, 3],
actual = concat(array);
assert.deepStrictEqual(actual, array);
assert.notStrictEqual(actual, array);
});
it('should concat arrays and values', () => {
const 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', () => {
const values = [, null, undefined, false, true, 1, NaN, 'a'];
let expected = lodashStable.map(values, (value, index) => (index ? [value] : []));
let actual = lodashStable.map(values, (value, index) => (index ? concat(value) : concat()));
assert.deepStrictEqual(actual, expected);
expected = lodashStable.map(values, (value) => [value, 2, [3]]);
actual = lodashStable.map(values, (value) => concat(value, [2], [[3]]));
assert.deepStrictEqual(actual, expected);
});
it('should treat sparse arrays as dense', () => {
const 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', () => {
const array = [1],
wrapped = _(array).concat([2, 3]),
actual = wrapped.value();
assert.deepEqual(array, [1]);
assert.deepEqual(actual, [1, 2, 3]);
});
});

View File

@@ -1,65 +0,0 @@
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);
});
});

81
test/cond.spec.ts Normal file
View File

@@ -0,0 +1,81 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, stubA, stubB, stubC, slice, stubFalse, stubTrue } from './utils';
describe('cond', () => {
it('should create a conditional function', () => {
const 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', () => {
let args1,
args2,
expected = ['a', 'b', 'c'];
const 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', () => {
const 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', () => {
const cond = _.cond([[stubFalse, stubA]]);
assert.strictEqual(cond({ a: 1 }), undefined);
});
it('should throw a TypeError if `pairs` is not composed of functions', () => {
lodashStable.each([false, true], (value) => {
assert.throws(() => {
_.cond([[stubTrue, value]])();
}, TypeError);
});
});
it('should use `this` binding of function for `pairs`', () => {
const cond = _.cond([
[
function (a) {
return this[a];
},
function (a, b) {
return this[b];
},
],
]);
const object = { cond: cond, a: 1, b: 2 };
assert.strictEqual(object.cond('a', 'b'), 2);
});
});

View File

@@ -1,153 +0,0 @@
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);
});
});
});

View File

@@ -0,0 +1,172 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, stubFalse, stubTrue, empties } from './utils';
import conformsTo from '../src/conformsTo';
describe('conforms methods', () => {
lodashStable.each(['conforms', 'conformsTo'], (methodName) => {
const 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\``, () => {
const objects = [
{ a: 1, b: 8 },
{ a: 2, b: 4 },
{ a: 3, b: 16 },
];
let par = conforms({
b: function (value) {
return value > 4;
},
});
let 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 Foo() {
this.a = function (value) {
return value > 1;
};
}
Foo.prototype.b = function (value) {
return value > 8;
};
const objects = [
{ a: 1, b: 8 },
{ a: 2, b: 4 },
{ a: 3, b: 16 },
];
const 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`, () => {
let count = 0;
const 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 Foo() {}
Foo.a = 1;
function Bar() {}
Bar.a = 2;
const 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 Foo() {}
Foo.a = function (value) {
return value > 1;
};
const 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 Foo() {
this.a = 1;
}
Foo.prototype.b = 2;
const par = conforms({
b: function (value) {
return value > 1;
},
});
assert.strictEqual(par(new Foo()), true);
});
it(`\`_.${methodName}\` should return \`false\` when \`object\` is nullish`, () => {
const values = [, null, undefined],
expected = lodashStable.map(values, stubFalse);
const par = conforms({
a: function (value) {
return value > 1;
},
});
const actual = lodashStable.map(values, (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\``, () => {
const values = [, null, undefined],
expected = lodashStable.map(values, stubTrue),
par = conforms({});
const actual = lodashStable.map(values, (value, index) => {
try {
return index ? par(value) : par();
} catch (e) {}
});
assert.deepStrictEqual(actual, expected);
});
it(`\`_.${methodName}\` should return \`true\` when comparing an empty \`source\``, () => {
const object = { a: 1 },
expected = lodashStable.map(empties, stubTrue);
const actual = lodashStable.map(empties, (value) => {
const par = conforms(value);
return par(object);
});
assert.deepStrictEqual(actual, expected);
});
});
});

View File

@@ -1,15 +0,0 @@
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);
});
});

21
test/conforms.spec.ts Normal file
View File

@@ -0,0 +1,21 @@
import assert from 'node:assert';
import conforms from '../src/conforms';
describe('conforms', () => {
it('should not change behavior if `source` is modified', () => {
const 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);
});
});

View File

@@ -1,40 +0,0 @@
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 _);
});
});

38
test/constant.spec.ts Normal file
View File

@@ -0,0 +1,38 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { empties, _, falsey, stubTrue } from './utils';
describe('constant', () => {
it('should create a function that returns `value`', () => {
const object = { a: 1 },
values = Array(2).concat(empties, true, 1, 'a'),
constant = _.constant(object);
const results = lodashStable.map(values, (value, index) => {
if (index < 2) {
return index ? constant.call({}) : constant();
}
return constant(value);
});
assert.ok(lodashStable.every(results, (result) => result === object));
});
it('should work with falsey values', () => {
const expected = lodashStable.map(falsey, stubTrue);
const actual = lodashStable.map(falsey, (value, index) => {
const 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', () => {
const wrapped = _(true).constant();
assert.ok(wrapped instanceof _);
});
});

View File

@@ -1,66 +0,0 @@
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)));
});
});

68
test/countBy.spec.ts Normal file
View File

@@ -0,0 +1,68 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { LARGE_ARRAY_SIZE } from './utils';
import countBy from '../src/countBy';
describe('countBy', () => {
const array = [6.1, 4.2, 6.3];
it('should transform keys by `iteratee`', () => {
const actual = countBy(array, Math.floor);
assert.deepStrictEqual(actual, { '4': 1, '6': 2 });
});
it('should use `_.identity` when `iteratee` is nullish', () => {
const array = [4, 6, 6],
values = [, null, undefined],
expected = lodashStable.map(values, lodashStable.constant({ '4': 1, '6': 2 }));
const actual = lodashStable.map(values, (value, index) =>
index ? countBy(array, value) : countBy(array),
);
assert.deepStrictEqual(actual, expected);
});
it('should work with `_.property` shorthands', () => {
const actual = countBy(['one', 'two', 'three'], 'length');
assert.deepStrictEqual(actual, { '3': 2, '5': 1 });
});
it('should only add values to own, not inherited, properties', () => {
const actual = countBy(array, (n) =>
Math.floor(n) > 4 ? 'hasOwnProperty' : 'constructor',
);
assert.deepStrictEqual(actual.constructor, 1);
assert.deepStrictEqual(actual.hasOwnProperty, 2);
});
it('should work with a number for `iteratee`', () => {
const 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`', () => {
const 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', () => {
const 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),
);
const actual = _(array).countBy().map(square).filter(isEven).take().value();
assert.deepEqual(actual, _.take(_.filter(_.map(countBy(array), square), isEven)));
});
});

100
test/create.spec.ts Normal file
View File

@@ -0,0 +1,100 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { falsey, primitives, stubTrue } from './utils';
import create from '../src/create';
import keys from '../src/keys';
describe('create', () => {
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', () => {
Circle.prototype = create(Shape.prototype);
Circle.prototype.constructor = Circle;
const 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', () => {
const expected = { constructor: Circle, radius: 0 };
const properties = Object.keys(expected);
Circle.prototype = create(Shape.prototype, expected);
const actual = new Circle();
assert.ok(actual instanceof Circle);
assert.ok(actual instanceof Shape);
assert.deepStrictEqual(Object.keys(Circle.prototype), properties);
properties.forEach((property) => {
assert.strictEqual(Circle.prototype[property], expected[property]);
});
});
it('should assign own properties', () => {
function Foo() {
this.a = 1;
this.c = 3;
}
Foo.prototype.b = 2;
const actual = create({}, new Foo());
const expected = { a: 1, c: 3 };
const properties = Object.keys(expected);
assert.deepStrictEqual(Object.keys(actual), properties);
properties.forEach((property) => {
assert.strictEqual(actual[property], expected[property]);
});
});
it('should assign properties that shadow those of `prototype`', () => {
function Foo() {
this.a = 1;
}
const object = create(new Foo(), { a: 1 });
assert.deepStrictEqual(lodashStable.keys(object), ['a']);
});
it('should accept a falsey `prototype`', () => {
const actual = lodashStable.map(falsey, (prototype, index) =>
index ? create(prototype) : create(),
);
actual.forEach((value) => {
assert.ok(lodashStable.isObject(value));
});
});
it('should accept a primitive `prototype`', () => {
const actual = lodashStable.map(primitives, (value, index) =>
index ? create(value) : create(),
);
actual.forEach((value) => {
assert.ok(lodashStable.isObject(value));
});
});
it('should work as an iteratee for methods like `_.map`', () => {
const array = [{ a: 1 }, { a: 1 }, { a: 1 }],
expected = lodashStable.map(array, stubTrue),
objects = lodashStable.map(array, create);
const actual = lodashStable.map(
objects,
(object) => object.a === 1 && !keys(object).length,
);
assert.deepStrictEqual(actual, expected);
});
});

View File

@@ -1,99 +0,0 @@
import assert from 'assert';
import lodashStable from 'lodash';
import { falsey, 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 };
var properties = Object.keys(expected);
Circle.prototype = create(Shape.prototype, expected);
var actual = new Circle;
assert.ok(actual instanceof Circle);
assert.ok(actual instanceof Shape);
assert.deepStrictEqual(Object.keys(Circle.prototype), properties);
properties.forEach((property) => {
assert.strictEqual(Circle.prototype[property], expected[property]);
});
});
it('should assign own properties', function() {
function Foo() {
this.a = 1;
this.c = 3;
}
Foo.prototype.b = 2;
var actual = create({}, new Foo);
var expected = { 'a': 1, 'c': 3 };
var properties = Object.keys(expected);
assert.deepStrictEqual(Object.keys(actual), properties);
properties.forEach((property) => {
assert.strictEqual(actual[property], expected[property]);
});
});
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 actual = lodashStable.map(falsey, function(prototype, index) {
return index ? create(prototype) : create();
});
actual.forEach((value) => {
assert.ok(lodashStable.isObject(value));
});
});
it('should accept a primitive `prototype`', function() {
var actual = lodashStable.map(primitives, function(value, index) {
return index ? create(value) : create();
});
actual.forEach((value) => {
assert.ok(lodashStable.isObject(value));
});
});
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);
});
});

View File

@@ -1,52 +0,0 @@
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);
});
});
});
});

View File

@@ -0,0 +1,53 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, slice } from './utils';
import curry from '../src/curry';
describe('curry methods', () => {
lodashStable.each(['curry', 'curryRight'], (methodName) => {
const 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 run(a, b) {
return a + b;
}
const 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\``, () => {
const curried = curry((a, b, c) => [a, b, c]);
const expected = [1, 2, 3];
assert.deepStrictEqual(curried(1)(2)(3), expected);
});
it(`\`_.${methodName}\` should work as an iteratee for methods like \`_.map\``, () => {
const array = [fn, fn, fn],
object = { a: fn, b: fn, c: fn };
lodashStable.each([array, object], (collection) => {
const curries = lodashStable.map(collection, func),
expected = lodashStable.map(
collection,
lodashStable.constant(isCurry ? ['a', 'b'] : ['b', 'a']),
);
const actual = lodashStable.map(curries, (curried) => curried('a')('b'));
assert.deepStrictEqual(actual, expected);
});
});
});
});

View File

@@ -1,135 +0,0 @@
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);
});
});

133
test/curry.spec.ts Normal file
View File

@@ -0,0 +1,133 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { slice, stubArray } from './utils';
import curry from '../src/curry';
import placeholder from '../src/placeholder';
import bind from '../src/bind';
import partial from '../src/partial';
import partialRight from '../src/partialRight';
describe('curry', () => {
function fn(a, b, c, d) {
return slice.call(arguments);
}
it('should curry based on the number of arguments given', () => {
const 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`', () => {
const 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', () => {
const values = ['0', 0.6, 'xyz'],
expected = lodashStable.map(values, stubArray);
const actual = lodashStable.map(values, (arity) => curry(fn, arity)());
assert.deepStrictEqual(actual, expected);
assert.deepStrictEqual(curry(fn, '2')(1)(2), [1, 2]);
});
it('should support placeholders', () => {
const 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', () => {
const 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', () => {
const 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', () => {
const 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`', () => {
lodashStable.times(2, (index) => {
const 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 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', () => {
const fn = function (a, b, c) {
const value = this || {};
return [value[a], value[b], value[c]];
};
const 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', () => {
const curried = curry(fn),
expected = [1, 2, 3, 4];
const 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);
});
});

View File

@@ -1,136 +0,0 @@
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);
});
});

134
test/curryRight.spec.ts Normal file
View File

@@ -0,0 +1,134 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { slice, stubArray } from './utils';
import curryRight from '../src/curryRight';
import placeholder from '../src/placeholder';
import bind from '../src/bind';
import partialRight from '../src/partialRight';
import partial from '../src/partial';
describe('curryRight', () => {
function fn(a, b, c, d) {
return slice.call(arguments);
}
it('should curry based on the number of arguments given', () => {
const 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`', () => {
const 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', () => {
const values = ['0', 0.6, 'xyz'],
expected = lodashStable.map(values, stubArray);
const actual = lodashStable.map(values, (arity) => curryRight(fn, arity)());
assert.deepStrictEqual(actual, expected);
assert.deepStrictEqual(curryRight(fn, '2')(1)(2), [2, 1]);
});
it('should support placeholders', () => {
const 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', () => {
const 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', () => {
const 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', () => {
const 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`', () => {
lodashStable.times(2, (index) => {
const 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 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', () => {
const fn = function (a, b, c) {
const value = this || {};
return [value[a], value[b], value[c]];
};
const 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', () => {
const curried = curryRight(fn),
expected = [1, 2, 3, 4];
const 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);
});
});

View File

@@ -1,270 +0,0 @@
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;
});
});

View File

@@ -0,0 +1,270 @@
import assert from 'node:assert';
import partial from '../src/partial';
import property from '../src/property';
import iteratee from '../src/iteratee';
describe('custom `_.iteratee` methods', () => {
var array = ['one', 'two', 'three'],
getPropA = partial(property, 'a'),
getPropB = partial(property, 'b'),
getLength = partial(property, 'length'),
iteratee = iteratee;
const getSum = function () {
return function (result, object) {
return result + object.a;
};
};
const objects = [
{ a: 0, b: 0 },
{ a: 1, b: 0 },
{ a: 1, b: 1 },
];
it('`_.countBy` should use `_.iteratee` internally', () => {
iteratee = getLength;
assert.deepEqual(_.countBy(array), { '3': 2, '5': 1 });
iteratee = iteratee;
});
it('`_.differenceBy` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.deepEqual(_.differenceBy(objects, [objects[1]]), [objects[0]]);
iteratee = iteratee;
});
it('`_.dropRightWhile` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.dropRightWhile(objects), objects.slice(0, 2));
iteratee = iteratee;
});
it('`_.dropWhile` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.dropWhile(objects.reverse()).reverse(), objects.reverse().slice(0, 2));
iteratee = iteratee;
});
it('`_.every` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.strictEqual(_.every(objects.slice(1)), true);
iteratee = iteratee;
});
it('`_.filter` should use `_.iteratee` internally', () => {
const objects = [{ a: 0 }, { a: 1 }];
iteratee = getPropA;
assert.deepEqual(_.filter(objects), [objects[1]]);
iteratee = iteratee;
});
it('`_.find` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.strictEqual(_.find(objects), objects[1]);
iteratee = iteratee;
});
it('`_.findIndex` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.strictEqual(_.findIndex(objects), 1);
iteratee = iteratee;
});
it('`_.findLast` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.strictEqual(_.findLast(objects), objects[2]);
iteratee = iteratee;
});
it('`_.findLastIndex` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.strictEqual(_.findLastIndex(objects), 2);
iteratee = iteratee;
});
it('`_.findKey` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.strictEqual(_.findKey(objects), '2');
iteratee = iteratee;
});
it('`_.findLastKey` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.strictEqual(_.findLastKey(objects), '2');
iteratee = iteratee;
});
it('`_.groupBy` should use `_.iteratee` internally', () => {
iteratee = getLength;
assert.deepEqual(_.groupBy(array), { '3': ['one', 'two'], '5': ['three'] });
iteratee = iteratee;
});
it('`_.intersectionBy` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.deepEqual(_.intersectionBy(objects, [objects[2]]), [objects[1]]);
iteratee = iteratee;
});
it('`_.keyBy` should use `_.iteratee` internally', () => {
iteratee = getLength;
assert.deepEqual(_.keyBy(array), { '3': 'two', '5': 'three' });
iteratee = iteratee;
});
it('`_.map` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.deepEqual(_.map(objects), [0, 1, 1]);
iteratee = iteratee;
});
it('`_.mapKeys` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.mapKeys({ a: { b: 2 } }), { '2': { b: 2 } });
iteratee = iteratee;
});
it('`_.mapValues` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.mapValues({ a: { b: 2 } }), { a: 2 });
iteratee = iteratee;
});
it('`_.maxBy` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.maxBy(objects), objects[2]);
iteratee = iteratee;
});
it('`_.meanBy` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.strictEqual(_.meanBy(objects), 2 / 3);
iteratee = iteratee;
});
it('`_.minBy` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.minBy(objects), objects[0]);
iteratee = iteratee;
});
it('`_.partition` should use `_.iteratee` internally', () => {
const 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', () => {
iteratee = getPropA;
assert.deepEqual(_.pullAllBy(objects.slice(), [{ a: 1, b: 0 }]), [objects[0]]);
iteratee = iteratee;
});
it('`_.reduce` should use `_.iteratee` internally', () => {
iteratee = getSum;
assert.strictEqual(_.reduce(objects, undefined, 0), 2);
iteratee = iteratee;
});
it('`_.reduceRight` should use `_.iteratee` internally', () => {
iteratee = getSum;
assert.strictEqual(_.reduceRight(objects, undefined, 0), 2);
iteratee = iteratee;
});
it('`_.reject` should use `_.iteratee` internally', () => {
const objects = [{ a: 0 }, { a: 1 }];
iteratee = getPropA;
assert.deepEqual(_.reject(objects), [objects[0]]);
iteratee = iteratee;
});
it('`_.remove` should use `_.iteratee` internally', () => {
const objects = [{ a: 0 }, { a: 1 }];
iteratee = getPropA;
_.remove(objects);
assert.deepEqual(objects, [{ a: 0 }]);
iteratee = iteratee;
});
it('`_.some` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.strictEqual(_.some(objects), true);
iteratee = iteratee;
});
it('`_.sortBy` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.deepEqual(_.sortBy(objects.slice().reverse()), [objects[0], objects[2], objects[1]]);
iteratee = iteratee;
});
it('`_.sortedIndexBy` should use `_.iteratee` internally', () => {
const objects = [{ a: 30 }, { a: 50 }];
iteratee = getPropA;
assert.strictEqual(_.sortedIndexBy(objects, { a: 40 }), 1);
iteratee = iteratee;
});
it('`_.sortedLastIndexBy` should use `_.iteratee` internally', () => {
const objects = [{ a: 30 }, { a: 50 }];
iteratee = getPropA;
assert.strictEqual(_.sortedLastIndexBy(objects, { a: 40 }), 1);
iteratee = iteratee;
});
it('`_.sumBy` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.strictEqual(_.sumBy(objects), 1);
iteratee = iteratee;
});
it('`_.takeRightWhile` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.takeRightWhile(objects), objects.slice(2));
iteratee = iteratee;
});
it('`_.takeWhile` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.takeWhile(objects.reverse()), objects.reverse().slice(2));
iteratee = iteratee;
});
it('`_.transform` should use `_.iteratee` internally', () => {
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', () => {
iteratee = getPropB;
assert.deepEqual(_.uniqBy(objects), [objects[0], objects[2]]);
iteratee = iteratee;
});
it('`_.unionBy` should use `_.iteratee` internally', () => {
iteratee = getPropB;
assert.deepEqual(_.unionBy(objects.slice(0, 1), [objects[2]]), [objects[0], objects[2]]);
iteratee = iteratee;
});
it('`_.xorBy` should use `_.iteratee` internally', () => {
iteratee = getPropA;
assert.deepEqual(_.xorBy(objects, objects.slice(1)), [objects[0]]);
iteratee = iteratee;
});
});

View File

@@ -1,167 +0,0 @@
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);
});
});
});

View File

@@ -0,0 +1,174 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, noop, push, isModularize } from './utils';
import runInContext from '../src/runInContext';
describe('debounce and throttle', () => {
lodashStable.each(['debounce', 'throttle'], (methodName) => {
const func = _[methodName],
isDebounce = methodName == 'debounce';
it(`\`_.${methodName}\` should not error for non-object \`options\` values`, () => {
func(noop, 32, 1);
assert.ok(true);
});
it(`\`_.${methodName}\` should use a default \`wait\` of \`0\``, (done) => {
let callCount = 0,
funced = func(() => {
callCount++;
});
funced();
setTimeout(() => {
funced();
assert.strictEqual(callCount, isDebounce ? 1 : 2);
done();
}, 32);
});
it(`\`_.${methodName}\` should invoke \`func\` with the correct \`this\` binding`, (done) => {
const 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(() => {
assert.deepStrictEqual(actual, expected);
done();
}, 64);
});
it(`\`_.${methodName}\` supports recursive calls`, (done) => {
const actual = [],
args = lodashStable.map(['a', 'b', 'c'], (chr) => [{}, chr]),
expected = args.slice(),
queue = args.slice();
var funced = func(function () {
const current = [this];
push.apply(current, arguments);
actual.push(current);
const next = queue.shift();
if (next) {
funced.call(next[0], next[1]);
}
}, 32);
const next = queue.shift();
funced.call(next[0], next[1]);
assert.deepStrictEqual(actual, expected.slice(0, isDebounce ? 0 : 1));
setTimeout(() => {
assert.deepStrictEqual(actual, expected.slice(0, actual.length));
done();
}, 256);
});
it(`\`_.${methodName}\` should work if the system time is set backwards`, (done) => {
if (!isModularize) {
let callCount = 0,
dateCount = 0;
const lodash = runInContext({
Date: {
now: function () {
return ++dateCount == 4
? +new Date(2012, 3, 23, 23, 27, 18)
: +new Date();
},
},
});
const funced = lodash[methodName](() => {
callCount++;
}, 32);
funced();
setTimeout(() => {
funced();
assert.strictEqual(callCount, isDebounce ? 1 : 2);
done();
}, 64);
} else {
done();
}
});
it(`\`_.${methodName}\` should support cancelling delayed calls`, (done) => {
let callCount = 0;
const funced = func(
() => {
callCount++;
},
32,
{ leading: false },
);
funced();
funced.cancel();
setTimeout(() => {
assert.strictEqual(callCount, 0);
done();
}, 64);
});
it(`\`_.${methodName}\` should reset \`lastCalled\` after cancelling`, (done) => {
let callCount = 0;
const funced = func(() => ++callCount, 32, { leading: true });
assert.strictEqual(funced(), 1);
funced.cancel();
assert.strictEqual(funced(), 2);
funced();
setTimeout(() => {
assert.strictEqual(callCount, 3);
done();
}, 64);
});
it(`\`_.${methodName}\` should support flushing delayed calls`, (done) => {
let callCount = 0;
const funced = func(() => ++callCount, 32, { leading: false });
funced();
assert.strictEqual(funced.flush(), 1);
setTimeout(() => {
assert.strictEqual(callCount, 1);
done();
}, 64);
});
it(`\`_.${methodName}\` should noop \`cancel\` and \`flush\` when nothing is queued`, (done) => {
let callCount = 0,
funced = func(() => {
callCount++;
}, 32);
funced.cancel();
assert.strictEqual(funced.flush(), undefined);
setTimeout(() => {
assert.strictEqual(callCount, 0);
done();
}, 64);
});
});
});

294
test/debounce.spec.ts Normal file
View File

@@ -0,0 +1,294 @@
import assert from 'node:assert';
import { identity, argv, isPhantom, push } from './utils';
import debounce from '../src/debounce';
describe('debounce', () => {
it('should debounce a function', (done) => {
let callCount = 0;
const debounced = debounce((value) => {
++callCount;
return value;
}, 32);
const results = [debounced('a'), debounced('b'), debounced('c')];
assert.deepStrictEqual(results, [undefined, undefined, undefined]);
assert.strictEqual(callCount, 0);
setTimeout(() => {
assert.strictEqual(callCount, 1);
const results = [debounced('d'), debounced('e'), debounced('f')];
assert.deepStrictEqual(results, ['c', 'c', 'c']);
assert.strictEqual(callCount, 1);
}, 128);
setTimeout(() => {
assert.strictEqual(callCount, 2);
done();
}, 256);
});
it('subsequent debounced calls return the last `func` result', (done) => {
const debounced = debounce(identity, 32);
debounced('a');
setTimeout(() => {
assert.notStrictEqual(debounced('b'), 'b');
}, 64);
setTimeout(() => {
assert.notStrictEqual(debounced('c'), 'c');
done();
}, 128);
});
it('should not immediately call `func` when `wait` is `0`', (done) => {
let callCount = 0,
debounced = debounce(() => {
++callCount;
}, 0);
debounced();
debounced();
assert.strictEqual(callCount, 0);
setTimeout(() => {
assert.strictEqual(callCount, 1);
done();
}, 5);
});
it('should apply default options', (done) => {
let callCount = 0,
debounced = debounce(
() => {
callCount++;
},
32,
{},
);
debounced();
assert.strictEqual(callCount, 0);
setTimeout(() => {
assert.strictEqual(callCount, 1);
done();
}, 64);
});
it('should support a `leading` option', (done) => {
const callCounts = [0, 0];
const withLeading = debounce(
() => {
callCounts[0]++;
},
32,
{ leading: true },
);
const withLeadingAndTrailing = debounce(
() => {
callCounts[1]++;
},
32,
{ leading: true },
);
withLeading();
assert.strictEqual(callCounts[0], 1);
withLeadingAndTrailing();
withLeadingAndTrailing();
assert.strictEqual(callCounts[1], 1);
setTimeout(() => {
assert.deepStrictEqual(callCounts, [1, 2]);
withLeading();
assert.strictEqual(callCounts[0], 2);
done();
}, 64);
});
it('subsequent leading debounced calls return the last `func` result', (done) => {
const debounced = debounce(identity, 32, { leading: true, trailing: false }),
results = [debounced('a'), debounced('b')];
assert.deepStrictEqual(results, ['a', 'a']);
setTimeout(() => {
const results = [debounced('c'), debounced('d')];
assert.deepStrictEqual(results, ['c', 'c']);
done();
}, 64);
});
it('should support a `trailing` option', (done) => {
let withCount = 0,
withoutCount = 0;
const withTrailing = debounce(
() => {
withCount++;
},
32,
{ trailing: true },
);
const withoutTrailing = debounce(
() => {
withoutCount++;
},
32,
{ trailing: false },
);
withTrailing();
assert.strictEqual(withCount, 0);
withoutTrailing();
assert.strictEqual(withoutCount, 0);
setTimeout(() => {
assert.strictEqual(withCount, 1);
assert.strictEqual(withoutCount, 0);
done();
}, 64);
});
it('should support a `maxWait` option', (done) => {
let callCount = 0;
const debounced = debounce(
(value) => {
++callCount;
return value;
},
32,
{ maxWait: 64 },
);
debounced();
debounced();
assert.strictEqual(callCount, 0);
setTimeout(() => {
assert.strictEqual(callCount, 1);
debounced();
debounced();
assert.strictEqual(callCount, 1);
}, 128);
setTimeout(() => {
assert.strictEqual(callCount, 2);
done();
}, 256);
});
it('should support `maxWait` in a tight loop', (done) => {
let limit = argv || isPhantom ? 1000 : 320,
withCount = 0,
withoutCount = 0;
const withMaxWait = debounce(
() => {
withCount++;
},
64,
{ maxWait: 128 },
);
const withoutMaxWait = debounce(() => {
withoutCount++;
}, 96);
const start = +new Date();
while (new Date() - start < limit) {
withMaxWait();
withoutMaxWait();
}
const actual = [Boolean(withoutCount), Boolean(withCount)];
setTimeout(() => {
assert.deepStrictEqual(actual, [false, true]);
done();
}, 1);
});
it('should queue a trailing call for subsequent debounced calls after `maxWait`', (done) => {
let callCount = 0;
const debounced = debounce(
() => {
++callCount;
},
200,
{ maxWait: 200 },
);
debounced();
setTimeout(debounced, 190);
setTimeout(debounced, 200);
setTimeout(debounced, 210);
setTimeout(() => {
assert.strictEqual(callCount, 2);
done();
}, 500);
});
it('should cancel `maxDelayed` when `delayed` is invoked', (done) => {
let callCount = 0;
const debounced = debounce(
() => {
callCount++;
},
32,
{ maxWait: 64 },
);
debounced();
setTimeout(() => {
debounced();
assert.strictEqual(callCount, 1);
}, 128);
setTimeout(() => {
assert.strictEqual(callCount, 2);
done();
}, 192);
});
it('should invoke the trailing call with the correct arguments and `this` binding', (done) => {
let actual,
callCount = 0,
object = {};
const 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(() => {
assert.strictEqual(callCount, 2);
assert.deepStrictEqual(actual, [object, 'a']);
done();
}, 64);
});
});

View File

@@ -1,250 +0,0 @@
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);
});
});

26
test/deburr.spec.ts Normal file
View File

@@ -0,0 +1,26 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { burredLetters, deburredLetters, comboMarks } from './utils';
import deburr from '../src/deburr';
describe('deburr', () => {
it('should convert Latin Unicode letters to basic Latin', () => {
const actual = lodashStable.map(burredLetters, deburr);
assert.deepStrictEqual(actual, deburredLetters);
});
it('should not deburr Latin mathematical operators', () => {
const operators = ['\xd7', '\xf7'],
actual = lodashStable.map(operators, deburr);
assert.deepStrictEqual(actual, operators);
});
it('should deburr combining diacritical marks', () => {
const expected = lodashStable.map(comboMarks, lodashStable.constant('ei'));
const actual = lodashStable.map(comboMarks, (chr) => deburr(`e${chr}i`));
assert.deepStrictEqual(actual, expected);
});
});

View File

@@ -1,28 +0,0 @@
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);
});
});

16
test/defaultTo.spec.ts Normal file
View File

@@ -0,0 +1,16 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { falsey } from './utils';
import defaultTo from '../src/defaultTo';
describe('defaultTo', () => {
it('should return a default value if `value` is `NaN` or nullish', () => {
const expected = lodashStable.map(falsey, (value) =>
value == null || value !== value ? 1 : value,
);
const actual = lodashStable.map(falsey, (value) => defaultTo(value, 1));
assert.deepStrictEqual(actual, expected);
});
});

View File

@@ -1,18 +0,0 @@
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.spec.ts Normal file
View File

@@ -0,0 +1,66 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { objectProto } from './utils';
import defaults from '../src/defaults';
describe('defaults', () => {
it('should assign source properties if missing on `object`', () => {
const actual = defaults({ a: 1 }, { a: 2, b: 2 });
assert.deepStrictEqual(actual, { a: 1, b: 2 });
});
it('should accept multiple sources', () => {
let 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', () => {
const actual = defaults({ a: null }, { a: 1 });
assert.strictEqual(actual.a, null);
});
it('should overwrite `undefined` values', () => {
const actual = defaults({ a: undefined }, { a: 1 });
assert.strictEqual(actual.a, 1);
});
it('should assign `undefined` values', () => {
const 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`', () => {
const object = {
constructor: objectProto.constructor,
hasOwnProperty: objectProto.hasOwnProperty,
isPrototypeOf: objectProto.isPrototypeOf,
propertyIsEnumerable: objectProto.propertyIsEnumerable,
toLocaleString: objectProto.toLocaleString,
toString: objectProto.toString,
valueOf: objectProto.valueOf,
};
const source = {
constructor: 1,
hasOwnProperty: 2,
isPrototypeOf: 3,
propertyIsEnumerable: 4,
toLocaleString: 5,
toString: 6,
valueOf: 7,
};
let expected = lodashStable.clone(source);
assert.deepStrictEqual(defaults({}, source), expected);
expected = lodashStable.clone(object);
assert.deepStrictEqual(defaults({}, object, source), expected);
});
});

View File

@@ -1,66 +0,0 @@
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);
});
});

View File

@@ -1,101 +0,0 @@
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']);
});
});

101
test/defaultsDeep.spec.ts Normal file
View File

@@ -0,0 +1,101 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { noop } from './utils';
import defaultsDeep from '../src/defaultsDeep';
describe('defaultsDeep', () => {
it('should deep assign source properties if missing on `object`', () => {
const 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', () => {
const 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', () => {
const object = { a: { b: null } },
source = { a: { b: 2 } },
actual = defaultsDeep(object, source);
assert.strictEqual(actual.a.b, null);
});
it('should not overwrite regexp values', () => {
const 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', () => {
let 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', () => {
const object = { a: { b: undefined } },
source = { a: { b: 2 } },
actual = defaultsDeep(object, source);
assert.strictEqual(actual.a.b, 2);
});
it('should assign `undefined` values', () => {
const 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', () => {
const object = {
foo: { b: { c: { d: {} } } },
bar: { a: 2 },
};
const source = {
foo: { b: { c: { d: {} } } },
bar: {},
};
object.foo.b.c.d = object;
source.foo.b.c.d = source;
source.bar.b = source.foo.b;
const 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', () => {
const 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', () => {
const actual = defaultsDeep({ a: ['abc'] }, { a: 'abc' });
assert.deepStrictEqual(actual.a, ['abc']);
});
});

48
test/defer.spec.ts Normal file
View File

@@ -0,0 +1,48 @@
import assert from 'node:assert';
import { slice } from './utils';
import defer from '../src/defer';
describe('defer', () => {
it('should defer `func` execution', (done) => {
let pass = false;
defer(() => {
pass = true;
});
setTimeout(() => {
assert.ok(pass);
done();
}, 32);
});
it('should provide additional arguments to `func`', (done) => {
let args;
defer(
function () {
args = slice.call(arguments);
},
1,
2,
);
setTimeout(() => {
assert.deepStrictEqual(args, [1, 2]);
done();
}, 32);
});
it('should be cancelable', (done) => {
let pass = true,
timerId = defer(() => {
pass = false;
});
clearTimeout(timerId);
setTimeout(() => {
assert.ok(pass);
done();
}, 32);
});
});

View File

@@ -1,40 +0,0 @@
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);
});
});

View File

@@ -1,67 +0,0 @@
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);
});
});

82
test/delay.spec.ts Normal file
View File

@@ -0,0 +1,82 @@
import assert from 'node:assert';
import { slice } from './utils';
import delay from '../src/delay';
describe('delay', () => {
it('should delay `func` execution', (done) => {
let pass = false;
delay(() => {
pass = true;
}, 32);
setTimeout(() => {
assert.ok(!pass);
}, 1);
setTimeout(() => {
assert.ok(pass);
done();
}, 64);
});
it('should provide additional arguments to `func`', (done) => {
let args;
delay(
function () {
args = slice.call(arguments);
},
32,
1,
2,
);
setTimeout(() => {
assert.deepStrictEqual(args, [1, 2]);
done();
}, 64);
});
it('should use a default `wait` of `0`', (done) => {
let pass = false;
delay(() => {
pass = true;
});
assert.ok(!pass);
setTimeout(() => {
assert.ok(pass);
done();
}, 0);
});
it('should be cancelable', (done) => {
let pass = true,
timerId = delay(() => {
pass = false;
}, 32);
clearTimeout(timerId);
setTimeout(() => {
assert.ok(pass);
done();
}, 64);
});
it('should work with mocked `setTimeout`', () => {
let pass = false,
setTimeout = root.setTimeout;
setProperty(root, 'setTimeout', (func) => {
func();
});
delay(() => {
pass = true;
}, 32);
setProperty(root, 'setTimeout', setTimeout);
assert.ok(pass);
});
});

View File

@@ -1,85 +0,0 @@
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]);
});
});
});

View File

@@ -0,0 +1,86 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { _, LARGE_ARRAY_SIZE, stubOne, stubNaN, args } from './utils';
describe('difference methods', () => {
lodashStable.each(['difference', 'differenceBy', 'differenceWith'], (methodName) => {
const func = _[methodName];
it(`\`_.${methodName}\` should return the difference of two arrays`, () => {
const actual = func([2, 1], [2, 3]);
assert.deepStrictEqual(actual, [1]);
});
it(`\`_.${methodName}\` should return the difference of multiple arrays`, () => {
const actual = func([2, 1, 2, 3], [3, 4], [3, 2]);
assert.deepStrictEqual(actual, [1]);
});
it(`\`_.${methodName}\` should treat \`-0\` as \`0\``, () => {
const array = [-0, 0];
let actual = lodashStable.map(array, (value) => func(array, [value]));
assert.deepStrictEqual(actual, [[], []]);
actual = lodashStable.map(func([-0, 1], [1]), lodashStable.toString);
assert.deepStrictEqual(actual, ['0']);
});
it(`\`_.${methodName}\` should match \`NaN\``, () => {
assert.deepStrictEqual(func([1, NaN, 3], [NaN, 5, NaN]), [1, 3]);
});
it(`\`_.${methodName}\` should work with large arrays`, () => {
const 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\``, () => {
const array = [-0, 0];
let actual = lodashStable.map(array, (value) => {
const largeArray = lodashStable.times(
LARGE_ARRAY_SIZE,
lodashStable.constant(value),
);
return func(array, largeArray);
});
assert.deepStrictEqual(actual, [[], []]);
const 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\``, () => {
const 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`, () => {
const 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`, () => {
const 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]);
});
});
});

View File

@@ -1,23 +0,0 @@
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]);
});
});

23
test/differenceBy.spec.ts Normal file
View File

@@ -0,0 +1,23 @@
import assert from 'node:assert';
import { slice } from './utils';
import differenceBy from '../src/differenceBy';
describe('differenceBy', () => {
it('should accept an `iteratee`', () => {
let 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', () => {
let args;
differenceBy([2.1, 1.2], [2.3, 3.4], function () {
args || (args = slice.call(arguments));
});
assert.deepStrictEqual(args, [2.3]);
});
});

View File

@@ -0,0 +1,29 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { LARGE_ARRAY_SIZE, stubOne } from './utils';
import differenceWith from '../src/differenceWith';
describe('differenceWith', () => {
it('should work with a `comparator`', () => {
const 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`', () => {
const array = [-0, 1],
largeArray = lodashStable.times(LARGE_ARRAY_SIZE, stubOne),
others = [[1], largeArray],
expected = lodashStable.map(others, lodashStable.constant(['-0']));
const actual = lodashStable.map(others, (other) =>
lodashStable.map(differenceWith(array, other, lodashStable.eq), lodashStable.toString),
);
assert.deepStrictEqual(actual, expected);
});
});

View File

@@ -1,26 +0,0 @@
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.spec.ts Normal file
View File

@@ -0,0 +1,15 @@
import assert from 'node:assert';
import divide from '../src/divide';
describe('divide', () => {
it('should divide two numbers', () => {
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', () => {
assert.strictEqual(divide('6', '4'), 1.5);
assert.deepStrictEqual(divide('x', 'y'), NaN);
});
});

View File

@@ -1,15 +0,0 @@
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);
});
});

66
test/drop.spec.ts Normal file
View File

@@ -0,0 +1,66 @@
import assert from 'node:assert';
import lodashStable from 'lodash';
import { falsey, LARGE_ARRAY_SIZE, isEven } from './utils';
import drop from '../src/drop';
describe('drop', () => {
const array = [1, 2, 3];
it('should drop the first two elements', () => {
assert.deepStrictEqual(drop(array, 2), [3]);
});
it('should treat falsey `n` values, except `undefined`, as `0`', () => {
const expected = lodashStable.map(falsey, (value) =>
value === undefined ? [2, 3] : array,
);
const actual = lodashStable.map(falsey, (n) => drop(array, n));
assert.deepStrictEqual(actual, expected);
});
it('should return all elements when `n` < `1`', () => {
lodashStable.each([0, -1, -Infinity], (n) => {
assert.deepStrictEqual(drop(array, n), array);
});
});
it('should return an empty array when `n` >= `length`', () => {
lodashStable.each([3, 4, 2 ** 32, Infinity], (n) => {
assert.deepStrictEqual(drop(array, n), []);
});
});
it('should coerce `n` to an integer', () => {
assert.deepStrictEqual(drop(array, 1.6), [2, 3]);
});
it('should work in a lazy sequence', () => {
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),
);
});
});

Some files were not shown because too many files have changed in this diff Show More