]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add tests and clean up resolveObjectKey helper (#8028)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Tue, 10 Nov 2020 15:34:31 +0000 (17:34 +0200)
committerGitHub <noreply@github.com>
Tue, 10 Nov 2020 15:34:31 +0000 (17:34 +0200)
* Add tests and clean up resolveObjectKey helper

* Change the optimized path to comply with thests

src/helpers/helpers.core.js
test/specs/helpers.core.tests.js

index 89bf473bd2a6c3278973b24e40de2372d7a7d320..7066e578ee8905ebde38c6a6a052d788929ba228 100644 (file)
@@ -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;
 }
index 0f38613f1c2cb377ff2ec42ba99c587c8a68f557..b491686f804e73a02eff0c379482a592c7c63fe9 100644 (file)
@@ -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();
+               });
+       });
 });