Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deep set & map comparison #251

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions src/calculateDeepEqualDiffs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
isError,
isFunction,
isSet,
isMap,
has,
uniq,
} from 'lodash';
Expand Down Expand Up @@ -75,17 +76,78 @@ function accumulateDeepEqualDiffs(a, b, diffsAccumulator, pathString = '', { det
}

if (isSet(a) && isSet(b)) {
if (a.size !== b.size) {
const setLength = a.size;
if (setLength !== b.size) {
return trackDiff(new Set(a), new Set(b), diffsAccumulator, pathString, diffTypes.different);
}

for (const valA of a) {
if (!b.has(valA)) {
return trackDiff(new Set(a), new Set(b), diffsAccumulator, pathString, diffTypes.different);
const setItemDiffs = [];
let numberOfDeepEqualsValues = 0;
const aValues = [...a.values()];
const bValues = [...b.values()];
for (let i = setLength; i--; i > 0) {
const diffEquals = accumulateDeepEqualDiffs(aValues[i], bValues[i], setItemDiffs, `${pathString}.values()[${i}]`, { detailed });
if (diffEquals) {
numberOfDeepEqualsValues++;
}
}

if (detailed || numberOfDeepEqualsValues !== setLength) {
diffsAccumulator.push(...setItemDiffs);
}

if (numberOfDeepEqualsValues === setLength) {
return trackDiff(new Set(a), new Set(b), diffsAccumulator, pathString, diffTypes.deepEquals);
}

return trackDiff(new Set(a), new Set(b), diffsAccumulator, pathString, diffTypes.different);
}

if (isMap(a) && isMap(b)) {
const mapLength = a.size;
if (mapLength !== b.size) {
return trackDiff(new Map(a), new Map(b), diffsAccumulator, pathString, diffTypes.different);
}

const mapKeysDiffs = [];
let numberOfDeepEqualsKeys = 0;
const aKeys = [...a.keys()];
const bKeys = [...b.keys()];
for (let i = mapLength; i--; i > 0) {
const diffEquals = accumulateDeepEqualDiffs(aKeys[i], bKeys[i], mapKeysDiffs, `${pathString}.keys()[${i}]`, { detailed });
if (diffEquals) {
numberOfDeepEqualsKeys++;
}
}

return trackDiff(new Set(a), new Set(b), diffsAccumulator, pathString, diffTypes.deepEquals);
if (detailed || numberOfDeepEqualsKeys !== mapLength) {
diffsAccumulator.push(...mapKeysDiffs);
}

if (numberOfDeepEqualsKeys !== mapLength) {
return trackDiff(new Map(a), new Map(b), diffsAccumulator, pathString, diffTypes.different);
}

const mapValuesDiffs = [];
let numberOfDeepEqualsValues = 0;
const aValues = [...a.values()];
const bValues = [...b.values()];
for (let i = mapLength; i--; i > 0) {
const diffEquals = accumulateDeepEqualDiffs(aValues[i], bValues[i], mapValuesDiffs, `${pathString}.values()[${i}]`, { detailed });
if (diffEquals) {
numberOfDeepEqualsValues++;
}
}

if (detailed || numberOfDeepEqualsValues !== mapLength) {
diffsAccumulator.push(...mapValuesDiffs);
}

if (numberOfDeepEqualsValues === mapLength) {
return trackDiff(new Map(a), new Map(b), diffsAccumulator, pathString, diffTypes.deepEquals);
}

return trackDiff(new Map(a), new Map(b), diffsAccumulator, pathString, diffTypes.different);
}

if (isDate(a) && isDate(b)) {
Expand Down Expand Up @@ -140,7 +202,7 @@ function accumulateDeepEqualDiffs(a, b, diffsAccumulator, pathString = '', { det
if (typeof a === 'object' && typeof b === 'object' && Object.getPrototypeOf(a) === Object.getPrototypeOf(b)) {
const aKeys = Object.getOwnPropertyNames(a);
const bKeys = Object.getOwnPropertyNames(b);

const allKeys = uniq([...aKeys, ...bKeys]);

const clonedA = isPlainObject(a) ? { ...a } : a;
Expand Down
90 changes: 87 additions & 3 deletions tests/calculateDeepEqualDiffs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,22 +423,106 @@ test('sets', () => {
a: new Set(['a']),
b: new Set(['a', 1]),
c: new Set(['a', 1]),
d: new Set([{ foo: 'bar' }]),
};

const nextValue = {
a: new Set(['a']),
b: new Set(['a', 2]),
c: new Set(['a', 1, 'c']),
d: new Set([{ foo: 'bar' }]),
};

const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '.d',
prevValue: prevValue.d,
nextValue: nextValue.d,
diffType: diffTypes.deepEquals,
},
{
pathString: '.c',
prevValue: prevValue.c,
nextValue: nextValue.c,
diffType: diffTypes.different,
},
{
pathString: '.b.values()[1]',
prevValue: [...prevValue.b.values()][1],
nextValue: [...nextValue.b.values()][1],
diffType: diffTypes.different,
},
{
pathString: '.b',
prevValue: prevValue.b,
nextValue: nextValue.b,
diffType: diffTypes.different,
},
{
pathString: '.a',
prevValue: prevValue.a,
nextValue: nextValue.a,
diffType: diffTypes.deepEquals,
},
{
pathString: '',
prevValue: prevValue,
nextValue: nextValue,
diffType: diffTypes.different,
},
]);
});

test('maps', () => {
const prevValue = {
a: new Map([['a', 'b']]),
b: new Map([['a', 'b'], [1, 2]]),
c: new Map([['a', 'b'], [1, 2]]),
d: new Map([[{ foo: 'bar' }, { bar: 'foo' }]]),
e: new Map([['a', 'b']]),
};

const nextValue = {
a: new Map([['a', 'b']]),
b: new Map([['a', 'b'], [2, 2]]),
c: new Map([['a', 'b'], [1, 2], ['c', 3]]),
d: new Map([[{ foo: 'bar' }, { bar: 'foo' }]]),
e: new Map([['a', 'e']]),
};

const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
expect(diffs).toEqual([
{
pathString: '.e.values()[0]',
prevValue: [...prevValue.e.values()][0],
nextValue: [...nextValue.e.values()][0],
diffType: diffTypes.different,
},
{
pathString: '.e',
prevValue: prevValue.e,
nextValue: nextValue.e,
diffType: diffTypes.different,
},
{
pathString: '.d',
prevValue: prevValue.d,
nextValue: nextValue.d,
diffType: diffTypes.deepEquals,
},
{
pathString: '.c',
prevValue: prevValue.c,
nextValue: nextValue.c,
diffType: diffTypes.different,
},
{
pathString: '.b.keys()[1]',
prevValue: [...prevValue.b.keys()][1],
nextValue: [...nextValue.b.keys()][1],
diffType: diffTypes.different,
},
{
pathString: '.b',
prevValue: prevValue.b,
Expand Down Expand Up @@ -489,7 +573,7 @@ describe('calculateDeepEqualDiffs - Errors', () => {
},
]);
});

test('Different Native Errors', () => {
const prevValue = new Error('message');
const nextValue = new Error('Second message');
Expand Down Expand Up @@ -568,7 +652,7 @@ test('Equal class instances', () => {
this.name = name;
}
}

const prevValue = new Person('Jon Snow');
const nextValue = new Person('Jon Snow');
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
Expand All @@ -588,7 +672,7 @@ test('Different class instances', () => {
this.name = name;
}
}

const prevValue = new Person('Jon Snow');
const nextValue = new Person('Aria Stark');
const diffs = calculateDeepEqualDiffs(prevValue, nextValue);
Expand Down
124 changes: 119 additions & 5 deletions tests/findObjectsDifferences.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ describe('findObjectsDifferences not shallow', () => {
});

test('For sets with same values', () => {
const prev = new Set([1, 2, 3]);
const next = new Set([1, 2, 3]);
const prev = new Set([1, 2, 3, { foo: 'bar' }]);
const next = new Set([1, 2, 3, { foo: 'bar' }]);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
expect(diffs).toEqual([{
pathString: '',
Expand All @@ -178,10 +178,30 @@ describe('findObjectsDifferences not shallow', () => {
});

test('For sets with different values', () => {
const prev = new Set([1, 2, 3]);
const next = new Set([4, 5, 6]);
const prevValues = [1, 2, 3];
const nextValues = [4, 5, 6];
const prev = new Set(prevValues);
const next = new Set(nextValues);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
expect(diffs).toEqual([
{
pathString: '.values()[2]',
diffType: diffTypes.different,
prevValue: prevValues[2],
nextValue: nextValues[2],
},
{
pathString: '.values()[1]',
diffType: diffTypes.different,
prevValue: prevValues[1],
nextValue: nextValues[1],
},
{
pathString: '.values()[0]',
diffType: diffTypes.different,
prevValue: prevValues[0],
nextValue: nextValues[0],
},
{
pathString: '',
diffType: diffTypes.different,
Expand All @@ -191,7 +211,7 @@ describe('findObjectsDifferences not shallow', () => {
]);
});

test('For sets with different value length', () => {
test('For sets with different length', () => {
const prev = new Set([1, 2, 3]);
const next = new Set([1, 2, 3, 4]);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
Expand All @@ -204,4 +224,98 @@ describe('findObjectsDifferences not shallow', () => {
},
]);
});

test('For maps with same entries', () => {
const prev = new Map([[1, 'a'], [2, 'b'], [3, 'c'], [{ foo: 'bar' }, { bar: 'foo' }]]);
const next = new Map([[1, 'a'], [2, 'b'], [3, 'c'], [{ foo: 'bar' }, { bar: 'foo' }]]);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
expect(diffs).toEqual([{
pathString: '',
diffType: diffTypes.deepEquals,
prevValue: prev,
nextValue: next,
}]);
});

test('For maps with different keys', () => {
const prevEntries = [[1, ''], [2, ''], [3, '']];
const nextEntries = [[4, ''], [5, ''], [6, '']];
const prev = new Map(prevEntries);
const next = new Map(nextEntries);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
expect(diffs).toEqual([
{
pathString: '.keys()[2]',
diffType: diffTypes.different,
prevValue: prevEntries[2][0],
nextValue: nextEntries[2][0],
},
{
pathString: '.keys()[1]',
diffType: diffTypes.different,
prevValue: prevEntries[1][0],
nextValue: nextEntries[1][0],
},
{
pathString: '.keys()[0]',
diffType: diffTypes.different,
prevValue: prevEntries[0][0],
nextValue: nextEntries[0][0],
},
{
pathString: '',
diffType: diffTypes.different,
prevValue: prev,
nextValue: next,
},
]);
});

test('For maps with different values', () => {
const prevEntries = [[1, 'a'], [2, 'b'], [3, 'c']];
const nextEntries = [[1, 'd'], [2, 'e'], [3, 'f']];
const prev = new Map(prevEntries);
const next = new Map(nextEntries);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
expect(diffs).toEqual([
{
pathString: '.values()[2]',
diffType: diffTypes.different,
prevValue: prevEntries[2][1],
nextValue: nextEntries[2][1],
},
{
pathString: '.values()[1]',
diffType: diffTypes.different,
prevValue: prevEntries[1][1],
nextValue: nextEntries[1][1],
},
{
pathString: '.values()[0]',
diffType: diffTypes.different,
prevValue: prevEntries[0][1],
nextValue: nextEntries[0][1],
},
{
pathString: '',
diffType: diffTypes.different,
prevValue: prev,
nextValue: next,
},
]);
});

test('For maps with different length', () => {
const prev = new Map([[1, 1], [2, 2], [3, 3]]);
const next = new Map([[1, 1], [2, 2], [3, 3], [4, 4]]);
const diffs = findObjectsDifferences(prev, next, { shallow: false });
expect(diffs).toEqual([
{
pathString: '',
diffType: diffTypes.different,
prevValue: prev,
nextValue: next,
},
]);
});
});