Skip to content

Commit

Permalink
Add Utils.shallowCompare plus unit tests for shallowCompare and shall…
Browse files Browse the repository at this point in the history
…owCompareKeys
  • Loading branch information
cmslewis committed Apr 14, 2017
1 parent 716bb6f commit 771bdd1
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 8 deletions.
46 changes: 39 additions & 7 deletions packages/table/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,16 +199,24 @@ export const Utils = {
return value;
},

shallowCompareKeys,

/**
* Partial shallow comparison between objects using the given list of keys.
* Returns true if the keys are the same between the two objects and the values for each key are
* shallowly equal.
*/
shallowCompareKeys(objA: any, objB: any, keys: string[]) {
for (const key of keys) {
if (objA[key] !== objB[key]) {
return false;
}
shallowCompare(objA: any, objB: any) {
if (bothUndefined(objA, objB) || bothNull(objA, objB)) {
return true;
} else if (objA == null || objB == null) {
return false;
} else if (Array.isArray(objA) !== Array.isArray(objB)) {
return false;
}
return true;
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
return shallowCompareKeys(objA, objB, keysA)
&& shallowCompareKeys(objA, objB, keysB);
},

/**
Expand Down Expand Up @@ -334,3 +342,27 @@ export const Utils = {
return event.button === 0;
},
};

/**
* Partial shallow comparison between objects using the given list of keys.
*/
function shallowCompareKeys(objA: any, objB: any, keys: string[]) {
if (bothUndefined(objA, objB) || bothNull(objA, objB)) {
return true;
} else if (objA == null || objB == null) {
return false;
} else if (Array.isArray(objA) !== Array.isArray(objB)) {
return false;
}
return keys
.map((key) => objA.hasOwnProperty(key) === objB.hasOwnProperty(key) && objA[key] === objB[key])
.every((isEqual) => isEqual);
}

function bothUndefined(objA: any, objB: any) {
return objA === undefined && objB === undefined;
}

function bothNull(objA: any, objB: any) {
return objA === null && objB === null;
}
80 changes: 79 additions & 1 deletion packages/table/test/utilsTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ describe("Utils", () => {
});

describe("reorderArray", () => {

const ARRAY_STRING = "ABCDEFG";
const ARRAY = ARRAY_STRING.split("");
const ARRAY_LENGTH = ARRAY.length;
Expand Down Expand Up @@ -303,4 +302,83 @@ describe("Utils", () => {
expect(result).to.eql(expected.split(""));
}
});

describe("shallowCompareKeys", () => {
describe("returns true if only the specified values are shallowly equal", () => {
runTest(true, { a: 1 }, { a: 1 }, ["a"]);
runTest(true, { a: 1, b: true }, { a: 1, b: false }, ["a"]);
runTest(true, { a: 1, b: true }, { a: 1, b: false }, []);
runTest(true, { a: 1 }, { a: 1 }, ["a", "b", "c", "d"]);
runTest(true, { a: 1, b: [1, 2, 3], c: "3" }, { b: [1, 2, 3], a: 1, c: "3" }, ["a", "c"]);
runTest(true, { a: 1, b: "2", c: { a: 1 }}, { a: 1, b: "2", c: { a: 1 }}, ["a", "b"]);
});

describe("returns false if any specified values are not shallowly equal", () => {
runTest(false, { a: [1, "2", true] }, { a: [1, "2", true] }, ["a"]);
runTest(false, { a: 1, b: "2", c: {}}, { a: 1, b: "2", c: {}}, ["a", "b", "c"]);
runTest(false, { a: 1, b: "2", c: {}}, { a: 1, b: "2", c: {}}, ["a", "b", "c"]);
runTest(false, { a: 1, b: "2", c: { a: 1 }}, { a: 1, b: "2", c: { a: 1 }}, ["a", "b", "c"]);
});

describe("edge cases that return true", () => {
runTest(true, undefined, undefined, []);
runTest(true, undefined, undefined, ["a"]);
runTest(true, null, null, []);
runTest(true, null, null, ["a"]);
runTest(true, {}, {}, []);
runTest(true, {}, {}, ["a"]);
});

describe("edge cases that return false", () => {
runTest(false, undefined, null, []);
runTest(false, null, {}, []);
runTest(false, {}, [], []);
});

function runTest(expectedResult: boolean, a: any, b: any, keys: string[]) {
it(`${JSON.stringify(a)} and ${JSON.stringify(b)} (keys: ${JSON.stringify(keys)})`, () => {
expect(Utils.shallowCompareKeys(a, b, keys)).to.equal(expectedResult);
});
}
});

describe("shallowCompare", () => {
describe("returns true if values are shallowly equal", () => {
runTest(true, { a: 1, b: "2", c: true}, { a: 1, b: "2", c: true});
runTest(true, {}, {});
runTest(true, null, null);
runTest(true, undefined, undefined);
});

describe("returns false if values are not shallowly equal", () => {
runTest(false, undefined, null);
runTest(false, null, {});
runTest(false, {}, []);
runTest(false, { a: [1, "2", true] }, { a: [1, "2", true] });
runTest(false, { a: 1, b: "2", c: {}}, { a: 1, b: "2", c: {}});
runTest(false, { a: 1, b: "2", c: {}}, { a: 1, b: "2", c: {}});
runTest(false, { a: 1, b: "2", c: { a: 1 }}, { a: 1, b: "2", c: { a: 1 }});
});

describe("returns false if keys are different", () => {
runTest(false, {}, { a: 1 });
runTest(false, { a: 1 }, {});
runTest(false, { a: 1, b: "2" }, { b: "2" });
runTest(false, { b: "2" }, { a: 1, b: "2" });
runTest(false, { a: 1, b: "2", c: true}, { b: "2", c: true, d: 3 });
});

describe("returns true if same deeply-comparable instance is reused in both objects", () => {
const deeplyComparableThing1 = { a: 1 };
const deeplyComparableThing2 = [1, "2", true];
runTest(true, { a: 1, b: deeplyComparableThing1 }, { a: 1, b: deeplyComparableThing1 });
runTest(true, { a: 1, b: deeplyComparableThing2 }, { a: 1, b: deeplyComparableThing2 });
});

function runTest(expectedResult: boolean, a: any, b: any) {
it(`${JSON.stringify(a)} and ${JSON.stringify(b)}`, () => {
expect(Utils.shallowCompare(a, b)).to.equal(expectedResult);
});
}
});
});

0 comments on commit 771bdd1

Please sign in to comment.