import assert from "node:assert/strict"; import * as runner from "../runner.mjs"; import { eq, keys, difference, assocIn, getIn, first, promisify, partial, strSortFn, } from "../../src/utils.mjs"; const test_eq = t => { t.start("eq()"); t.test("scalar values equality", () => { assert(eq(0, 0)); assert(eq(100, 100)); assert(eq(1.5, 1.5)); assert(eq(-9, -9)); assert(!eq(0, 1)); assert(!eq(100, 99)); assert(!eq(1.5, 1.4)); assert(!eq(-9, 9)); assert(eq(null, null)); assert(eq(undefined, undefined)); assert(eq("", "")); assert(eq("a string", "a string")); assert(!eq(null, undefined)); assert(!eq(undefined, 0)); assert(!eq("", "0")); assert(!eq("a string", "another string")); assert(eq(true, true)); assert(eq(false, false)); assert(!eq(true, false)); assert(eq(1n, 1n)); assert(eq(99999999999999n, 99999999999999n)); }); t.test("array equality", () => { assert(eq([], [])); assert(eq([0, 1, 2], [0, 1, 2])); assert(eq([0, 1, 2], new Array(0, 1, 2))); assert(!eq([0, 1, 2], [0, 1])); assert(!eq([0, 1], new Array(0, 1, 2))); assert(eq([undefined], [undefined])); assert(eq([null, 0, "", true], [null, 0, "", true])); assert(eq([[[[0]]]], [[[[0]]]])); assert(!eq([[[[0]]]], [0])); }); t.test("object equality", () => { assert(eq({}, {})); assert(eq({ a: 1 }, { a: 1 })); assert(!eq({ a: 1, b: undefined }, { a: 1 })); assert(eq( { a: 1, b: { c: { d: "e" } } }, { a: 1, b: { c: { d: "e" } } }, )); }); t.test("mixed values", () => { assert(eq( {a: ["", 1, 2, 3, [{ b: { c: [ "d", "e" ]}}]]}, {a: ["", 1, 2, 3, [{ b: { c: [ "d", "e" ]}}]]}, )); assert(!eq(null, {})); assert(!eq([], {})); }); }; const test_keys = t => { t.start("keys()"); t.test("happy paths", () => { assert.deepEqual( { a: 1, b: 2 }, keys(["a", "b"], { a: 1, b: 2, c: 3 }), ); }); t.test("stress scenarios", () => { assert.deepEqual( {}, keys([], {}), "empty selection of empty object", ); assert.deepEqual( {}, keys([], {a: 1}), "empty selection of non-empty object", ); assert.deepEqual( {}, keys(["a"], {}), "non-empty selection of empty object", ); assert.deepEqual( { a: undefined, b: null }, keys(["a", "b", "c"], { a: undefined, b: null }), "falsy values", ); }); }; const test_difference = t => { t.start("difference()"); t.test("empty values", () => { assert.deepEqual( difference(new Set(), new Set()), new Set(), ); assert.deepEqual( difference(new Set(), new Set([1, 2])), new Set(), ); assert.deepEqual( difference(new Set([1, 2]), new Set()), new Set([1, 2]), ); }); t.test("different subsets", () => { assert.deepEqual( difference(new Set([1, 2]), new Set([3, 4])), new Set([1, 2]), ); assert.deepEqual( difference(new Set([1, 2, 3]), new Set([2, 4, 5])), new Set([1, 3]), ); assert.deepEqual( difference(new Set([1]), new Set([1, 2, 3, 4, 5])), new Set(), ); assert.deepEqual( difference(new Set([1, 2, 3]), new Set([1, 2, 3])), new Set(), ); }); }; const test_assocIn = t => { t.start("assocIn()"); t.test("empty values", () => { assert.deepEqual(assocIn({}, [], null), {}); assert.deepEqual(assocIn({ k: "v" }, [], null), { k: "v" }); }); t.test("adding values", () => { assert.deepEqual(assocIn({}, ["k"], "v"), { k: "v" }); assert.deepEqual(assocIn({}, ["k1", "k2"], "v"), { k1: { k2: "v" }}); assert.deepEqual(assocIn({}, ["k1", "k2", "k3"], "v"), { k1: { k2: { k3: "v" }}}); assert.deepEqual(assocIn({ k: "v" }, ["k1", "k2"], "v"), { k: "v", k1: { k2: "v" }}); }); t.test("replacing values", () => { assert.deepEqual( assocIn( { k1: { k2: { k3: "before" }}}, ["k1", "k2", "k3"], "after" ), { k1: { k2: { k3: "after" }}} ); }); }; const test_getIn = t => { t.start("getIn()"); t.test("empty values", () => { assert.deepEqual(getIn({}, []), {}); assert.deepEqual(getIn({ k: "v" }, []), { k: "v" }); }); t.test("missing values", () => { assert.deepEqual(getIn({}, ["a", "b", "c"]), undefined); assert.deepEqual(getIn({ a: {}}, ["a", "b", "c"]), undefined); assert.deepEqual(getIn({ a: { b: {}}}, ["a", "b", "c"]), undefined); assert.deepEqual(getIn({ a: { b: {}, c: {}}}, ["a", "b", "c"]), undefined); }); t.test("nested valeues", () => { assert.deepEqual(getIn({ a: { b: { c: { d: "e" }}}}, ["a", "b", "c", "d"]), "e"); }); }; const test_first = t => { t.start("first()"); t.test("empty values", () => { assert.equal(first([], () => {}), null); }); t.test("when function doesn't transform, it behaves similarly to [].find()", () => { const arr1 = [ 0, null, undefined, "", 1, 2 ]; assert.equal(first(arr1, x => x), 1); assert.equal(arr1.find(x => x), 1); const arr2 = [ 0, null, undefined, "", false ]; assert.equal(first(arr2, x => x), null); assert.equal(arr2.find(x => x), undefined); }); t.test("when it does transform, we return the transformed value", () => { const arr = [ 1, 3, 5, 6 ]; assert.equal( first(arr, x => x % 2 === 0 && "a brand new value"), "a brand new value", ); }); }; const test_promisify = t => { t.start("promisify()"); t.test("we wrap the callbacky function", async () => { const okFn1 = (a, b, cb) => setTimeout(() => cb(null, { a, b, ok: true })); const errFn1 = (a, b, c, cb) => setTimeout(() => cb({ err: true, a }, "ignored")); const okFn2 = promisify(okFn1); const errFn2 = promisify(errFn1); assert.deepEqual( await okFn2("a-value", "b-value"), { a: "a-value", b: "b-value", ok: true, }, ); assert.rejects( async () => await errFn2("aa", "bb", "cc"), { err: true, a: "aa", }, ); }); }; const test_partial = t => { t.start("partial()"); t.test("empty values", () => { const adder = (a, b, c) => a + b + c; const adder1 = partial(adder); assert.equal(adder1(1, 2, 3), 6); const adder2 = partial(adder, 4, 5, 6); assert.equal(adder2(), 15); const noargs = () => "static"; assert.equal(partial(noargs)(), noargs()); }); t.test("too few arguments", () => { const threeArgs = (a, b, c) => { assert.notEqual(c, undefined); return a + b + c }; const add1 = partial(threeArgs, 1); assert.throws( () => add1(2), assert.AssertionError, ); const add1And2 = partial(threeArgs, 1, 2); assert.throws( () => add1And2(), assert.AssertionError, ); const addNothing = partial(threeArgs); assert.throws( () => addNothing(), assert.AssertionError, ); }); t.test("too many arguments", () => { const twoArgs = (a, b) => a + b; assert.equal(partial(twoArgs, 1)(2, 3), 3); assert.equal(partial(twoArgs, 1, 2)(3), 3); }); t.test("daily usage", () => { const twoArg = (a, b) => a + b; const numbers = [ 1, 2, 3, 4, 5 ]; assert.deepEqual( numbers.map(partial(twoArg, 2)), [ 3, 4, 5, 6, 7 ], ); }); t.test("nested partials", () => { const threeArgs = (a, b, c) => a + b + c; const add1 = partial(threeArgs, 1); const add1And2 = partial(add1, 2); assert.equal(add1And2(3), 6); }); }; const test_strSortFn = t => { t.start("strSortFn()"); t.test("empty value", () => { assert.equal(strSortFn("", ""), 0); }); t.test("default sort", () => { const arr = [ "a", "Z" ]; assert.deepEqual( [...arr].sort(strSortFn), [...arr].sort().reverse(), ); }); }; await runner.runTests([ test_eq, test_keys, test_difference, test_assocIn, test_getIn, test_first, test_promisify, test_partial, test_strSortFn, ]);