From ab4643b59d4e011c9233c1090385d17b31727721 Mon Sep 17 00:00:00 2001 From: Drew Smith Date: Wed, 28 Jun 2017 10:47:41 -0500 Subject: [PATCH 1/3] fix(graphite): added Object key sort prior to JSON.stringify comparison close #5908 --- src/shared/util.js | 19 +++++++- test/unit/modules/shared/key-sort.spec.js | 55 +++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/unit/modules/shared/key-sort.spec.js diff --git a/src/shared/util.js b/src/shared/util.js index 8fbb1b812c8..53b7be931d5 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -17,6 +17,23 @@ export function isTrue (v: any): boolean %checks { export function isFalse (v: any): boolean %checks { return v === false } + +/** + * Sorts an object by key to ensure seraialized equality + * by succinct key order. Guaranteed to at least return an + * empty object. + */ +export function keySort (obj: Object): Object { + if (isObject(obj) === false) { + return {} + } + const sorted = {} + Object.keys(obj).sort().forEach(key => { + sorted[key] = obj[key] + }) + return sorted +} + /** * Check if value is primitive */ @@ -240,7 +257,7 @@ export function looseEqual (a: mixed, b: mixed): boolean { const isObjectB = isObject(b) if (isObjectA && isObjectB) { try { - return JSON.stringify(a) === JSON.stringify(b) + return JSON.stringify(keySort(a)) === JSON.stringify(keySort(b)) } catch (e) { // possible circular reference return a === b diff --git a/test/unit/modules/shared/key-sort.spec.js b/test/unit/modules/shared/key-sort.spec.js new file mode 100644 index 00000000000..e4ce1b72d75 --- /dev/null +++ b/test/unit/modules/shared/key-sort.spec.js @@ -0,0 +1,55 @@ +import { keySort, looseEqual } from 'shared/util' + +describe('keySort', () => { + const chars = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()_+./' + const randomWord = () => { + const letters = [] + for (let cnt = 0; cnt < 10; cnt++) { + letters.push(chars.charAt(Math.floor(Math.random() * chars.length))) + } + return letters.join('') + } + const unsortedObject = () => { + const unsorted = {} + chars.split('').map(c => { + unsorted[c + '' + randomWord()] = randomWord() + }) + return unsorted + } + + it('returns Object for empty Object argument', () => { + expect(looseEqual(keySort({}), {})).toBe(true) + }) + + it('returns Object for Array argument', () => { + expect(looseEqual(keySort([]), {})).toBe(true) + }) + + it('returns Object for String argument', () => { + expect(looseEqual(keySort('Test String'), {})).toBe(true) + }) + + it('returns Object for Number argument', () => { + expect(looseEqual(keySort(Number.MAX_SAFE_INTEGER), {})).toBe(true) + }) + + it('returns Object for Undefined argument', () => { + expect(looseEqual(keySort(undefined), {})).toBe(true) + }) + + it('returns Object for Null argument', () => { + expect(looseEqual(keySort(null), {})).toBe(true) + }) + + it('Sorts an unsorted Object, which are equal', () => { + const unsortedTestObj = unsortedObject() + const sortedObject = keySort(unsortedTestObj) + expect(looseEqual(sortedObject, sortedObject)).toBe(true) + }) + + it('does not unsort a sorted object', () => { + const sortedObject = keySort(unsortedObject()) + const sortedObjectCompare = keySort(sortedObject) + expect(looseEqual(sortedObject, sortedObjectCompare)).toBe(true) + }) +}) From fca0f0c570e503e0d4066b992d1094cbff6ccfa9 Mon Sep 17 00:00:00 2001 From: Drew Smith Date: Wed, 28 Jun 2017 11:15:23 -0500 Subject: [PATCH 2/3] fix(graphite): changed argument type to passify mixed #5908 --- src/shared/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/util.js b/src/shared/util.js index 53b7be931d5..cc27940c0f5 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -23,7 +23,7 @@ export function isFalse (v: any): boolean %checks { * by succinct key order. Guaranteed to at least return an * empty object. */ -export function keySort (obj: Object): Object { +export function keySort (obj: any): Object { if (isObject(obj) === false) { return {} } From 1a08c30193cd612b16c9fcd6974524dc726ffbe1 Mon Sep 17 00:00:00 2001 From: Drew Smith Date: Wed, 28 Jun 2017 12:06:40 -0500 Subject: [PATCH 3/3] fixed spec typo --- test/unit/modules/shared/key-sort.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/modules/shared/key-sort.spec.js b/test/unit/modules/shared/key-sort.spec.js index e4ce1b72d75..ec865fa098e 100644 --- a/test/unit/modules/shared/key-sort.spec.js +++ b/test/unit/modules/shared/key-sort.spec.js @@ -44,7 +44,7 @@ describe('keySort', () => { it('Sorts an unsorted Object, which are equal', () => { const unsortedTestObj = unsortedObject() const sortedObject = keySort(unsortedTestObj) - expect(looseEqual(sortedObject, sortedObject)).toBe(true) + expect(looseEqual(sortedObject, unsortedTestObj)).toBe(true) }) it('does not unsort a sorted object', () => {