From 5510e1af1ae12aacb3759c7da96d58fb0f9f8f22 Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Thu, 27 Aug 2020 14:39:56 -0700 Subject: [PATCH 01/10] fix(src/plugins/utils/findOctetSequencePaths.js): Show path to erring element on exception Recently, I ran across an issue where [if the validator throws an exception in a specific part of the code, the path to the exception-causing code is swallowed](https://github.com/IBM/openapi-validator/issues/180). After a moderate amount of digging, I decided that an option for providing more information about this code would be to put the path to the problematic element or elements into the exception message. This exception message is displayed whenever the code crashes out. So, for example, the previous error message output by lint-openapi would say "Cannot read property 'type' of null", whereas the new error would list the full path to the type that was causing the exception. re #180 --- src/plugins/utils/findOctetSequencePaths.js | 36 +++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/plugins/utils/findOctetSequencePaths.js b/src/plugins/utils/findOctetSequencePaths.js index caf255c05..570de7329 100644 --- a/src/plugins/utils/findOctetSequencePaths.js +++ b/src/plugins/utils/findOctetSequencePaths.js @@ -35,12 +35,36 @@ function arrayOctetSequences(resolvedSchema, path) { const pathToSchema = Array.isArray(path) ? path.concat('items') : `${path}.items`; - if (arrayItems.type === 'string' && arrayItems.format === 'binary') { - arrayPathsToOctetSequence.push(pathToSchema); - } else if (arrayItems.type === 'object' || arrayItems.type === 'array') { - arrayPathsToOctetSequence.push( - ...findOctetSequencePaths(arrayItems, pathToSchema) - ); + try { + if (arrayItems.type === 'string' && arrayItems.format === 'binary') { + arrayPathsToOctetSequence.push(pathToSchema); + } else if (arrayItems.type === 'object' || arrayItems.type === 'array') { + arrayPathsToOctetSequence.push( + ...findOctetSequencePaths(arrayItems, pathToSchema) + ); + } + } catch(err) { + if (err instanceof TypeError) { + var escapedPaths = []; + const strEscaper = function(strToEscape) { + var newStr = ""; + for (i=0;i Date: Thu, 8 Oct 2020 15:05:00 -0700 Subject: [PATCH 02/10] More standard quoting practice. --- src/plugins/utils/findOctetSequencePaths.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/utils/findOctetSequencePaths.js b/src/plugins/utils/findOctetSequencePaths.js index 570de7329..b513b3353 100644 --- a/src/plugins/utils/findOctetSequencePaths.js +++ b/src/plugins/utils/findOctetSequencePaths.js @@ -6,7 +6,7 @@ // the path both as an array and a string and returns the path in the same // format received: // typeof(path) === 'array' => [[path1, get], [path2, get], ...] -// typeof(path) === 'string' => ['path1.get', path2.get, ...] +// typeof(path) === 'string' => ['path1.get', 'path2.get', ...] const findOctetSequencePaths = (resolvedSchema, path) => { if (!resolvedSchema) { @@ -47,10 +47,10 @@ function arrayOctetSequences(resolvedSchema, path) { if (err instanceof TypeError) { var escapedPaths = []; const strEscaper = function(strToEscape) { - var newStr = ""; + var newStr = ''; for (i=0;i Date: Thu, 8 Oct 2020 15:33:24 -0700 Subject: [PATCH 03/10] First run at some tests for this. --- .../utils/find-octet-sequence-paths.test.js | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 test/plugins/utils/find-octet-sequence-paths.test.js diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js new file mode 100644 index 000000000..c48b15c58 --- /dev/null +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -0,0 +1,63 @@ +const expect = require('expect'); +const findOctetSequencePaths = require('../../../src/plugins/utils/findOctetSequencePaths').findOctetSequencePaths; + +function arrayEquals(a, b) { + return Array.isArray(a) && + Array.isArray(b) && + a.length === b.length && + a.every((val, index) => val === b[index]); +}; + +describe('falsy values should return an empty array', function() { + describe('undefined should return an empty array', function() { + it('undefined is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(undefined, []), [])); + }); + }); + + describe('null should return an empty array', function() { + it('null is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(null, []), [])); + }); + }); + + describe('NaN should return an empty array', function() { + it('NaN is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(NaN, []), [])); + }); + }); + + describe('0 should return an empty array', function() { + it('0 is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(0, []), [])); + }); + }); + + describe('The Empty String should return an empty array', function() { + it('The Empty String is falsy', function() { + expect(arrayEquals(findOctetSequencePaths('', []), [])); + }); + }); + + describe('false should return an empty array', function() { + it('false is falsy', function() { + expect(findOctetSequencePaths(false, [])).toEqual([]); + }); + }); +}); + +describe('binary format string schemas should return the passed path', function() { + describe('binary format strings should include the path in string form', function() { + it('should return an array with string elements', function() { + const schemaObj = {'type': 'string', 'format': 'binary'}; + const path = ['path1.get']; + + expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); + }); + }); +}); + +describe('array-type schemas must extract values from the resolved schema', function() { + describe('', function() {}); +}); + From 952dcb79057310e81789b28fec29a92bda9b7c00 Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Thu, 8 Oct 2020 16:03:48 -0700 Subject: [PATCH 04/10] Style changes. --- src/plugins/utils/findOctetSequencePaths.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plugins/utils/findOctetSequencePaths.js b/src/plugins/utils/findOctetSequencePaths.js index b513b3353..bb283411a 100644 --- a/src/plugins/utils/findOctetSequencePaths.js +++ b/src/plugins/utils/findOctetSequencePaths.js @@ -43,12 +43,12 @@ function arrayOctetSequences(resolvedSchema, path) { ...findOctetSequencePaths(arrayItems, pathToSchema) ); } - } catch(err) { + } catch (err) { if (err instanceof TypeError) { - var escapedPaths = []; + let escapedPaths = []; const strEscaper = function(strToEscape) { - var newStr = ''; - for (i=0;i Date: Thu, 8 Oct 2020 16:14:38 -0700 Subject: [PATCH 05/10] Style changes. --- src/plugins/utils/findOctetSequencePaths.js | 8 +- .../utils/find-octet-sequence-paths.test.js | 75 +++++++++---------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/plugins/utils/findOctetSequencePaths.js b/src/plugins/utils/findOctetSequencePaths.js index bb283411a..bb5608e9d 100644 --- a/src/plugins/utils/findOctetSequencePaths.js +++ b/src/plugins/utils/findOctetSequencePaths.js @@ -45,7 +45,7 @@ function arrayOctetSequences(resolvedSchema, path) { } } catch (err) { if (err instanceof TypeError) { - let escapedPaths = []; + const escapedPaths = []; const strEscaper = function(strToEscape) { let newStr = ''; for (let i = 0; i < strToEscape.length; i++) { @@ -58,9 +58,11 @@ function arrayOctetSequences(resolvedSchema, path) { escapedPaths.push(newStr); }; path.forEach(strEscaper); - let e = new TypeError('items.type and items.format must resolve for the path "' + + const e = new TypeError( + 'items.type and items.format must resolve for the path "' + escapedPaths.join('/') + - '"'); + '"' + ); e.stack = err.stack; e.original = err; throw e; diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js index c48b15c58..5bc22c28f 100644 --- a/test/plugins/utils/find-octet-sequence-paths.test.js +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -2,62 +2,61 @@ const expect = require('expect'); const findOctetSequencePaths = require('../../../src/plugins/utils/findOctetSequencePaths').findOctetSequencePaths; function arrayEquals(a, b) { - return Array.isArray(a) && - Array.isArray(b) && - a.length === b.length && - a.every((val, index) => val === b[index]); + return Array.isArray(a) && + Array.isArray(b) && + a.length === b.length && + a.every((val, index) => val === b[index]); }; describe('falsy values should return an empty array', function() { - describe('undefined should return an empty array', function() { - it('undefined is falsy', function() { - expect(arrayEquals(findOctetSequencePaths(undefined, []), [])); - }); + describe('undefined should return an empty array', function() { + it('undefined is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(undefined, []), [])); }); + }); - describe('null should return an empty array', function() { - it('null is falsy', function() { - expect(arrayEquals(findOctetSequencePaths(null, []), [])); - }); + describe('null should return an empty array', function() { + it('null is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(null, []), [])); }); + }); - describe('NaN should return an empty array', function() { - it('NaN is falsy', function() { - expect(arrayEquals(findOctetSequencePaths(NaN, []), [])); - }); + describe('NaN should return an empty array', function() { + it('NaN is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(NaN, []), [])); }); + }); - describe('0 should return an empty array', function() { - it('0 is falsy', function() { - expect(arrayEquals(findOctetSequencePaths(0, []), [])); - }); + describe('0 should return an empty array', function() { + it('0 is falsy', function() { + expect(arrayEquals(findOctetSequencePaths(0, []), [])); }); + }); - describe('The Empty String should return an empty array', function() { - it('The Empty String is falsy', function() { - expect(arrayEquals(findOctetSequencePaths('', []), [])); - }); + describe('The Empty String should return an empty array', function() { + it('The Empty String is falsy', function() { + expect(arrayEquals(findOctetSequencePaths('', []), [])); }); + }); - describe('false should return an empty array', function() { - it('false is falsy', function() { - expect(findOctetSequencePaths(false, [])).toEqual([]); - }); + describe('false should return an empty array', function() { + it('false is falsy', function() { + expect(findOctetSequencePaths(false, [])).toEqual([]); }); + }); }); describe('binary format string schemas should return the passed path', function() { - describe('binary format strings should include the path in string form', function() { - it('should return an array with string elements', function() { - const schemaObj = {'type': 'string', 'format': 'binary'}; - const path = ['path1.get']; - - expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); - }); - }); + describe('binary format strings should include the path in string form', function() { + it('should return an array with string elements', function() { + const schemaObj = {'type': 'string', 'format': 'binary'}; + const path = ['path1.get']; + + expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); + }); + }); }); describe('array-type schemas must extract values from the resolved schema', function() { - describe('', function() {}); + describe('', function() {}); }); - From 5e60216d9eb68ebd91638f1b54293162ed804d4b Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Thu, 8 Oct 2020 16:20:54 -0700 Subject: [PATCH 06/10] Style changes. --- .../utils/find-octet-sequence-paths.test.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js index 5bc22c28f..2544cce24 100644 --- a/test/plugins/utils/find-octet-sequence-paths.test.js +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -1,12 +1,15 @@ const expect = require('expect'); -const findOctetSequencePaths = require('../../../src/plugins/utils/findOctetSequencePaths').findOctetSequencePaths; +const findOctetSequencePaths = require('../../../src/plugins/utils/findOctetSequencePaths') + .findOctetSequencePaths; function arrayEquals(a, b) { - return Array.isArray(a) && + return ( + Array.isArray(a) && Array.isArray(b) && a.length === b.length && - a.every((val, index) => val === b[index]); -}; + a.every((val, index) => val === b[index]) + ); +} describe('falsy values should return an empty array', function() { describe('undefined should return an empty array', function() { @@ -49,11 +52,11 @@ describe('falsy values should return an empty array', function() { describe('binary format string schemas should return the passed path', function() { describe('binary format strings should include the path in string form', function() { it('should return an array with string elements', function() { - const schemaObj = {'type': 'string', 'format': 'binary'}; - const path = ['path1.get']; + const schemaObj = {'type': 'string', 'format': 'binary'}; + const path = ['path1.get']; - expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); - }); + expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); + }); }); }); From 84b5a6794731199fca4cfc214c90e86bca07da6e Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Thu, 8 Oct 2020 16:24:15 -0700 Subject: [PATCH 07/10] Style Changes. --- test/plugins/utils/find-octet-sequence-paths.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js index 2544cce24..d398c8520 100644 --- a/test/plugins/utils/find-octet-sequence-paths.test.js +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -4,7 +4,7 @@ const findOctetSequencePaths = require('../../../src/plugins/utils/findOctetSequ function arrayEquals(a, b) { return ( - Array.isArray(a) && + Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((val, index) => val === b[index]) @@ -51,8 +51,8 @@ describe('falsy values should return an empty array', function() { describe('binary format string schemas should return the passed path', function() { describe('binary format strings should include the path in string form', function() { - it('should return an array with string elements', function() { - const schemaObj = {'type': 'string', 'format': 'binary'}; + it('should return an array with string elements', function() { + const schemaObj = {type: 'string', format: 'binary'}; const path = ['path1.get']; expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); From 8fdbc0d295a7fc4c55204dba639374eac04809b4 Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Thu, 8 Oct 2020 16:27:20 -0700 Subject: [PATCH 08/10] Style Changes. --- test/plugins/utils/find-octet-sequence-paths.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js index d398c8520..b327745cc 100644 --- a/test/plugins/utils/find-octet-sequence-paths.test.js +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -52,7 +52,7 @@ describe('falsy values should return an empty array', function() { describe('binary format string schemas should return the passed path', function() { describe('binary format strings should include the path in string form', function() { it('should return an array with string elements', function() { - const schemaObj = {type: 'string', format: 'binary'}; + const schemaObj = { type: 'string', format: 'binary' }; const path = ['path1.get']; expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); From fe48c78ca4181f94ae498388e385019d43dbde52 Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Thu, 8 Oct 2020 17:36:41 -0700 Subject: [PATCH 09/10] Cover object-type paths. --- .../utils/find-octet-sequence-paths.test.js | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js index b327745cc..eb9383d50 100644 --- a/test/plugins/utils/find-octet-sequence-paths.test.js +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -60,6 +60,35 @@ describe('binary format string schemas should return the passed path', function( }); }); -describe('array-type schemas must extract values from the resolved schema', function() { - describe('', function() {}); +describe('object-type schemas must extract values from the resolved schema', function() { + const schemaObj = { type: 'object' }; + const path = ['path1.get']; + it('falsy properties should not append to the path', function() { + schemaObj.properties = false; + + expect(arrayEquals(findOctetSequencePaths(schemaObj, path), path)); + }); + + it('truthy properties should be added to the octet paths', function() { + schemaObj.properties = { one: { type: 'string', format: 'binary' } }; + const expectedOut = ['path1.get', 'path1.get.properties.one']; + + expect(arrayEquals(findOctetSequencePaths(schemaObj, path), expectedOut)); + }); + + it('truthy properties should be recursively added to the octet paths', function() { + schemaObj.properties = { + one: { + type: 'object', + properties: { two: { type: 'string', format: 'binary' } } + } + }; + const expectedOut = [ + 'path1.get', + 'path1.get.properties.one', + 'path1.get.properties.one.properties.two' + ]; + + expect(arrayEquals(findOctetSequencePaths(schemaObj, path), expectedOut)); + }); }); From 54e7fa823eeb992b98b1012ddd43bc9788ba2755 Mon Sep 17 00:00:00 2001 From: Tom Kelley Date: Fri, 9 Oct 2020 09:50:17 -0700 Subject: [PATCH 10/10] Test throw/catch added in this change. --- .../utils/find-octet-sequence-paths.test.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/plugins/utils/find-octet-sequence-paths.test.js b/test/plugins/utils/find-octet-sequence-paths.test.js index eb9383d50..c67663436 100644 --- a/test/plugins/utils/find-octet-sequence-paths.test.js +++ b/test/plugins/utils/find-octet-sequence-paths.test.js @@ -92,3 +92,27 @@ describe('object-type schemas must extract values from the resolved schema', fun expect(arrayEquals(findOctetSequencePaths(schemaObj, path), expectedOut)); }); }); + +describe('array-type schemas require the proper values in proper fields', function() { + const schemaObj = { type: 'array', items: null }; + + it('should throw with a full path if the proper structure is not provided', function() { + const path = ['path1.get']; + + expect(function() { + findOctetSequencePaths(schemaObj, path); + }).toThrow( + 'items.type and items.format must resolve for the path "path1.get"' + ); + }); + + it('should escape forward-slashes in the path', function() { + const path = ['path1/get']; + + expect(function() { + findOctetSequencePaths(schemaObj, path); + }).toThrow( + 'items.type and items.format must resolve for the path "path1\\/get"' + ); + }); +});