import { max, min, isNumeric, explode, getIn, merge, compareString, compareNumber, compareObject, escapeHTML, union, eq, keys, difference, assocIn, dissoc, partial, undefinedAsNull, first, rest, butlast, last, complement, take, range, initFn, seedFn, generateFn, makeRandom, isReduced, reduced, reduceRec, reduce, reductionsRec, reductions, mapValues, repeat, runTests, } from "../src/sjs.exported.mjs"; const test_max = t => { t.start("max()"); t.testing("gets the greater number", () => { t.assertEq(max(0, 0), 0); t.assertEq(max(1, 2), 2); t.assertEq(max(4, 3), 4); }); }; const test_min = t => { t.start("min()"); t.testing("gets the smaller number", () => { t.assertEq(min(0, 0), 0); t.assertEq(min(1, 2), 1); t.assertEq(min(4, 3), 3); }); }; const test_isNumeric = t => { t.start("isNumeric()"); t.testing("checks if (first) char is numeric", () => { t.assertEq(isNumeric("0"), true); t.assertEq(isNumeric("5"), true); t.assertEq(isNumeric("9"), true); t.assertEq(isNumeric("10"), true); t.assertEq(isNumeric("1a"), true); t.assertEq(isNumeric("a1"), false); }); }; const test_explode = t => { t.start("explode()"); t.testing("empty array on empty string", () => { t.assertEq(explode(""), []); }); t.testing("string to array of chars", () => { t.assertEq(explode("a"), ["a"]); t.assertEq(explode("string"), ["s", "t", "r", "i", "n", "g"]); }); }; const test_getIn = t => { t.start("getIn()"); t.testing("empty values", () => { t.assertEq(getIn({}, []), {}); t.assertEq(getIn({ k: "v" }, []), { k: "v" }); t.assertEq(getIn({}, [0]), undefined); }); t.testing("undefined on bad path", () => { t.assertEq(getIn({a: 1}, ["b", "c"]), undefined); }); t.testing("mix of arrays and objects", () => { t.assertEq(getIn( {a: [{}, {b: [{c: [123]}]}]}, ["a", 1, "b", 0, "c", 0], ), 123); }); t.testing("missing values", () => { t.assertEq(getIn({}, ["a", "b", "c"]), undefined); t.assertEq(getIn({ a: {}}, ["a", "b", "c"]), undefined); t.assertEq(getIn({ a: { b: {}}}, ["a", "b", "c"]), undefined); t.assertEq(getIn({ a: { b: {}, c: {}}}, ["a", "b", "c"]), undefined); }); t.testing("nested valeues", () => { t.assertEq(getIn( { a: { b: { c: { d: "e" }}}}, ["a", "b", "c", "d"], ), "e"); }); }; const test_merge = t => { t.start("merge()"); t.testing("empty values", () => { t.assertEq(merge({}, {}), {}); }); t.testing("rhs gets preference over lhs", () => { t.assertEq( merge({a: 1, b: 2}, {b: 3, c: 4}), {a: 1, b: 3, c: 4}, ); }); t.testing("deep merge", () => { const lhs = { a: 1, b: 2, c: { 0: "zero", 1: "one", 2: { two: [2, 3], }, }, }; const rhs = { a: 11, c: { 0: "ZERO", 2: { three: 123, }, }, }; const expected = { a: 11, b: 2, c: { 0: "ZERO", 1: "one", 2: { two: [2, 3], three: 123, }, }, }; t.assertEq(merge(lhs, rhs), expected); }); }; const test_compareString = t => { t.start("compareString()"); t.testing("empty value", () => { t.assertEq(compareString("", ""), 0); }); t.testing("default sort", () => { const arr = [ "a", "Z" ]; t.assertEq( arr.toSorted(compareString), arr.toSorted().reverse(), ); }); }; const test_compareNumber = t => { t.start("compareNumber()"); t.testing("ascending sort", () => { const input = [ 9, 3, 8, 4, 6, 7 ]; const expected = [ 3, 4, 6, 7, 8, 9 ]; t.assertEq(input.toSorted(compareNumber), expected); }); }; const test_compareObject = t => { t.start("compareObject()"); t.testing("sort array of objects", () => { const input = [ { a: 3, b: 1, c: 1 }, { a: 1, b: 3, c: 1 }, { a: 1, b: 1, c: 3 }, ]; const expected = [ { a: 1, b: 1, c: 3 }, { a: 1, b: 3, c: 1 }, { a: 3, b: 1, c: 1 }, ]; t.assertEq(input.toSorted(compareObject), expected); }); }; const test_escapeHTML = t => { t.start("escapeHTML()"); t.testing("noop on empty string", () => { t.assertEq(escapeHTML(""), ""); }); t.testing("noop on string without special chars", () => { t.assertEq( escapeHTML("my non-special string"), "my non-special string", ); }); t.testing("escapeable chars", () => { const input = `&gt;`; const expected = `<img href="img'ln.png" ` + `/>&amp;gt;`; t.assertEq(escapeHTML(input), expected); }); }; const test_union = t => { t.start("union()"); t.testing("empty values", () => { t.assertEq(union([], []), []); t.assertEq(union([1], []), [1]); t.assertEq(union([], [1]), [1]); }); t.testing("non intersecting arrays", () => { t.assertEq( union([1, 2], [3, 4]).toSorted(compareNumber), [1, 2, 3, 4], ); }); t.testing("intersecting arrays", () => { t.assertEq( union([1, 2, 3, 4], [3, 4, 5]).toSorted(compareNumber), [1, 2, 3, 4, 5], ) }); }; const test_eq = t => { t.start("eq()"); t.testing("scalar values equality", () => { t.assertEq(eq(0, 0), true); t.assertEq(eq(100, 100), true); t.assertEq(eq(1.5, 1.5), true); t.assertEq(eq(-9, -9), true); t.assertEq(eq(0, 1), false); t.assertEq(eq(100, 99), false); t.assertEq(eq(1.5, 1.4), false); t.assertEq(eq(-9, 9), false); t.assertEq(eq(null, null), true); t.assertEq(eq(undefined, undefined), true); t.assertEq(eq("", ""), true); t.assertEq(eq("a string", "a string"), true); t.assertEq(eq(null, undefined), false); t.assertEq(eq(undefined, 0), false); t.assertEq(eq("", "0"), false); t.assertEq(eq("a string", "another string"), false); t.assertEq(eq(true, true), true); t.assertEq(eq(false, false), true); t.assertEq(eq(true, false), false); t.assertEq(eq(1n, 1n), true); t.assertEq(eq(99999999999999n, 99999999999999n), true); }); t.testing("array equality", () => { t.assertEq(eq([], []), true); t.assertEq(eq([0, 1, 2], [0, 1, 2]), true); t.assertEq(eq([0, 1, 2], new Array(0, 1, 2)), true); t.assertEq(eq([0, 1, 2], [0, 1]), false); t.assertEq(eq([0, 1], new Array(0, 1, 2)), false); t.assertEq(eq([undefined], [undefined]), true); t.assertEq(eq([null, 0, "", true], [null, 0, "", true]), true); t.assertEq(eq([[[[0]]]], [[[[0]]]]), true); t.assertEq(eq([[[[0]]]], [0]), false); }); t.testing("object equality", () => { t.assertEq(eq({}, {}), true); t.assertEq(eq({ a: 1 }, { a: 1 }), true); t.assertEq(eq({ a: 1, b: undefined }, { a: 1 }), false); t.assertEq(eq( { a: 1, b: { c: { d: "e" } } }, { a: 1, b: { c: { d: "e" } } }, ), true); }); t.testing("mixed values", () => { t.assertEq(eq( {a: ["", 1, 2, 3, [{ b: { c: [ "d", "e" ]}}]]}, {a: ["", 1, 2, 3, [{ b: { c: [ "d", "e" ]}}]]}, ), true); t.assertEq(eq(null, {}), false); t.assertEq(eq([], {}), false); t.assertEq(eq(new Date(123), new Date(123)), true); t.assertEq(eq({ d: new Date(12) }, { d: new Date(12) }), true); }); }; const test_keys = t => { t.start("keys()"); t.testing("happy paths", () => { t.assertEq( { a: 1, b: 2 }, keys(["a", "b"], { a: 1, b: 2, c: 3 }), ); }); t.testing("stress scenarios", () => { t.assertEq( {}, keys([], {}), "empty selection of empty object", ); t.assertEq( {}, keys([], {a: 1}), "empty selection of non-empty object", ); t.assertEq( {}, keys(["a"], {}), "non-empty selection of empty object", ); t.assertEq( { a: undefined, b: null }, keys(["a", "b", "c"], { a: undefined, b: null }), "falsy values", ); }); }; const test_difference = t => { t.start("difference()"); t.testing("empty values", () => { t.assertEq( difference(new Set(), new Set()), new Set(), ); t.assertEq( difference(new Set(), new Set([1, 2])), new Set(), ); t.assertEq( difference(new Set([1, 2]), new Set()), new Set([1, 2]), ); }); t.testing("different subsets", () => { t.assertEq( difference(new Set([1, 2]), new Set([3, 4])), new Set([1, 2]), ); t.assertEq( difference(new Set([1, 2, 3]), new Set([2, 4, 5])), new Set([1, 3]), ); t.assertEq( difference(new Set([1]), new Set([1, 2, 3, 4, 5])), new Set(), ); t.assertEq( difference(new Set([1, 2, 3]), new Set([1, 2, 3])), new Set(), ); }); }; const test_assocIn = t => { t.start("assocIn()"); t.testing("empty values", () => { t.assertEq(assocIn({}, [], null), {}); t.assertEq(assocIn({ k: "v" }, [], null), { k: "v" }); }); t.testing("adding values", () => { t.assertEq(assocIn({}, ["k"], "v"), { k: "v" }); t.assertEq(assocIn({}, ["k1", "k2"], "v"), { k1: { k2: "v" }}); t.assertEq( assocIn({}, ["k1", "k2", "k3"], "v"), { k1: { k2: { k3: "v" }}}, ); t.assertEq( assocIn({ k: "v" }, ["k1", "k2"], "v"), { k: "v", k1: { k2: "v" }}, ); }); t.testing("replacing values", () => { t.assertEq( assocIn( { k1: { k2: { k3: "before" }}}, ["k1", "k2", "k3"], "after" ), { k1: { k2: { k3: "after" }}} ); }); }; const test_dissoc = t => { t.start("dissoc()"); t.testing("empty values", () => { t.assertEq(dissoc({}, "k"), {}); }); t.testing("noop when key does not exist", () => { t.assertEq(dissoc({ a: 1 }, "b"), { a: 1 }); }); t.testing("removes the key", () => { t.assertEq(dissoc({ a: 1, b: 2}, "b"), { a: 1 }); }); }; const test_partial = t => { t.start("partial()"); t.testing("empty values", () => { const adder = (a, b, c) => a + b + c; const adder1 = partial(adder); t.assertEq(adder1(1, 2, 3), 6); const adder2 = partial(adder, 4, 5, 6); t.assertEq(adder2(), 15); const noargs = () => "static"; t.assertEq(partial(noargs)(), noargs()); }); t.testing("too few arguments", () => { const threeArgs = (a, b, c) => { if (c === undefined) { throw new Error("missing args"); } return a + b + c; }; const add1 = partial(threeArgs, 1); try { add1(2); t.assertEq(true, false); } catch (e) { t.assertEq(e.message, "missing args"); } const add1And2 = partial(threeArgs, 1, 2); try { add1And2(); t.assertEq(true, false); } catch (e) { t.assertEq(e.message, "missing args"); } const addNothing = partial(threeArgs); try { addNothing(); t.assertEq(true, false); } catch (e) { t.assertEq(e.message, "missing args"); } }); t.testing("too many arguments", () => { const twoArgs = (a, b) => a + b; t.assertEq(partial(twoArgs, 1)(2, 3), 3); t.assertEq(partial(twoArgs, 1, 2)(3), 3); }); t.testing("daily usage", () => { const twoArg = (a, b) => a + b; const numbers = [ 1, 2, 3, 4, 5 ]; t.assertEq( numbers.map(partial(twoArg, 2)), [ 3, 4, 5, 6, 7 ], ); }); t.testing("nested partials", () => { const threeArgs = (a, b, c) => a + b + c; const add1 = partial(threeArgs, 1); const add1And2 = partial(add1, 2); t.assertEq(add1And2(3), 6); }); }; const test_undefinedAsNull = t => { t.start("undefinedAsNull()"); t.testing("null for undefined or null", () => { t.assertEq(undefinedAsNull(undefined), null); t.assertEq(undefinedAsNull(null), null); }); t.testing("identity otherwise", () => { const expected = [ " ", "", 0, 1, -1.1, true, false, [], [ "" ], {}, { k: "v" }, ]; const given = expected.map(undefinedAsNull); t.assertEq(given, expected); }); }; const test_first = t => { t.start("first()"); t.testing("undefined for an empty array", () => { t.assertEq(undefined, first([])); t.assertEq(undefined, first("")); }); t.testing("the first element otherwise", () => { t.assertEq(1, first([1, 2, 3])); t.assertEq("a", first("abc")); }); }; const test_rest = t => { t.start("rest()"); t.testing("an empty array when no more elements are available", () => { t.assertEq([], rest([])); t.assertEq([], rest([1])); t.assertEq("", rest("")); t.assertEq("bc", rest("abc")); }); t.testing("the rest of the collection otherwise", () => { t.assertEq([2, 3], rest([1, 2, 3])); t.assertEq("bc", rest("abc")); }); t.testing("combines with first() well", () => { const arr = ["anything", "can", "go", "here"]; t.assertEq(arr, [ first(arr), ...rest(arr) ]); }); }; const test_butlast = t => { t.start("butlast()"); t.testing("empty array when ther are no more elements", () => { t.assertEq([], butlast([])); t.assertEq([], butlast([1])); t.assertEq("", butlast("")); t.assertEq("", butlast("c")); }); t.testing("the beginning of the array otherwise", () => { t.assertEq([1, 2], butlast([1, 2, 3])); t.assertEq("ab", butlast("abc")); }); }; const test_last = t => { t.start("last()"); t.testing("undefined for an empty array", () => { t.assertEq(undefined, last([])); t.assertEq(undefined, last("")); }); t.testing("the last element otherwise", () => { t.assertEq(3, last([1, 2, 3])); t.assertEq("c", last("abc")); }); t.testing("combines with butlast() well", () => { const arr = ["anything", "goes", "here", "too"]; t.assertEq(arr, [ ...butlast(arr), last(arr) ]); }); }; const test_complement = t => { t.start("complement()"); t.testing("even to odd", () => { const even = n => (n % 2) === 0; const odd = complement(even); const input = [1, 2, 3, 4, 5]; const expected1 = [2, 4]; const expected2 = [1, 3, 5]; t.assertEq(input.filter(even), expected1); t.assertEq(input.filter(odd), expected2); }); }; const test_take = t => { t.start("take()"); t.testing("example usage", () => { t.assertEq(Array.from(take(3, [1, 2, 3, 4, 5, 6])), [1, 2, 3]); t.assertEq([...take(3, [1, 2, 3, 4, 5, 6])], [1, 2, 3]); const gen = function*() { yield* [1, 2, 3, 4, 5, 6]; } t.assertEq([...take(3, gen())], [1, 2, 3]); t.assertEq([...take(3, [1, 2])], [1, 2]); t.assertEq([...take(1, [])], []); t.assertEq([...take(0, [1])], []); t.assertEq([...take(-1, [1])], []); }); }; const test_range = t => { t.start("range()"); t.testing("empty values", () => { const [] = range(); const [ a ] = range(); t.assertEq(a, 0n); const [ b, c, d, e ] = range(); t.assertEq( [ b, c, d, e ], [ 0n, 1n, 2n, 3n ], ); t.assertEq( Array.from(take(5, range())), [ 0n, 1n, 2n, 3n, 4n ], ); t.assertEq( Array.from(take(1, range())), [ 0n ], ); t.assertEq( Array.from(take(0, range())), [], ); }); t.testing("example usage", () => { t.assertEq( [...range(-5, 5)], [ -5n, -4n, -3n, -2n, -1n, 0n, 1n, 2n, 3n, 4n ], ); t.assertEq( [...range(-100, 100, 10)], [ -100n, -90n, -80n, -70n, -60n, -50n, -40n, -30n, -20n, -10n, 0n, 10n, 20n, 30n, 40n, 50n, 60n, 70n, 80n, 90n, ], ); t.assertEq([...range(0, 4, 2)], [0n, 2n]); t.assertEq([...range(0, 5, 2)], [0n, 2n, 4n]); t.assertEq([...range(0, 6, 2)], [0n, 2n, 4n]); t.assertEq([...range(0, 7, 2)], [0n, 2n, 4n, 6n]); t.assertEq( [...range(100, 0, -10)], [ 100n, 90n, 80n, 70n, 60n, 50n, 40n, 30n, 20n, 10n ] ); t.assertEq( [...range(10, -10, -1)], [ 10n, 9n, 8n, 7n, 6n, 5n, 4n, 3n, 2n, 1n, 0n, -1n, -2n, -3n, -4n, -5n, -6n, -7n, -8n, -9n, ], ); t.assertEq( [...take(3, range(1, 10, 0))], [ 1n, 1n, 1n ], ); t.assertEq( [...take(3, range(10, 1, 0))], [ 10n, 10n, 10n ], ); }); }; const test_initFn = t => { t.start("initFn()"); t.testing("constant values", () => { t.assertEq(initFn(), { mt: new Array(624), mti: 625, }); }); }; const test_seedFn = t => { t.start("seedFn()"); t.testing("expected values", () => { const expected = [ 1, 1812433254, 3713160357, 3109174145, 64984499, 3392658084, 446538473, 2629760756, 2453345558, 1394803949, ]; const ref = initFn(); seedFn(ref, 1); t.assertEq(ref.mt.slice(0, 10), expected); }); }; const test_generateFn = t => { t.start("generateFn()"); t.testing("expected values, created from a seed", () => { const n1 = 1791095845; const n2 = 4282876139; const n3 = 3093770124; const ref = initFn(); seedFn(ref, 1); const rand = partial(generateFn, ref); t.assertEq(rand(), n1); t.assertEq(rand(), n2); t.assertEq(rand(), n3); rand(1); t.assertEq(rand(), n1); t.assertEq(rand(), n2); t.assertEq(rand(), n3); }); }; const test_makeRandom = t => { t.start("random()"); t.testing("generates the expected numbers", () => { const expected = [ 1791095845, 4282876139, 3093770124, 4005303368, 491263, 550290313, 1298508491, 4290846341, 630311759, 1013994432, 396591248, 1703301249, 799981516, 1666063943, 1484172013, 2876537340, 1704103302, 4018109721, 2314200242, 3634877716, 1800426750, 1345499493, 2942995346, 2252917204, 878115723, 1904615676, 3771485674, 986026652, 117628829, 2295290254, 2879636018, 3925436996, 1792310487, 1963679703, 2399554537, 1849836273, 602957303, 4033523166, 850839392, 3343156310, 3439171725, 3075069929, 4158651785, 3447817223, 1346146623, 398576445, 2973502998, 2225448249, 3764062721, 3715233664, 3842306364, 3561158865, 365262088, 3563119320, 167739021, 1172740723, 729416111, 254447594, 3771593337, 2879896008, 422396446, 2547196999, 1808643459, 2884732358, 4114104213, 1768615473, 2289927481, 848474627, 2971589572, 1243949848, 1355129329, 610401323, 2948499020, 3364310042, 3584689972, 1771840848, 78547565, 146764659, 3221845289, 2680188370, 4247126031, 2837408832, 3213347012, 1282027545, 1204497775, 1916133090, 3389928919, 954017671, 443352346, 315096729, 1923688040, 2015364118, 3902387977, 413056707, 1261063143, 3879945342, 1235985687, 513207677, 558468452, 2253996187, 83180453, 359158073, 2915576403, 3937889446, 908935816, 3910346016, 1140514210, 1283895050, 2111290647, 2509932175, 229190383, 2430573655, 2465816345, 2636844999, 630194419, 4108289372, 2531048010, 1120896190, 3005439278, 992203680, 439523032, 2291143831, 1778356919, 4079953217, 2982425969, 2117674829, 1778886403, 2321861504, 214548472, 3287733501, 2301657549, 194758406, 2850976308, 601149909, 2211431878, 3403347458, 4057003596, 127995867, 2519234709, 3792995019, 3880081671, 2322667597, 590449352, 1924060235, 598187340, 3831694379, 3467719188, 1621712414, 1708008996, 2312516455, 710190855, 2801602349, 3983619012, 1551604281, 1493642992, 2452463100, 3224713426, 2739486816, 3118137613, 542518282, 3793770775, 2964406140, 2678651729, 2782062471, 3225273209, 1520156824, 1498506954, 3278061020, 1159331476, 1531292064, 3847801996, 3233201345, 1838637662, 3785334332, 4143956457, 50118808, 2849459538, 2139362163, 2670162785, 316934274, 492830188, 3379930844, 4078025319, 275167074, 1932357898, 1526046390, 2484164448, 4045158889, 1752934226, 1631242710, 1018023110, 3276716738, 3879985479, 3313975271, 2463934640, 1294333494, 12327951, 3318889349, 2650617233, 656828586, ]; const firstRand = makeRandom(1); const given1 = expected.map(_ => firstRand()); firstRand(1); const given2 = expected.map(_ => firstRand()); const secondRand = makeRandom(1); const given3 = expected.map(_ => secondRand()); secondRand(1); const given4 = expected.map(_ => secondRand()); t.assertEq(given1, expected); t.assertEq(given2, expected); t.assertEq(given3, expected); t.assertEq(given4, expected); }); }; const test_isReduced = t => { t.start("isReduced()"); t.testing("simple boolean response", () => { t.assertEq(isReduced(null), false); t.assertEq(isReduced(undefined), false); t.assertEq(isReduced(0), false); t.assertEq(isReduced([]), false); t.assertEq(isReduced("reduce"), false); t.assertEq(isReduced({}), false); t.assertEq(isReduced(reduced(null)), true); }); }; const test_reduced = t => { t.start("reduced()"); t.testing("simple constructor", () => { t.assertEq(isReduced(reduced(123)), true); }); t.testing("we can extract the value", () => { t.assertEq(reduced("data").value, "data"); }); }; const test_reduceRec = t => { t.start("reduceRec()"); t.testing("return the value if isReduced()", () => { t.assertEq(reduceRec(null, null, reduced("abc"), null), "abc"); }); t.testing("the bare value if at the end of the collection", () => { t.assertEq(reduceRec([], null, "acc", 0), "acc"); t.assertEq(reduceRec([1, 2], null, "acc", 2), "acc"); }); t.testing("recurse while applying function", () => { const expected = [{ acc: -5, el: 4, index: 3, coll: [1, 2, 3, 4, 5], ret: -1, }, { acc: -1, el: 5, index: 4, coll: [1, 2, 3, 4, 5], ret: 4, }]; const calls = []; const fn = (acc, el, index, coll) => { const ret = acc + el; calls.push({ acc, el, index, coll, ret, }); return ret; }; const coll = [1, 2, 3, 4, 5]; t.assertEq(reduceRec(coll, fn, -5, 3), 4); t.assertEq(calls, expected); }); }; const test_reduce = t => { t.start("reduce()"); t.testing("empty value", () => { t.assertEq(reduce([], null), undefined); t.assertEq(reduce([], null, 123), 123); }); t.testing("without init", () => { t.assertEq(reduce([1], null), 1); t.assertEq(reduce([1, 300, 2, 3], max), 300); }); t.testing("with init", () => { t.assertEq(reduce([1], max, 100), 100); t.assertEq(reduce([1, 300, 2, 3], max, 400), 400); }); }; const test_reductionsRec = t => { t.start("reductionsRec()"); t.testing("return the value if isReduced()", () => { t.assertEq( reductionsRec(null, null, reduced("abc"), null, []), ["abc"], ); }); t.testing("the bare value if at the end of the collection", () => { t.assertEq(reductionsRec([], null, null, 0, "ret"), "ret"); t.assertEq(reductionsRec([1, 2], null, null, 2, "ret"), "ret"); }); t.testing("recurse while applying function", () => { const expected = [{ acc: -5, el: 4, index: 3, coll: [1, 2, 3, 4, 5], ret: -1, }, { acc: -1, el: 5, index: 4, coll: [1, 2, 3, 4, 5], ret: 4, }]; const calls = []; const fn = (acc, el, index, coll) => { const ret = acc + el; calls.push({ acc, el, index, coll, ret, }); return ret; }; const coll = [1, 2, 3, 4, 5]; t.assertEq(reductionsRec(coll, fn, -5, 3, []), [-1, 4]); t.assertEq(calls, expected); }); }; const test_reductions = t => { t.start("reductions()"); const add = (a, b) => a + b; t.testing("with and without initial values", () => { t.assertEq(reductions([1, 1, 1, 1], add), [1, 2, 3, 4]); t.assertEq(reductions([1, 1, 1], add, 0), [1, 2, 3]); t.assertEq(reductions([1, 1, 1], add, 1), [2, 3, 4]); t.assertEq(reductions([1, 2, 3], add), [1, 3, 6]); }); t.testing("the last values corresponds to reduce()", () => { const arr = [1, 2, 3]; t.assertEq(last(reductions(arr, add)), reduce(arr, add)); }); }; const test_mapValues = t => { t.start("mapValues()"); t.testing("empty object", () => { t.assertEq(mapValues({}, null), {}); }); t.testing("update the values", () => { const obj = { a: 1, b: 2, c: 3 }; t.assertEq(mapValues(obj, _ => 1, ), {a: 1, b: 1, c: 1}); t.assertEq(mapValues(obj, x => x * x, ), {a: 1, b: 4, c: 9}); }); }; const test_repeat = t => { t.start("repeat()"); t.testing("empty value", () => { t.assertEq(repeat(0, null), []); }); t.testing("just repeat the values", () => { t.assertEq(repeat(1, ""), [""]); t.assertEq(repeat(10, 1), [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]); }); }; runTests([ test_max, test_min, test_isNumeric, test_explode, test_getIn, test_merge, test_compareString, test_compareNumber, test_compareObject, test_escapeHTML, test_union, test_eq, test_keys, test_difference, test_assocIn, test_dissoc, test_partial, test_undefinedAsNull, test_first, test_rest, test_butlast, test_last, test_complement, test_take, test_range, test_initFn, test_seedFn, test_generateFn, test_makeRandom, test_isReduced, test_reduced, test_reduceRec, test_reduce, test_reductionsRec, test_reductions, test_mapValues, test_repeat, ]);