From 183637b87f928c3d62991de764d15228f1a19338 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Tue, 10 Nov 2020 17:34:31 +0200 Subject: [PATCH] Add tests and clean up resolveObjectKey helper (#8028) * Add tests and clean up resolveObjectKey helper * Change the optimized path to comply with thests --- src/helpers/helpers.core.js | 18 ++++--- test/specs/helpers.core.tests.js | 83 ++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/helpers/helpers.core.js b/src/helpers/helpers.core.js index 89bf473bd..7066e578e 100644 --- a/src/helpers/helpers.core.js +++ b/src/helpers/helpers.core.js @@ -274,17 +274,21 @@ export function _deprecated(scope, value, previous, current) { } export function resolveObjectKey(obj, key) { - if (key.length < 3) { - return obj[key]; + // Special cases for `x` and `y` keys. It's quite a lot faster to aceess this way. + // Those are the default keys Chart.js is resolving, so it makes sense to be fast. + if (key === 'x') { + return obj.x; + } + if (key === 'y') { + return obj.y; } const keys = key.split('.'); - for (let i = 0, n = keys.length; i < n; ++i) { + for (let i = 0, n = keys.length; i < n && obj; ++i) { const k = keys[i]; - if (k in obj) { - obj = obj[k]; - } else { - return; + if (!k) { + break; } + obj = obj[k]; } return obj; } diff --git a/test/specs/helpers.core.tests.js b/test/specs/helpers.core.tests.js index 0f38613f1..b491686f8 100644 --- a/test/specs/helpers.core.tests.js +++ b/test/specs/helpers.core.tests.js @@ -374,4 +374,87 @@ describe('Chart.helpers.core', function() { expect(output.o.a).not.toBe(a1); }); }); + + describe('resolveObjectKey', function() { + it('should resolve empty key to root object', function() { + const obj = {test: true}; + expect(helpers.resolveObjectKey(obj, '')).toEqual(obj); + }); + it('should resolve one level', function() { + const obj = { + bool: true, + str: 'test', + int: 42, + obj: {name: 'object'} + }; + expect(helpers.resolveObjectKey(obj, 'bool')).toEqual(true); + expect(helpers.resolveObjectKey(obj, 'str')).toEqual('test'); + expect(helpers.resolveObjectKey(obj, 'int')).toEqual(42); + expect(helpers.resolveObjectKey(obj, 'obj')).toEqual(obj.obj); + }); + it('should resolve multiple levels', function() { + const obj = { + child: { + level: 1, + child: { + level: 2, + child: { + level: 3 + } + } + } + }; + expect(helpers.resolveObjectKey(obj, 'child.level')).toEqual(1); + expect(helpers.resolveObjectKey(obj, 'child.child.level')).toEqual(2); + expect(helpers.resolveObjectKey(obj, 'child.child.child.level')).toEqual(3); + }); + it('should resolve circular reference', function() { + const root = {}; + const child = {root}; + child.child = child; + root.child = child; + expect(helpers.resolveObjectKey(root, 'child')).toEqual(child); + expect(helpers.resolveObjectKey(root, 'child.child.child.child.child.child')).toEqual(child); + expect(helpers.resolveObjectKey(root, 'child.child.root')).toEqual(root); + }); + it('should break at empty key', function() { + const obj = { + child: { + level: 1, + child: { + level: 2, + child: { + level: 3 + } + } + } + }; + expect(helpers.resolveObjectKey(obj, 'child..level')).toEqual(obj.child); + expect(helpers.resolveObjectKey(obj, 'child.child.level...')).toEqual(2); + expect(helpers.resolveObjectKey(obj, '.')).toEqual(obj); + expect(helpers.resolveObjectKey(obj, '..')).toEqual(obj); + }); + it('should resolve undefined', function() { + const obj = { + child: { + level: 1, + child: { + level: 2, + child: { + level: 3 + } + } + } + }; + expect(helpers.resolveObjectKey(obj, 'level')).toEqual(undefined); + expect(helpers.resolveObjectKey(obj, 'child.level.a')).toEqual(undefined); + }); + it('should throw on invalid input', function() { + expect(() => helpers.resolveObjectKey(undefined, undefined)).toThrow(); + expect(() => helpers.resolveObjectKey({}, null)).toThrow(); + expect(() => helpers.resolveObjectKey({}, false)).toThrow(); + expect(() => helpers.resolveObjectKey({}, true)).toThrow(); + expect(() => helpers.resolveObjectKey({}, 1)).toThrow(); + }); + }); }); -- 2.47.2