deep-compare-by
Version:
Deep compare with a function
195 lines (193 loc) • 6.71 kB
JavaScript
const compare = require("./index");
const test = require("tape");
test("Basic compare", t => {
t.plan(2);
const cmp = compare(null);
t.equal(cmp({ a: 1 }, { a: 1 }), true, "Equivalent");
t.equal(cmp({ a: 2 }, { a: 1 }), false, "Not equivalent");
});
test("Null tests", t => {
t.plan(4);
const cmp = compare(null);
t.equal(cmp({ a: 1 }, { a: 1 }), true, "Equivalent null");
t.equal(cmp({ a: 2 }, { a: 1 }), false, "Not equivalent null");
const cmp2 = compare([]);
t.equal(cmp2({ a: 1 }, { a: 1 }), true, "Equivalent array");
t.equal(cmp2({ a: 2 }, { a: 1 }), false, "Not equivalent array");
});
test("Empty curry return", t => {
t.plan(2);
const cmp = compare();
const cmp2 = cmp(null);
t.equal(cmp2({ a: 1 }, { a: 1 }), true, "Equivalent");
t.equal(cmp2({ a: 2 }, { a: 1 }), false, "Not equivalent");
});
test("Invalid tests", t => {
t.plan(1);
const cmp = compare(7);
t.throws(()=>{
cmp.tests();
},/Tests invalid/,"Throw invlid tests when evaluated");
});
test("Empty curry return", t => {
t.plan(4);
const cmp = compare(null,{a:1});
const cmp2 = compare(null,cmp.lhs());
t.equal(cmp({ a: 1 }), true, "Equivalent: 1");
t.equal(cmp({ a: 2 }), false, "Not equivalent: 1");
t.equal(cmp2({ a: 1 }), true, "Equivalent: 2");
t.equal(cmp2({ a: 2 }), false, "Not equivalent: 2");
});
test("No default compare", t => {
t.plan(4);
const cmp = compare.noDefault((a, b) => b === 3);
t.equal(cmp({ a: 1 }, { a: 1 }), false, "Equivalent");
t.equal(cmp({ a: 1 }, { a: 3 }), true, "Pass custom");
const cmp2 = compare((a, b) => b === 3, { a: 1 });
t.equal(cmp2.noDefault({ a: 1 }), false, "Equivalent: later");
t.equal(cmp2.noDefault({ a: 3 }), true, "Pass custom: later");
});
test("Curried first value", t => {
t.plan(4);
const cmp = compare(null)({ a: 1 });
t.equal(cmp({ a: 1 }), true, "Equivalent");
t.equal(cmp({ a: 3 }), false, "Pass custom");
const cmp2 = compare(null, { a: 1 });
t.equal(cmp({ a: 1 }), true, "Equivalent");
t.equal(cmp({ a: 3 }), false, "Pass custom");
});
test("Non-object compare", t => {
t.plan(2);
const cmp = compare(null);
t.equal(cmp(6, 6), true, "Equal number");
t.equal(cmp(7, 6), false, "Unequal number");
});
test("Empty", t => {
t.plan(1);
const cmp = compare(null);
t.equal(cmp({}, {}), false, "Empty objects");
});
test("Object to not object", t => {
t.plan(1);
const cmp = compare(null);
t.equal(cmp({ a: 1 }, 6), false, "Object and number");
});
test("Partial match", t => {
t.plan(2);
const cmp = compare(null);
t.equal(cmp({ a: 1, b: 2 }, { a: 1 }), false, "Extra in arg1");
t.equal(cmp({ a: 1 }, { a: 1, b: 2 }), false, "Extra in arg2");
});
test("Same key count: different keys", t => {
t.plan(2);
const cmp = compare(null);
t.equal(cmp({ a: 1, b: 2 }, { a: 1, b: 2 }), true, "Same keys: a b");
t.equal(cmp({ a: 1, b: 2 }, { a: 1, c: 2 }), false, "Different keys: a c");
});
test("With function", t => {
t.plan(8);
const cmp = compare(null);
const cmpt = compare((a, b) => (
(typeof a === "function") &&
(typeof b === "function") &&
(a.toString() == b.toString())
));
t.equal(cmp({ a: 1, b: () => 2 }, { a: 1, b: () => 2 }), false, "Function not equal");
t.equal(cmpt({ a: 1, b: () => 2 }, { a: 1, b: () => 2 }), true, "Equal by string"); {
const testFuncA = () => 2;
const testFuncB = () => 2;
testFuncA.foo = 3;
testFuncA.foo = 2;
t.equal(cmpt({ a: 1, b: testFuncA }, { a: 1, b: testFuncB }), true, "Test scope");
} {
const cmpt2 = compare((a, b) => a.a === b.a);
t.equal(cmpt2({ a: 1, b: 3 }, { a: 1, b: 2, c: 4 }), true, "Compare can pass for objects");
}
t.equal(cmpt(
() => 2,
() => 2
), true, "Direct functions");
t.equal(cmpt({ a: 1, b: () => 2, c: 3 }, { a: 1, b: () => 2 }), false, "Extra property");
t.equal(cmpt({ a: 1, b: () => 2 }, { a: 1, b: () => 2, c: 3 }), false, "Extra property: switch");
t.equal(cmpt({ a: 1, b: () => 2 }, { a: 1, b: () => 3 }), false, "Diffirent function source");
});
test("Make new compare", t => {
t.plan(5);
const cmp = compare(null);
const cmp2 = compare(null);
t.equal(cmp({ a: 1 }, { a: 1 }), true, "Old compare: same");
t.equal(cmp({ a: 2 }, { a: 1 }), false, "Old compare: different");
t.equal(cmp2({ a: 1 }, { a: 1 }), true, "New compare: same");
t.equal(cmp2({ a: 2 }, { a: 1 }), false, "New compare: different");
t.notEqual(cmp, cmp2, "Function are, indeed, different");
});
test("Failed on path", t => {
t.plan(4);
const cmp = compare(null);
const newCmp = compare(null);
t.equal(cmp.failPath({
a: { b: { c: 2 } },
d: 3,
e: { f: 4 },
}, {
a: { b: { c: 2 } },
d: 3,
e: { f: 4 },
}), true, "Default fail path");
t.deepEqual(newCmp.failPath({
a: { b: { c: 2 } },
d: 3,
e: { f: 4 },
}, {
a: { b: { c: 3 } },
d: 3,
e: { f: 4 },
}), ['a', 'b', 'c'], "Correct path 1");
t.deepEqual(newCmp.failPath({
a: { b: { c: 2 } },
d: 3,
e: { f: 4 },
}, {
a: { b: { c: 2 } },
d: 3,
e: { f: 5 },
}), ['e', 'f'], "Correct path 2");
t.equal(newCmp.failPath({
a: { b: { c: 2 } },
d: 3,
e: { f: 4 },
}, {
a: { b: { c: 2 } },
d: 3,
e: { f: 4 },
}), true, "Fail path reset on success");
});
test("With function: top level", t => {
t.plan(2);
const cmp = compare(null);
const cmpt = compare((a, b) => (typeof a === typeof b));
t.equal(cmp(1, 2), false, "Default fails");
t.equal(cmpt(1, 2), true, "Modified passes");
});
test("Multiple tests", t => {
t.plan(5);
const cmp = compare(null);
const cmpt = compare([(a, b) => (typeof a === typeof b), (a, b) => (a === 9)]);
t.equal(cmp(1, 2), false, "Default 1");
t.equal(cmpt(1, 2), true, "Test 1");
t.equal(cmp(9, "8"), false, "Default 2");
t.equal(cmpt(8, "8"), false, "Fail 2");
t.equal(cmpt(9, "8"), true, "Pass 2");
});
test("Multiple tests: extended", t => {
t.plan(5);
const cmp = compare(null);
const cmpt = compare((a, b) => (typeof a === typeof b));
const cmpt2 = compare(cmpt.tests()
.concat([(a, b) => (a === 9)]));
t.equal(cmp(1, 2), false, "Default 1");
t.equal(cmpt(1, 2), true, "Test 1");
t.equal(cmpt(9, "8"), false, "Middle version");
t.equal(cmpt2(8, "8"), false, "Fail 2");
t.equal(cmpt2(9, "8"), true, "Pass 2");
});