From 6da18650413ce2a0a9f1ffe44fc6b2cee483adb0 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Wed, 16 Feb 2022 11:46:54 -0600 Subject: [PATCH 01/13] values like in validation Accept values like , etc. in validation --- lib/ajValidation/ajvValidation.js | 47 +++++++- test/data/31CollectionTransactions/479.yaml | 32 ++++++ .../data/31CollectionTransactions/479col.json | 105 ++++++++++++++++++ test/unit/x31schemapack.test.js | 21 ++++ test/unit/xajvValidation.test.js | 84 ++++++++++++++ 5 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 test/data/31CollectionTransactions/479.yaml create mode 100644 test/data/31CollectionTransactions/479col.json diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index bd80363..34b3f16 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -17,6 +17,45 @@ function isPmVariable (value) { return _.isString(value) && _.startsWith(value, '{{') && _.endsWith(value, '}}'); } +/** + * Checks if value is the representation of its type like: + * "" + * + * @param {string} value - Value to check for + * @param {string} type - The type in the schemna + * @returns {Boolean} the value is the representation of its type + */ +function compareType(value, type) { + return value === '<' + type + '>'; +} + +/** + * Checks if value is the representation of its type like: + * "" + * Works in array types + * @param {string} value - Value to check for + * @param {*} types - The types in the schemna + * @returns {Boolean} the value is the representation of its type + */ +function isTypeValueArrayCheck(value, types) { + return types.find((type) => { + return compareType(value, type); + }) !== undefined; +} + +/** + * Checks if value is the representation of its type like: + * "" + * Works in array types + * @param {string} value - Value to check for + * @param {*} types - The types in the schemna + * @returns {Boolean} the value is the representation of its type + */ +function isTypeValue(value, types) { + return Array.isArray(types) ? isTypeValueArrayCheck(value, types) : compareType(value, types); +} + + /** * returns the local $schema value * @@ -97,6 +136,11 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { isPmVariable(dataPath === '' ? valueToUse : _.get(valueToUse, dataPath))) { return false; } + + if (validationError.keyword === 'type') { + return !isTypeValue(_.get(valueToUse, dataPath), validationError.params.type); + } + return true; }); @@ -110,5 +154,6 @@ module.exports = { validateSchema, getLocalDraft, getAjvValidator, - getDraftToUse + getDraftToUse, + isTypeValue }; diff --git a/test/data/31CollectionTransactions/479.yaml b/test/data/31CollectionTransactions/479.yaml new file mode 100644 index 0000000..3b9acdf --- /dev/null +++ b/test/data/31CollectionTransactions/479.yaml @@ -0,0 +1,32 @@ +openapi: "3.1.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets/anyOf: + post: + summary: issue 479 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/example" + responses: + default: + description: ok +components: + schemas: + example: + type: + - object + properties: + id: + type: + - integer + hasPet: + type: + - boolean diff --git a/test/data/31CollectionTransactions/479col.json b/test/data/31CollectionTransactions/479col.json new file mode 100644 index 0000000..715c104 --- /dev/null +++ b/test/data/31CollectionTransactions/479col.json @@ -0,0 +1,105 @@ +{ + "item": [ + { + "id": "c3a2f66d-f91e-45ec-9116-4ce926acb630", + "name": "pets", + "item": [ + { + "id": "25758366-55ed-4370-90fd-1e1be8536b0b", + "name": "issue 479", + "request": { + "name": "composite schema with anyOf keyword", + "description": {}, + "url": { + "path": [ + "pets", + "anyOf" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [] + }, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "method": "POST", + "auth": null, + "body": { + "mode": "raw", + "raw": "{ \"id\": \"\", \"hasPet\": \"\" }", + "options": { + "raw": { + "language": "json" + } + } + } + }, + "response": [ + { + "id": "f4f6ddf5-d259-45b7-89fe-086cc22a6549", + "name": "ok", + "originalRequest": { + "url": { + "path": [ + "pets", + "anyOf" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [] + }, + "method": "POST", + "body": { + "mode": "raw", + "raw": "{ \"id\": \"\", \"hasPet\": \"\" }", + "options": { + "raw": { + "language": "json" + } + } + } + }, + "status": "Internal Server Error", + "code": 500, + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": "", + "cookie": [], + "_postman_previewlanguage": "text" + } + ], + "event": [] + } + ], + "event": [] + } + ], + "event": [], + "variable": [ + { + "type": "string", + "value": "http://petstore.swagger.io/v1", + "key": "baseUrl" + } + ], + "info": { + "_postman_id": "b498d8c3-e6e5-4a72-92de-e5c455786a8e", + "name": "Swagger Petstore", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": { + "content": "", + "type": "text/plain" + } + } +} diff --git a/test/unit/x31schemapack.test.js b/test/unit/x31schemapack.test.js index d1a3fcd..3a299fd 100644 --- a/test/unit/x31schemapack.test.js +++ b/test/unit/x31schemapack.test.js @@ -145,6 +145,27 @@ describe('Openapi 3.1 schema pack validateTransactions', function() { }); } + it('Fix for GITHUB#479: Should accept values like in validation', function() { + const collectionSource = path.join(__dirname, OPENAPI_31_COLLECTIONS + '/479col.json'), + collectionData = fs.readFileSync(collectionSource, 'utf8'), + schemaSource = path.join(__dirname, OPENAPI_31_COLLECTIONS + '/479.yaml'), + schemaData = fs.readFileSync(schemaSource, 'utf8'), + validator = new SchemaPack({ + type: 'string', + data: schemaData + }); + let transactions = []; + getAllTransactions(JSON.parse(collectionData), transactions); + + validator.validateTransaction(transactions, (err, result) => { + let requestIds = Object.keys(result.requests); + expect(err).to.be.null; + requestIds.forEach((requestId) => { + expect(result.requests[requestId].endpoints[0].matched).to.be.true; + }); + }); + }); + it('Should not generate any mismatch with a correct file', function() { const collectionSource = path.join(__dirname, OPENAPI_31_COLLECTIONS + '/compositeSchemaCollection.json'), collectionData = fs.readFileSync(collectionSource, 'utf8'), diff --git a/test/unit/xajvValidation.test.js b/test/unit/xajvValidation.test.js index 7daad7d..109401d 100644 --- a/test/unit/xajvValidation.test.js +++ b/test/unit/xajvValidation.test.js @@ -1,6 +1,7 @@ const { getLocalDraft, getAjvValidator, validateSchema, + isTypeValue, getDraftToUse } = require('../../lib/ajValidation/ajvValidation'), { validateSchemaAJVDraft04 } = require('../../lib/ajValidation/ajvValidatorDraft04'), expect = require('chai').expect; @@ -302,6 +303,61 @@ describe('validateSchema', function () { result = validateSchemaAJVDraft04(null, valueToUse); expect(result.filteredValidationError).to.be.undefined; }); + + it('Fix for GITHUB#479: should validate as correct input for type integer', function () { + const schema = { + type: 'object', + properties: { + id: { + type: [ + 'integer', + 'boolean' + ], + examples: [ + 111111 + ] + }, + hasPet: { + type: [ + 'boolean' + ] + } + } + }, + valueToUse = { + 'id': '', + 'hasPet': '' + }, + result = validateSchema(schema, valueToUse); + expect(result).to.be.empty; + }); + + it('Fix for GITHUB#479: should validate as incorrect input for type integer', function () { + const schema = { + type: 'object', + properties: { + id: { + type: [ + 'integer' + ], + examples: [ + 111111 + ] + }, + hasPet: { + type: [ + 'boolean' + ] + } + } + }, + valueToUse = { + 'id': '', + 'hasPet': '' + }, + result = validateSchema(schema, valueToUse); + expect(result[0].instancePath).equal('/id'); + }); }); describe('getDraftToUse', function() { @@ -326,3 +382,31 @@ describe('getDraftToUse', function() { expect(draftToUse).to.equal(undefined); }); }); + +describe('isTypeValue method', function () { + it('should return true when value is and type is integer', function () { + const result = isTypeValue('', ['integer']); + expect(result).to.be.true; + }); + + it('should return false when value is and type is boolean', function () { + const result = isTypeValue('', ['boolean']); + expect(result).to.be.false; + }); + + it('should return true when value is and type is string', function () { + const result = isTypeValue('', ['string']); + expect(result).to.be.true; + }); + + it('should return true when value is and type is ["boolean", "integer"]', function () { + const result = isTypeValue('', ['boolean', 'integer']); + expect(result).to.be.true; + }); + + it('should return true when value is and type is integer not array', function () { + const result = isTypeValue('', 'integer'); + expect(result).to.be.true; + }); + +}); From 01ed77adf281fb7279a1dcbddb400dd9bdbdb792 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Fri, 18 Feb 2022 14:20:15 -0600 Subject: [PATCH 02/13] WIP add support for more scenarios --- lib/ajValidation/ajvValidation.js | 95 +++++++++++++++++++++++- test/unit/xajvValidation.test.js | 115 ++++++++++++++++++++++++++++-- 2 files changed, 201 insertions(+), 9 deletions(-) diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index 34b3f16..b92cbd1 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -4,7 +4,36 @@ var _ = require('lodash'); const IGNORED_KEYWORDS = ['propertyNames', 'const', 'additionalItems', 'dependencies'], { validateSchemaAJV } = require('./ajvValidator'), { validateSchemaAJVDraft04 } = require('./ajvValidatorDraft04'), - specialDraft = 'http://json-schema.org/draft-04/schema#'; + specialDraft = 'http://json-schema.org/draft-04/schema#', + typesMap = { + integer: { + int32: '', + int64: '' + }, + number: { + float: '', + double: '' + }, + string: { + byte: '', + binary: '', + date: '', + 'date-time': '', + password: '' + }, + boolean: '' + }; + +/** + * Checks if value is postman variable or not + * + * @param {string} type - type to look for + * @param {string} format - format from schema + * @returns {Boolean} postman variable or not + */ +function getDefaultFromTypeAndFormat(type, format) { + return typesMap[type][format]; +} /** * Checks if value is postman variable or not @@ -51,10 +80,68 @@ function isTypeValueArrayCheck(value, types) { * @param {*} types - The types in the schemna * @returns {Boolean} the value is the representation of its type */ -function isTypeValue(value, types) { +function checkValueOnlyTypes(value, types) { return Array.isArray(types) ? isTypeValueArrayCheck(value, types) : compareType(value, types); } +/** + * Checks if value is the representation of its type like: + * "" + * Works in array types + * @param {string} value - Value to check for + * @param {*} types - The types in the schema + * @param {*} format - format from the schema + * @returns {Boolean} the value is the representation of its type + */ +function checkValueTypesAndFormat(value, types, format) { + let typesNotInMapp = [], + typesArray = Array.isArray(types) ? types : [types], + found = typesArray.find((type) => { + let defaultValue; + if (typesMap.hasOwnProperty(type)) { + defaultValue = getDefaultFromTypeAndFormat(type, format); + + // in case the format is a custom format (email, hostname etc.) + // https://swagger.io/docs/specification/data-models/data-types/#string + if (!defaultValue && format) { + defaultValue = '<' + format + '>'; + } + } + else { + typesNotInMapp.push(type); + } + return defaultValue === value; + }); + if (found) { + return true; + } + + found = typesNotInMapp.find((type) => { + let defaultValue; + defaultValue = '<' + type + (format ? ('-' + format) : '') + '>'; + return defaultValue === value; + }); + + return found !== undefined; +} + +/** + * Checks if value is the representation of its type like: + * "" + * Works in array types + * @param {string} value - Value to check for + * @param {*} schema - The schema portion used in validation + * @returns {Boolean} the value is the representation of its type + */ +function isTypeValue(value, schema) { + if (schema.hasOwnProperty('type') && !schema.hasOwnProperty('format')) { + return checkValueOnlyTypes(value, schema.type); + } + if (schema.hasOwnProperty('type') && schema.hasOwnProperty('format')) { + return checkValueTypesAndFormat(value, schema.type, schema.format); + } +} + /** * returns the local $schema value @@ -138,7 +225,9 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { } if (validationError.keyword === 'type') { - return !isTypeValue(_.get(valueToUse, dataPath), validationError.params.type); + let schemaToUse = schema.hasOwnProperty('properties') ? _.get(schema, 'properties.' + dataPath) : schema; + return !isTypeValue(_.get(valueToUse, dataPath), + schemaToUse); } return true; diff --git a/test/unit/xajvValidation.test.js b/test/unit/xajvValidation.test.js index 109401d..17f615a 100644 --- a/test/unit/xajvValidation.test.js +++ b/test/unit/xajvValidation.test.js @@ -358,6 +358,57 @@ describe('validateSchema', function () { result = validateSchema(schema, valueToUse); expect(result[0].instancePath).equal('/id'); }); + + it('Fix for GITHUB#479: should validate as correct input for type integer format int64', function () { + const schema = { + type: 'object', + properties: { + id: { + type: [ + 'integer' + ], + format: 'int64' + }, + hasPet: { + type: [ + 'boolean' + ] + } + } + }, + valueToUse = { + 'id': '', + 'hasPet': '' + }, + result = validateSchema(schema, valueToUse); + expect(result).to.be.empty; + }); + + it('Fix for GITHUB#479: should validate as correct input for type integer boolean format int64', function () { + const schema = { + type: 'object', + properties: { + id: { + type: [ + 'integer', + 'boolean' + ], + format: 'int64' + }, + hasPet: { + type: [ + 'boolean' + ] + } + } + }, + valueToUse = { + 'id': '', + 'hasPet': '' + }, + result = validateSchema(schema, valueToUse); + expect(result).to.be.empty; + }); }); describe('getDraftToUse', function() { @@ -385,27 +436,79 @@ describe('getDraftToUse', function() { describe('isTypeValue method', function () { it('should return true when value is and type is integer', function () { - const result = isTypeValue('', ['integer']); + const result = isTypeValue('', { + type: [ + 'integer' + ] + }); + expect(result).to.be.true; + }); + + it('should return true when input is type integer and format int64', function () { + const result = isTypeValue('', { + format: 'int64', + type: ['integer'] + }); + expect(result).to.be.true; + }); + + it('should return true when value is type is string format is uuid', function () { + const result = isTypeValue('', { + format: 'uuid', + type: ['string'] + }); + expect(result).to.be.true; + }); + + + it('should return true when value is type is otherType and there is not format', function () { + const result = isTypeValue('', { + type: ['otherType'] + }); + expect(result).to.be.true; + }); + + it('should return true value is type is otherType and format is otherFormat', function () { + const result = isTypeValue('', { + format: 'otherFormat', + type: ['otherType'] + }); expect(result).to.be.true; }); it('should return false when value is and type is boolean', function () { - const result = isTypeValue('', ['boolean']); + const result = isTypeValue('', { + type: ['boolean'] + }); expect(result).to.be.false; }); - it('should return true when value is and type is string', function () { - const result = isTypeValue('', ['string']); + it('should return true when value is and type is string', function () { + const result = isTypeValue('', { + type: ['string'] + }); expect(result).to.be.true; }); it('should return true when value is and type is ["boolean", "integer"]', function () { - const result = isTypeValue('', ['boolean', 'integer']); + const result = isTypeValue('', { + type: ['boolean', 'integer'] + }); expect(result).to.be.true; }); it('should return true when value is and type is integer not array', function () { - const result = isTypeValue('', 'integer'); + const result = isTypeValue('', { + type: 'integer' + }); + expect(result).to.be.true; + }); + + it('should return true when value is and type is integer not array format int64', function () { + const result = isTypeValue('', { + format: 'int64', + type: 'integer' + }); expect(result).to.be.true; }); From d283fd81da3d0fbdac832088a1a6dab25eef7b78 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 21 Feb 2022 11:47:46 -0600 Subject: [PATCH 03/13] Added support for reading schema with schemapath converted as datapath Added support for reading schema with schemapath converted as datapath --- lib/ajValidation/ajvValidation.js | 8 +++--- lib/common/schemaUtilsCommon.js | 40 ++++++++++++++++++++++++++--- test/unit/schemaUtilsCommon.test.js | 18 +++++++++++-- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index b92cbd1..7b6ee93 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -1,4 +1,4 @@ -const { formatDataPath } = require('../common/schemaUtilsCommon'); +const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../common/schemaUtilsCommon'); var _ = require('lodash'); const IGNORED_KEYWORDS = ['propertyNames', 'const', 'additionalItems', 'dependencies'], @@ -225,8 +225,10 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { } if (validationError.keyword === 'type') { - let schemaToUse = schema.hasOwnProperty('properties') ? _.get(schema, 'properties.' + dataPath) : schema; - return !isTypeValue(_.get(valueToUse, dataPath), + let schemaDataPath = formatDataPath(formatSchemaPathToConverToDataPath(validationError.schemaPath)), + schemaToUse = schemaDataPath ? _.get(schema, schemaDataPath) : schema, + valueToValidate = dataPath ? _.get(valueToUse, dataPath) : valueToUse; + return !isTypeValue(valueToValidate, schemaToUse); } diff --git a/lib/common/schemaUtilsCommon.js b/lib/common/schemaUtilsCommon.js index d9619ad..f19923e 100644 --- a/lib/common/schemaUtilsCommon.js +++ b/lib/common/schemaUtilsCommon.js @@ -4,6 +4,28 @@ const parse = require('../parse.js'); +/** + * Remove the # character from the beginning of a schema path + * @param {string} schemaPath - a defined schemaPath + * @returns {string} - the schema path with # removed + */ +function removeSharpAndSlashFromFirstPosition(schemaPath) { + return schemaPath[0] === '#' ? schemaPath.slice(2) : schemaPath; +} + +/** + * Remove the type from the last position of a schema path + * @param {string} schemaPath - a defined schemaPath + * @returns {string} - the schema path with type removed + */ +function removeTypeFromLastPosition(schemaPath) { + let splittedDataPath = schemaPath.split('/'); + if (splittedDataPath[splittedDataPath.length - 1] === 'type') { + splittedDataPath.splice(-1); + } + return splittedDataPath.join('/'); +} + module.exports = { /** @@ -54,15 +76,21 @@ module.exports = { isANumber = (value) => { return !isNaN(value); }, - formattedElements = splittedDataPath.map((element) => { + formattedElements = splittedDataPath.map((element, index) => { if (element !== '' && isANumber(element)) { return `[${element}]`; } - return element; + if (element === '' || element[0] === '.') { + return element; + } + if (index === 0 && !initialDotIfExist) { + return `${element}`; + } + return `.${element}`; }), formattedDataPath = formattedElements.join(''); - return `${initialDotIfExist}${formattedDataPath}`; + return `${formattedDataPath}`; }, handleExclusiveMaximum: function(schema, max) { @@ -101,5 +129,11 @@ module.exports = { } } return min; + }, + + formatSchemaPathToConverToDataPath: function (schemaPath) { + return removeTypeFromLastPosition(removeSharpAndSlashFromFirstPosition(schemaPath)); } + + }; diff --git a/test/unit/schemaUtilsCommon.test.js b/test/unit/schemaUtilsCommon.test.js index 04c9779..503e8fe 100644 --- a/test/unit/schemaUtilsCommon.test.js +++ b/test/unit/schemaUtilsCommon.test.js @@ -1,5 +1,5 @@ const schemaUtilsCommon = require('../../lib/common/schemaUtilsCommon'); -const { formatDataPath } = require('../../lib/common/schemaUtilsCommon'), +const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../../lib/common/schemaUtilsCommon'), expect = require('chai').expect; describe('formatData method', function() { @@ -31,6 +31,14 @@ describe('formatData method', function() { expect(formattedDataPath).to.be.equal(expectedDataPath); }); + it('Should return "properties.automatic.items.properties.configs.items"' + + ' when input is "#/properties/automatic/items/properties/configs/items/type"', function() { + const input = 'properties/automatic/items/properties/configs/items', + expectedDataPath = 'properties.automatic.items.properties.configs.items', + formattedDataPath = formatDataPath(input); + expect(formattedDataPath).to.be.equal(expectedDataPath); + }); + }); describe('handleExclusiveMaximum method', function() { @@ -149,4 +157,10 @@ describe('handleExclusiveMinimum method', function() { }); }); - +describe('formatSchemaPathToConverToDataPath method', function () { + it('should return properties/automatic/items/properties/configs/items ' + + 'when entry is #/properties/automatic/items/properties/configs/items/type', function () { + const result = formatSchemaPathToConverToDataPath('#/properties/automatic/items/properties/configs/items/type'); + expect(result).to.equal('properties/automatic/items/properties/configs/items'); + }); +}); From 50631020d2293b887cd4736d63aa285ff947c02a Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Tue, 22 Feb 2022 11:37:24 -0600 Subject: [PATCH 04/13] Extract typesMap, space and lines issues, improve naming Extract typesMap to schemaUtilsCommon and consume it in deref.js and ajvValidation.js, fix new lines issues and change method's name from formatSchemaPathToConverToDataPath to formatSchemaPathFromAJVErrorToConvertToDataPath --- lib/ajValidation/ajvValidation.js | 30 +++++++--------------------- lib/common/schemaUtilsCommon.js | 31 +++++++++++++++++++++++++---- lib/deref.js | 23 +++------------------ test/unit/schemaUtilsCommon.test.js | 9 +++++---- 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index 7b6ee93..d984ba0 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -1,28 +1,12 @@ -const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../common/schemaUtilsCommon'); +const { formatDataPath, + formatSchemaPathFromAJVErrorToConvertToDataPath, + typesMap } = require('../common/schemaUtilsCommon'); var _ = require('lodash'); const IGNORED_KEYWORDS = ['propertyNames', 'const', 'additionalItems', 'dependencies'], { validateSchemaAJV } = require('./ajvValidator'), { validateSchemaAJVDraft04 } = require('./ajvValidatorDraft04'), - specialDraft = 'http://json-schema.org/draft-04/schema#', - typesMap = { - integer: { - int32: '', - int64: '' - }, - number: { - float: '', - double: '' - }, - string: { - byte: '', - binary: '', - date: '', - 'date-time': '', - password: '' - }, - boolean: '' - }; + specialDraft = 'http://json-schema.org/draft-04/schema#'; /** * Checks if value is postman variable or not @@ -112,6 +96,7 @@ function checkValueTypesAndFormat(value, types, format) { } return defaultValue === value; }); + if (found) { return true; } @@ -225,11 +210,10 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { } if (validationError.keyword === 'type') { - let schemaDataPath = formatDataPath(formatSchemaPathToConverToDataPath(validationError.schemaPath)), + let schemaDataPath = formatDataPath(formatSchemaPathFromAJVErrorToConvertToDataPath(validationError.schemaPath)), schemaToUse = schemaDataPath ? _.get(schema, schemaDataPath) : schema, valueToValidate = dataPath ? _.get(valueToUse, dataPath) : valueToUse; - return !isTypeValue(valueToValidate, - schemaToUse); + return !isTypeValue(valueToValidate, schemaToUse); } return true; diff --git a/lib/common/schemaUtilsCommon.js b/lib/common/schemaUtilsCommon.js index f19923e..ead54f8 100644 --- a/lib/common/schemaUtilsCommon.js +++ b/lib/common/schemaUtilsCommon.js @@ -2,7 +2,25 @@ * This file contains util functions that are common between versions */ -const parse = require('../parse.js'); +const parse = require('../parse.js'), + typesMap = { + integer: { + int32: '', + int64: '' + }, + number: { + float: '', + double: '' + }, + string: { + byte: '', + binary: '', + date: '', + 'date-time': '', + password: '' + }, + boolean: '' + }; /** * Remove the # character from the beginning of a schema path @@ -131,9 +149,14 @@ module.exports = { return min; }, - formatSchemaPathToConverToDataPath: function (schemaPath) { + /** + * Removes initial "#/" from a schema path and the last "/type" segment + * @param {string} schemaPath - The OAS 3.x specification specified in either YAML or JSON + * @returns {string} - The schemaPath with initial #/ and last "/type" removed + */ + formatSchemaPathFromAJVErrorToConvertToDataPath: function (schemaPath) { return removeTypeFromLastPosition(removeSharpAndSlashFromFirstPosition(schemaPath)); - } - + }, + typesMap }; diff --git a/lib/deref.js b/lib/deref.js index 96bcf42..e2c85c9 100644 --- a/lib/deref.js +++ b/lib/deref.js @@ -1,23 +1,6 @@ const _ = require('lodash'), mergeAllOf = require('json-schema-merge-allof'), - type = { - integer: { - int32: '', - int64: '' - }, - number: { - float: '', - double: '' - }, - string: { - byte: '', - binary: '', - date: '', - 'date-time': '', - password: '' - }, - boolean: '' - }, + { typesMap } = require('./common/schemaUtilsCommon'), PARAMETER_SOURCE = { REQUEST: 'REQUEST', RESPONSE: 'RESPONSE' @@ -328,8 +311,8 @@ module.exports = { if (!schema.hasOwnProperty('format')) { schema.default = '<' + schema.type + '>'; } - else if (type.hasOwnProperty(schema.type)) { - schema.default = type[schema.type][schema.format]; + else if (typesMap.hasOwnProperty(schema.type)) { + schema.default = typesMap[schema.type][schema.format]; // in case the format is a custom format (email, hostname etc.) // https://swagger.io/docs/specification/data-models/data-types/#string diff --git a/test/unit/schemaUtilsCommon.test.js b/test/unit/schemaUtilsCommon.test.js index 503e8fe..dfa4ca2 100644 --- a/test/unit/schemaUtilsCommon.test.js +++ b/test/unit/schemaUtilsCommon.test.js @@ -1,5 +1,5 @@ -const schemaUtilsCommon = require('../../lib/common/schemaUtilsCommon'); -const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../../lib/common/schemaUtilsCommon'), +const schemaUtilsCommon = require('../../lib/common/schemaUtilsCommon'), + { formatDataPath, formatSchemaPathFromAJVErrorToConvertToDataPath } = require('../../lib/common/schemaUtilsCommon'), expect = require('chai').expect; describe('formatData method', function() { @@ -157,10 +157,11 @@ describe('handleExclusiveMinimum method', function() { }); }); -describe('formatSchemaPathToConverToDataPath method', function () { +describe('formatSchemaPathFromAJVErrorToConvertToDataPath method', function () { it('should return properties/automatic/items/properties/configs/items ' + 'when entry is #/properties/automatic/items/properties/configs/items/type', function () { - const result = formatSchemaPathToConverToDataPath('#/properties/automatic/items/properties/configs/items/type'); + const result = + formatSchemaPathFromAJVErrorToConvertToDataPath('#/properties/automatic/items/properties/configs/items/type'); expect(result).to.equal('properties/automatic/items/properties/configs/items'); }); }); From 438a7b3a7ced3fe1480798f5b3c4189e0118fc03 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Tue, 22 Feb 2022 15:59:09 -0600 Subject: [PATCH 05/13] Add tests to check transactionJsonPath when detailedBlobValidation is true Add tests to check transactionJsonPath when detailedBlobValidation is true --- .../invalidTypeProperty.yaml | 118 ++++++ .../validationData/invalidTypeProperty.json | 375 ++++++++++++++++++ .../validationData/invalidTypeProperty.yaml | 118 ++++++ test/unit/validator.test.js | 79 +++- 4 files changed, 671 insertions(+), 19 deletions(-) create mode 100644 test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml create mode 100644 test/data/validationData/invalidTypeProperty.json create mode 100644 test/data/validationData/invalidTypeProperty.yaml diff --git a/test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml b/test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml new file mode 100644 index 0000000..6ce3ebd --- /dev/null +++ b/test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml @@ -0,0 +1,118 @@ + +openapi: "3.1.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: https://postman-echo.com/get +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + format: date + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string` diff --git a/test/data/validationData/invalidTypeProperty.json b/test/data/validationData/invalidTypeProperty.json new file mode 100644 index 0000000..e35fcc6 --- /dev/null +++ b/test/data/validationData/invalidTypeProperty.json @@ -0,0 +1,375 @@ +{ + "item": [ + { + "id": "ec09078b-8861-4367-9e9e-22f8c3d31f82", + "name": "pets", + "description": { + "content": "", + "type": "text/plain" + }, + "item": [ + { + "id": "2c8762c9-54bc-4981-8d2c-09b71fadcebc", + "name": "List all pets", + "request": { + "name": "List all pets", + "description": {}, + "url": { + "path": [ + "pets" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [ + { + "disabled": false, + "key": "limit", + "value": "82526723", + "description": "How many items to return at one time (max 100)" + } + ], + "variable": [] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + } + ], + "method": "GET", + "auth": null + }, + "response": [ + { + "id": "2d0c2488-0d26-4029-9294-fbc5c9b8363f", + "name": "A paged array of pets", + "originalRequest": { + "url": { + "path": [ + "pets" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [ + { + "key": "limit", + "value": "82526723" + } + ], + "variable": [] + }, + "method": "GET", + "body": {} + }, + "status": "OK", + "code": 200, + "header": [ + { + "disabled": false, + "description": "A link to the next page of responses", + "key": "x-next", + "value": "in nulla Lorem ex" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": "[\n {\n \"id\": 41014273,\n \"name\": \"dolor eu minim in\",\n \"tag\": \"urn:uuid:94b326e4-ed11-bd40-c87d-1a1524b6bc2f\"\n },\n {\n \"id\": -74291521,\n \"name\": \"pariatur dolor e\",\n \"tag\": \"urn:uuid:092c825a-7a1d-1adc-71da-b9dbe24c2da6\"\n }\n]", + "cookie": [], + "_postman_previewlanguage": "json" + }, + { + "id": "eb93bc02-1380-433a-9a6e-acd8875a8334", + "name": "unexpected error", + "originalRequest": { + "url": { + "path": [ + "pets" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [ + { + "key": "limit", + "value": "82526723" + } + ], + "variable": [] + }, + "method": "GET", + "body": {} + }, + "status": "Internal Server Error", + "code": 500, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": "{\n \"code\": -57418069,\n \"message\": \"non quis proident\"\n}", + "cookie": [], + "_postman_previewlanguage": "json" + } + ], + "event": [] + }, + { + "id": "87611012-e59c-40e1-90f2-24a50fbbff1d", + "name": "Create a pet", + "request": { + "name": "Create a pet", + "description": {}, + "url": { + "path": [ + "pets" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [] + }, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json" + } + ], + "method": "POST", + "auth": null, + "body": { + "mode": "raw", + "raw": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", + "options": { + "raw": { + "language": "json" + } + } + } + }, + "response": [ + { + "id": "813809b9-3290-43e3-8c43-f939db815d2c", + "name": "Null response", + "originalRequest": { + "url": { + "path": [ + "pets" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [] + }, + "method": "POST", + "body": { + "mode": "raw", + "raw": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", + "options": { + "raw": { + "language": "json" + } + } + } + }, + "status": "Created", + "code": 201, + "header": [ + { + "key": "Content-Type", + "value": "text/plain" + } + ], + "body": "", + "cookie": [], + "_postman_previewlanguage": "text" + }, + { + "id": "436ebb0e-5c7a-4cba-883e-f36089ccd5e2", + "name": "unexpected error", + "originalRequest": { + "url": { + "path": [ + "pets" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [] + }, + "method": "POST", + "body": { + "mode": "raw", + "raw": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", + "options": { + "raw": { + "language": "json" + } + } + } + }, + "status": "Internal Server Error", + "code": 500, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": "{\n \"code\": -57418069,\n \"message\": \"non quis proident\"\n}", + "cookie": [], + "_postman_previewlanguage": "json" + } + ], + "event": [], + "protocolProfileBehavior": { + "disableBodyPruning": true + } + }, + { + "id": "ab623305-0ccf-4edc-9210-c3ed68d4e1dc", + "name": "Info for a specific pet", + "request": { + "name": "Info for a specific pet", + "description": {}, + "url": { + "path": [ + "pets", + ":petId" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [ + { + "disabled": false, + "type": "any", + "value": "in nulla Lorem ex", + "key": "petId", + "description": "(Required) The id of the pet to retrieve" + } + ] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + } + ], + "method": "GET", + "auth": null + }, + "response": [ + { + "id": "6de63e43-7e59-4713-8893-53bdbddeddef", + "name": "Expected response to a valid request", + "originalRequest": { + "url": { + "path": [ + "pets", + ":petId" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [ + { + "disabled": false, + "type": "any", + "value": "in nulla Lorem ex", + "key": "petId", + "description": "(Required) The id of the pet to retrieve" + } + ] + }, + "method": "GET", + "body": {} + }, + "status": "OK", + "code": 200, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", + "cookie": [], + "_postman_previewlanguage": "json" + }, + { + "id": "d221e68f-af12-4042-935e-ae2709ef52e7", + "name": "unexpected error", + "originalRequest": { + "url": { + "path": [ + "pets", + ":petId" + ], + "host": [ + "{{baseUrl}}" + ], + "query": [], + "variable": [ + { + "disabled": false, + "type": "any", + "value": "in nulla Lorem ex", + "key": "petId", + "description": "(Required) The id of the pet to retrieve" + } + ] + }, + "method": "GET", + "body": {} + }, + "status": "Internal Server Error", + "code": 500, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": "{\n \"code\": -57418069,\n \"message\": \"non quis proident\"\n}", + "cookie": [], + "_postman_previewlanguage": "json" + } + ], + "event": [] + } + ], + "event": [] + } + ], + "event": [], + "variable": [ + { + "type": "string", + "value": "https://postman-echo.com/get", + "key": "baseUrl" + } + ], + "info": { + "_postman_id": "5baba942-df02-45da-9e3d-540db4667bc4", + "name": "Swagger Petstore", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": { + "content": "", + "type": "text/plain" + } + } +} diff --git a/test/data/validationData/invalidTypeProperty.yaml b/test/data/validationData/invalidTypeProperty.yaml new file mode 100644 index 0000000..e5fcef0 --- /dev/null +++ b/test/data/validationData/invalidTypeProperty.yaml @@ -0,0 +1,118 @@ + +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: https://postman-echo.com/get +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + format: date + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string` diff --git a/test/unit/validator.test.js b/test/unit/validator.test.js index a1f9655..82468b8 100644 --- a/test/unit/validator.test.js +++ b/test/unit/validator.test.js @@ -391,21 +391,21 @@ describe('The Validation option', function () { { detailedBlobValidation: true }), historyRequest = [], resultObj, - violatedKeywords = [ - 'data.items.minProperties', - 'data.items.required', - 'data.items.properties.entityId.maxLength', - 'data.items.properties.accountNumber.minLength', - 'data.items.properties.entityName.format', - 'data.items.properties.incType.enum', - 'data.items.properties.companyNumber.exclusiveMinimum', - 'data.items.properties.website.type', - 'data.items.properties.turnover.multipleOf', - 'data.items.properties.description.pattern', - 'data.items.properties.wants.uniqueItems', - 'meta.maxProperties', - 'meta.additionalProperties' - ]; + violatedKeywords = { + 'data.items.minProperties': '$.request.body.data[0]', + 'data.items.required': '$.request.body.data[0]', + 'data.items.properties.entityId.maxLength': '$.request.body.data[0].entityId', + 'data.items.properties.accountNumber.minLength': '$.request.body.data[0].accountNumber', + 'data.items.properties.entityName.format': '$.request.body.data[0].entityName', + 'data.items.properties.incType.enum': '$.request.body.data[0].incType', + 'data.items.properties.companyNumber.exclusiveMinimum': '$.request.body.data[0].companyNumber', + 'data.items.properties.website.type': '$.request.body.data[0].website', + 'data.items.properties.turnover.multipleOf': '$.request.body.data[0].turnover', + 'data.items.properties.description.pattern': '$.request.body.data[0].description', + 'data.items.properties.wants.uniqueItems': '$.request.body.data[0].wants', + 'meta.maxProperties': '$.request.body.meta', + 'meta.additionalProperties': '$.request.body.meta' + }; getAllTransactions(JSON.parse(collection), historyRequest); schemaPack.validateTransaction(historyRequest, (err, result) => { @@ -416,7 +416,8 @@ describe('The Validation option', function () { _.forEach(resultObj.mismatches, (mismatch) => { // remove starting string '$.paths[/user].post.requestBody.content[application/json].schema.properties.' let localJsonPath = mismatch.schemaJsonPath.slice(76); - expect(_.includes(violatedKeywords, localJsonPath)).to.eql(true); + expect(_.includes(_.keys(violatedKeywords), localJsonPath)).to.eql(true); + expect(_.includes(_.values(violatedKeywords), mismatch.transactionJsonPath)).to.eql(true); // mark matched path as empty to ensure repetition does'n occur violatedKeywords[_.indexOf(violatedKeywords, localJsonPath)] = ''; @@ -506,6 +507,13 @@ describe('VALIDATE FUNCTION TESTS ', function () { VALIDATION_DATA_SCENARIOS_FOLDER_31_PATH ), '/compositeSchemaSpec.yaml' + ), + invalidTypeProperty = getSpecsPathByVersion( + getFoldersByVersion( + VALIDATION_DATA_FOLDER_PATH, + VALIDATION_DATA_SCENARIOS_FOLDER_31_PATH + ), + '/invalidTypeProperty.yaml' ); emptyParameterSpecs.forEach((specData) => { @@ -749,7 +757,7 @@ describe('VALIDATE FUNCTION TESTS ', function () { ignoreUnresolvedVariables: true, validateMetadata: true, suggestAvailableFixes: true, - detailedBlobValidation: false + detailedBlobValidation: true }, schemaPack = new Converter.SchemaPack({ type: 'string', data: primitiveDataTypeBodySpec }, options); @@ -762,11 +770,13 @@ describe('VALIDATE FUNCTION TESTS ', function () { // request body is boolean resultObj = result.requests[historyRequest[0].id].endpoints[0]; expect(resultObj.mismatches).to.have.lengthOf(0); - + const responseId = _.keys(resultObj.responses)[0]; // request body is integer - responseObj = resultObj.responses[_.keys(resultObj.responses)[0]]; + responseObj = resultObj.responses[responseId]; expect(responseObj.mismatches).to.have.lengthOf(1); expect(responseObj.mismatches[0].suggestedFix.suggestedValue).to.be.within(5, 10); + expect(responseObj.mismatches[0].transactionJsonPath).to + .equal(`$.responses[${responseId}].body`); done(); }); }); @@ -961,6 +971,37 @@ describe('VALIDATE FUNCTION TESTS ', function () { }); }); }); + + invalidTypeProperty.forEach((specData) => { + it('Should correctly suggest value and report transactionJsonPath on a body property with incorrect value ' + + specData.version, function (done) { + let invalidTypePropertySpec = fs.readFileSync(specData.path, 'utf-8'), + invalidTypePropertyCollection = fs.readFileSync(path.join(__dirname, VALIDATION_DATA_FOLDER_PATH + + '/invalidTypeProperty.json'), 'utf-8'), + options = { suggestAvailableFixes: true, detailedBlobValidation: true }, + resultObj, + historyRequest = [], + schemaPack = new Converter.SchemaPack({ type: 'string', data: invalidTypePropertySpec }, options); + + getAllTransactions(JSON.parse(invalidTypePropertyCollection), historyRequest); + + schemaPack.validateTransaction(historyRequest, (err, result) => { + expect(err).to.be.null; + expect(result).to.be.an('object'); + resultObj = result.requests[historyRequest[0].id].endpoints[0]; + const responseId = _.keys(resultObj.responses)[0], + responseMissmatches = resultObj.responses[responseId].mismatches; + expect(responseMissmatches).to.have.lengthOf(2); + expect(responseMissmatches[0].transactionJsonPath) + .to.equal(`$.responses[${responseId}].body[0].tag`); + expect(responseMissmatches[0].suggestedFix.key).to.equal('tag'); + expect(responseMissmatches[1].transactionJsonPath) + .to.equal(`$.responses[${responseId}].body[1].tag`); + expect(responseMissmatches[1].suggestedFix.key).to.equal('tag'); + done(); + }); + }); + }); }); describe('getPostmanUrlSuffixSchemaScore function', function () { From 95e7e6567db819b4ce74e506ff891fe3c38a3f17 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:58:42 -0600 Subject: [PATCH 06/13] Support falsy examples defined out of schema --- lib/schemaUtils.js | 2 +- test/data/valid_openapi/issue#10229.json | 174 +++++++++++++++++++++++ test/unit/base.test.js | 20 ++- 3 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 test/data/valid_openapi/issue#10229.json diff --git a/lib/schemaUtils.js b/lib/schemaUtils.js index b3ff35a..bec862d 100644 --- a/lib/schemaUtils.js +++ b/lib/schemaUtils.js @@ -406,7 +406,7 @@ module.exports = { let example = _.get(parameter, 'example'), examples = _.values(_.get(parameter, 'examples')); - if (example) { + if (example !== undefined) { _.set(parameter, 'schema.example', example); } else if (examples) { diff --git a/test/data/valid_openapi/issue#10229.json b/test/data/valid_openapi/issue#10229.json new file mode 100644 index 0000000..7a784f3 --- /dev/null +++ b/test/data/valid_openapi/issue#10229.json @@ -0,0 +1,174 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "#10229", + "license": { + "name": "MIT" + } + }, + "servers": [ + { + "url": "http://petstore.swagger.io/v1" + } + ], + "paths": { + "/pets": { + "servers": [ + { + "url": "http://petstore.swagger.io:{port}/{basePath}", + "variables": { + "port": { + "enum": [ + "8443", + "443" + ], + "default": "8443" + }, + "basePath": { + "default": "v2" + } + } + } + ], + "get": { + "summary": "List all pets", + "operationId": "listPets", + "tags": [ + "pets" + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "How many items to return at one time (max 100)", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 0 + }, + { + "name": "otherString", + "in": "query", + "description": "other parameter", + "required": false, + "schema": { + "type": "string" + }, + "example": "" + }, + + { + "name": "otherBoolean", + "in": "query", + "description": "other parameter", + "required": false, + "schema": { + "type": "boolean" + }, + "example": false + } + ], + "responses": { + "200": { + "description": "A paged array of pets", + "headers": { + "x-next": { + "description": "A link to the next page of responses", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + } + } + }, + "default": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "post": { + "summary": "Create a pet", + "operationId": "createPets", + "tags": [ + "pets" + ], + "responses": { + "201": { + "description": "Null response" + }, + "default": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Pet": { + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "Pets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + }, + "Error": { + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + } + } + } +} diff --git a/test/unit/base.test.js b/test/unit/base.test.js index e59817c..b289c67 100644 --- a/test/unit/base.test.js +++ b/test/unit/base.test.js @@ -43,7 +43,8 @@ describe('CONVERT FUNCTION TESTS ', function() { securityTestCases = path.join(__dirname, VALID_OPENAPI_PATH + '/security-test-cases.yaml'), emptySecurityTestCase = path.join(__dirname, VALID_OPENAPI_PATH + '/empty-security-test-case.yaml'), rootUrlServerWithVariables = path.join(__dirname, VALID_OPENAPI_PATH + '/root_url_server_with_variables.json'), - parameterExamples = path.join(__dirname, VALID_OPENAPI_PATH + '/parameteres_with_examples.yaml'); + parameterExamples = path.join(__dirname, VALID_OPENAPI_PATH + '/parameteres_with_examples.yaml'), + issue10229 = path.join(__dirname, VALID_OPENAPI_PATH, '/issue#10229.json'); it('Should add collection level auth with type as `bearer`' + @@ -393,6 +394,23 @@ describe('CONVERT FUNCTION TESTS ', function() { done(); }); }); + it('#GITHUB-10229 should generate correct example is out of the schema and is falsy' + + issue10229, function(done) { + var openapi = fs.readFileSync(issue10229, 'utf8'); + Converter.convert({ type: 'string', data: openapi }, { requestParametersResolution: 'Example' }, + (err, conversionResult) => { + expect(err).to.be.null; + expect(conversionResult.result).to.equal(true); + expect(conversionResult.output.length).to.equal(1); + expect(conversionResult.output[0].type).to.equal('collection'); + expect(conversionResult.output[0].data).to.have.property('info'); + expect(conversionResult.output[0].data).to.have.property('item'); + expect(conversionResult.output[0].data.item[0].item[0].request.url.query[0].value).to.equal('0'); + expect(conversionResult.output[0].data.item[0].item[0].request.url.query[1].value).to.equal(''); + expect(conversionResult.output[0].data.item[0].item[0].request.url.query[2].value).to.equal('false'); + done(); + }); + }); describe('[Github #108]- Parameters resolution option', function() { it('Should respect schema faking for root request and example for example request' + examplesInSchemaSpec, function(done) { From 7ac8c9447ceb5a00e26999999af821d8d4f3161c Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Thu, 24 Feb 2022 12:30:29 -0600 Subject: [PATCH 07/13] Update schemaUtils.js validate also null possibility --- lib/schemaUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schemaUtils.js b/lib/schemaUtils.js index bec862d..91043c9 100644 --- a/lib/schemaUtils.js +++ b/lib/schemaUtils.js @@ -406,7 +406,7 @@ module.exports = { let example = _.get(parameter, 'example'), examples = _.values(_.get(parameter, 'examples')); - if (example !== undefined) { + if (example !== undefined && example !== null) { _.set(parameter, 'schema.example', example); } else if (examples) { From fb88c347337c36dbddc8a622ed9efc45707aa1cc Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 28 Feb 2022 09:54:25 -0600 Subject: [PATCH 08/13] Revert "Add tests to check transactionJsonPath when detailedBlobValidation is true" This reverts commit 438a7b3a7ced3fe1480798f5b3c4189e0118fc03. --- .../invalidTypeProperty.yaml | 118 ------ .../validationData/invalidTypeProperty.json | 375 ------------------ .../validationData/invalidTypeProperty.yaml | 118 ------ test/unit/validator.test.js | 79 +--- 4 files changed, 19 insertions(+), 671 deletions(-) delete mode 100644 test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml delete mode 100644 test/data/validationData/invalidTypeProperty.json delete mode 100644 test/data/validationData/invalidTypeProperty.yaml diff --git a/test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml b/test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml deleted file mode 100644 index 6ce3ebd..0000000 --- a/test/data/31CollectionTransactions/validate30Scenarios/invalidTypeProperty.yaml +++ /dev/null @@ -1,118 +0,0 @@ - -openapi: "3.1.0" -info: - version: 1.0.0 - title: Swagger Petstore - license: - name: MIT -servers: - - url: https://postman-echo.com/get -paths: - /pets: - get: - summary: List all pets - operationId: listPets - tags: - - pets - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - format: int32 - responses: - '200': - description: A paged array of pets - headers: - x-next: - description: A link to the next page of responses - schema: - type: string - content: - application/json: - schema: - $ref: "#/components/schemas/Pets" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - post: - summary: Create a pet - operationId: createPets - tags: - - pets - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/Pet" - responses: - '201': - description: Null response - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - /pets/{petId}: - get: - summary: Info for a specific pet - operationId: showPetById - tags: - - pets - parameters: - - name: petId - in: path - required: true - description: The id of the pet to retrieve - schema: - type: string - responses: - '200': - description: Expected response to a valid request - content: - application/json: - schema: - $ref: "#/components/schemas/Pet" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Pet: - type: object - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string - format: date - Pets: - type: array - items: - $ref: "#/components/schemas/Pet" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string` diff --git a/test/data/validationData/invalidTypeProperty.json b/test/data/validationData/invalidTypeProperty.json deleted file mode 100644 index e35fcc6..0000000 --- a/test/data/validationData/invalidTypeProperty.json +++ /dev/null @@ -1,375 +0,0 @@ -{ - "item": [ - { - "id": "ec09078b-8861-4367-9e9e-22f8c3d31f82", - "name": "pets", - "description": { - "content": "", - "type": "text/plain" - }, - "item": [ - { - "id": "2c8762c9-54bc-4981-8d2c-09b71fadcebc", - "name": "List all pets", - "request": { - "name": "List all pets", - "description": {}, - "url": { - "path": [ - "pets" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [ - { - "disabled": false, - "key": "limit", - "value": "82526723", - "description": "How many items to return at one time (max 100)" - } - ], - "variable": [] - }, - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "method": "GET", - "auth": null - }, - "response": [ - { - "id": "2d0c2488-0d26-4029-9294-fbc5c9b8363f", - "name": "A paged array of pets", - "originalRequest": { - "url": { - "path": [ - "pets" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [ - { - "key": "limit", - "value": "82526723" - } - ], - "variable": [] - }, - "method": "GET", - "body": {} - }, - "status": "OK", - "code": 200, - "header": [ - { - "disabled": false, - "description": "A link to the next page of responses", - "key": "x-next", - "value": "in nulla Lorem ex" - }, - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": "[\n {\n \"id\": 41014273,\n \"name\": \"dolor eu minim in\",\n \"tag\": \"urn:uuid:94b326e4-ed11-bd40-c87d-1a1524b6bc2f\"\n },\n {\n \"id\": -74291521,\n \"name\": \"pariatur dolor e\",\n \"tag\": \"urn:uuid:092c825a-7a1d-1adc-71da-b9dbe24c2da6\"\n }\n]", - "cookie": [], - "_postman_previewlanguage": "json" - }, - { - "id": "eb93bc02-1380-433a-9a6e-acd8875a8334", - "name": "unexpected error", - "originalRequest": { - "url": { - "path": [ - "pets" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [ - { - "key": "limit", - "value": "82526723" - } - ], - "variable": [] - }, - "method": "GET", - "body": {} - }, - "status": "Internal Server Error", - "code": 500, - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": "{\n \"code\": -57418069,\n \"message\": \"non quis proident\"\n}", - "cookie": [], - "_postman_previewlanguage": "json" - } - ], - "event": [] - }, - { - "id": "87611012-e59c-40e1-90f2-24a50fbbff1d", - "name": "Create a pet", - "request": { - "name": "Create a pet", - "description": {}, - "url": { - "path": [ - "pets" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [] - }, - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "method": "POST", - "auth": null, - "body": { - "mode": "raw", - "raw": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", - "options": { - "raw": { - "language": "json" - } - } - } - }, - "response": [ - { - "id": "813809b9-3290-43e3-8c43-f939db815d2c", - "name": "Null response", - "originalRequest": { - "url": { - "path": [ - "pets" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [] - }, - "method": "POST", - "body": { - "mode": "raw", - "raw": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", - "options": { - "raw": { - "language": "json" - } - } - } - }, - "status": "Created", - "code": 201, - "header": [ - { - "key": "Content-Type", - "value": "text/plain" - } - ], - "body": "", - "cookie": [], - "_postman_previewlanguage": "text" - }, - { - "id": "436ebb0e-5c7a-4cba-883e-f36089ccd5e2", - "name": "unexpected error", - "originalRequest": { - "url": { - "path": [ - "pets" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [] - }, - "method": "POST", - "body": { - "mode": "raw", - "raw": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", - "options": { - "raw": { - "language": "json" - } - } - } - }, - "status": "Internal Server Error", - "code": 500, - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": "{\n \"code\": -57418069,\n \"message\": \"non quis proident\"\n}", - "cookie": [], - "_postman_previewlanguage": "json" - } - ], - "event": [], - "protocolProfileBehavior": { - "disableBodyPruning": true - } - }, - { - "id": "ab623305-0ccf-4edc-9210-c3ed68d4e1dc", - "name": "Info for a specific pet", - "request": { - "name": "Info for a specific pet", - "description": {}, - "url": { - "path": [ - "pets", - ":petId" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [ - { - "disabled": false, - "type": "any", - "value": "in nulla Lorem ex", - "key": "petId", - "description": "(Required) The id of the pet to retrieve" - } - ] - }, - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "method": "GET", - "auth": null - }, - "response": [ - { - "id": "6de63e43-7e59-4713-8893-53bdbddeddef", - "name": "Expected response to a valid request", - "originalRequest": { - "url": { - "path": [ - "pets", - ":petId" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [ - { - "disabled": false, - "type": "any", - "value": "in nulla Lorem ex", - "key": "petId", - "description": "(Required) The id of the pet to retrieve" - } - ] - }, - "method": "GET", - "body": {} - }, - "status": "OK", - "code": 200, - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": "{\n \"id\": -56104459,\n \"name\": \"dolore incididunt pariatur occaecat\",\n \"tag\": \"9e6b59af-239e-b38b-74a7-f3110c87227e\"\n}", - "cookie": [], - "_postman_previewlanguage": "json" - }, - { - "id": "d221e68f-af12-4042-935e-ae2709ef52e7", - "name": "unexpected error", - "originalRequest": { - "url": { - "path": [ - "pets", - ":petId" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [ - { - "disabled": false, - "type": "any", - "value": "in nulla Lorem ex", - "key": "petId", - "description": "(Required) The id of the pet to retrieve" - } - ] - }, - "method": "GET", - "body": {} - }, - "status": "Internal Server Error", - "code": 500, - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": "{\n \"code\": -57418069,\n \"message\": \"non quis proident\"\n}", - "cookie": [], - "_postman_previewlanguage": "json" - } - ], - "event": [] - } - ], - "event": [] - } - ], - "event": [], - "variable": [ - { - "type": "string", - "value": "https://postman-echo.com/get", - "key": "baseUrl" - } - ], - "info": { - "_postman_id": "5baba942-df02-45da-9e3d-540db4667bc4", - "name": "Swagger Petstore", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "description": { - "content": "", - "type": "text/plain" - } - } -} diff --git a/test/data/validationData/invalidTypeProperty.yaml b/test/data/validationData/invalidTypeProperty.yaml deleted file mode 100644 index e5fcef0..0000000 --- a/test/data/validationData/invalidTypeProperty.yaml +++ /dev/null @@ -1,118 +0,0 @@ - -openapi: "3.0.0" -info: - version: 1.0.0 - title: Swagger Petstore - license: - name: MIT -servers: - - url: https://postman-echo.com/get -paths: - /pets: - get: - summary: List all pets - operationId: listPets - tags: - - pets - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - format: int32 - responses: - '200': - description: A paged array of pets - headers: - x-next: - description: A link to the next page of responses - schema: - type: string - content: - application/json: - schema: - $ref: "#/components/schemas/Pets" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - post: - summary: Create a pet - operationId: createPets - tags: - - pets - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/Pet" - responses: - '201': - description: Null response - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - /pets/{petId}: - get: - summary: Info for a specific pet - operationId: showPetById - tags: - - pets - parameters: - - name: petId - in: path - required: true - description: The id of the pet to retrieve - schema: - type: string - responses: - '200': - description: Expected response to a valid request - content: - application/json: - schema: - $ref: "#/components/schemas/Pet" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Pet: - type: object - required: - - id - - name - properties: - id: - type: integer - format: int64 - name: - type: string - tag: - type: string - format: date - Pets: - type: array - items: - $ref: "#/components/schemas/Pet" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string` diff --git a/test/unit/validator.test.js b/test/unit/validator.test.js index 82468b8..a1f9655 100644 --- a/test/unit/validator.test.js +++ b/test/unit/validator.test.js @@ -391,21 +391,21 @@ describe('The Validation option', function () { { detailedBlobValidation: true }), historyRequest = [], resultObj, - violatedKeywords = { - 'data.items.minProperties': '$.request.body.data[0]', - 'data.items.required': '$.request.body.data[0]', - 'data.items.properties.entityId.maxLength': '$.request.body.data[0].entityId', - 'data.items.properties.accountNumber.minLength': '$.request.body.data[0].accountNumber', - 'data.items.properties.entityName.format': '$.request.body.data[0].entityName', - 'data.items.properties.incType.enum': '$.request.body.data[0].incType', - 'data.items.properties.companyNumber.exclusiveMinimum': '$.request.body.data[0].companyNumber', - 'data.items.properties.website.type': '$.request.body.data[0].website', - 'data.items.properties.turnover.multipleOf': '$.request.body.data[0].turnover', - 'data.items.properties.description.pattern': '$.request.body.data[0].description', - 'data.items.properties.wants.uniqueItems': '$.request.body.data[0].wants', - 'meta.maxProperties': '$.request.body.meta', - 'meta.additionalProperties': '$.request.body.meta' - }; + violatedKeywords = [ + 'data.items.minProperties', + 'data.items.required', + 'data.items.properties.entityId.maxLength', + 'data.items.properties.accountNumber.minLength', + 'data.items.properties.entityName.format', + 'data.items.properties.incType.enum', + 'data.items.properties.companyNumber.exclusiveMinimum', + 'data.items.properties.website.type', + 'data.items.properties.turnover.multipleOf', + 'data.items.properties.description.pattern', + 'data.items.properties.wants.uniqueItems', + 'meta.maxProperties', + 'meta.additionalProperties' + ]; getAllTransactions(JSON.parse(collection), historyRequest); schemaPack.validateTransaction(historyRequest, (err, result) => { @@ -416,8 +416,7 @@ describe('The Validation option', function () { _.forEach(resultObj.mismatches, (mismatch) => { // remove starting string '$.paths[/user].post.requestBody.content[application/json].schema.properties.' let localJsonPath = mismatch.schemaJsonPath.slice(76); - expect(_.includes(_.keys(violatedKeywords), localJsonPath)).to.eql(true); - expect(_.includes(_.values(violatedKeywords), mismatch.transactionJsonPath)).to.eql(true); + expect(_.includes(violatedKeywords, localJsonPath)).to.eql(true); // mark matched path as empty to ensure repetition does'n occur violatedKeywords[_.indexOf(violatedKeywords, localJsonPath)] = ''; @@ -507,13 +506,6 @@ describe('VALIDATE FUNCTION TESTS ', function () { VALIDATION_DATA_SCENARIOS_FOLDER_31_PATH ), '/compositeSchemaSpec.yaml' - ), - invalidTypeProperty = getSpecsPathByVersion( - getFoldersByVersion( - VALIDATION_DATA_FOLDER_PATH, - VALIDATION_DATA_SCENARIOS_FOLDER_31_PATH - ), - '/invalidTypeProperty.yaml' ); emptyParameterSpecs.forEach((specData) => { @@ -757,7 +749,7 @@ describe('VALIDATE FUNCTION TESTS ', function () { ignoreUnresolvedVariables: true, validateMetadata: true, suggestAvailableFixes: true, - detailedBlobValidation: true + detailedBlobValidation: false }, schemaPack = new Converter.SchemaPack({ type: 'string', data: primitiveDataTypeBodySpec }, options); @@ -770,13 +762,11 @@ describe('VALIDATE FUNCTION TESTS ', function () { // request body is boolean resultObj = result.requests[historyRequest[0].id].endpoints[0]; expect(resultObj.mismatches).to.have.lengthOf(0); - const responseId = _.keys(resultObj.responses)[0]; + // request body is integer - responseObj = resultObj.responses[responseId]; + responseObj = resultObj.responses[_.keys(resultObj.responses)[0]]; expect(responseObj.mismatches).to.have.lengthOf(1); expect(responseObj.mismatches[0].suggestedFix.suggestedValue).to.be.within(5, 10); - expect(responseObj.mismatches[0].transactionJsonPath).to - .equal(`$.responses[${responseId}].body`); done(); }); }); @@ -971,37 +961,6 @@ describe('VALIDATE FUNCTION TESTS ', function () { }); }); }); - - invalidTypeProperty.forEach((specData) => { - it('Should correctly suggest value and report transactionJsonPath on a body property with incorrect value ' + - specData.version, function (done) { - let invalidTypePropertySpec = fs.readFileSync(specData.path, 'utf-8'), - invalidTypePropertyCollection = fs.readFileSync(path.join(__dirname, VALIDATION_DATA_FOLDER_PATH + - '/invalidTypeProperty.json'), 'utf-8'), - options = { suggestAvailableFixes: true, detailedBlobValidation: true }, - resultObj, - historyRequest = [], - schemaPack = new Converter.SchemaPack({ type: 'string', data: invalidTypePropertySpec }, options); - - getAllTransactions(JSON.parse(invalidTypePropertyCollection), historyRequest); - - schemaPack.validateTransaction(historyRequest, (err, result) => { - expect(err).to.be.null; - expect(result).to.be.an('object'); - resultObj = result.requests[historyRequest[0].id].endpoints[0]; - const responseId = _.keys(resultObj.responses)[0], - responseMissmatches = resultObj.responses[responseId].mismatches; - expect(responseMissmatches).to.have.lengthOf(2); - expect(responseMissmatches[0].transactionJsonPath) - .to.equal(`$.responses[${responseId}].body[0].tag`); - expect(responseMissmatches[0].suggestedFix.key).to.equal('tag'); - expect(responseMissmatches[1].transactionJsonPath) - .to.equal(`$.responses[${responseId}].body[1].tag`); - expect(responseMissmatches[1].suggestedFix.key).to.equal('tag'); - done(); - }); - }); - }); }); describe('getPostmanUrlSuffixSchemaScore function', function () { From 45f733bd719d23f6a123e5590af5b9d0ec13fc3f Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 28 Feb 2022 09:54:38 -0600 Subject: [PATCH 09/13] Revert "Extract typesMap, space and lines issues, improve naming" This reverts commit 50631020d2293b887cd4736d63aa285ff947c02a. --- lib/ajValidation/ajvValidation.js | 30 +++++++++++++++++++++------- lib/common/schemaUtilsCommon.js | 31 ++++------------------------- lib/deref.js | 23 ++++++++++++++++++--- test/unit/schemaUtilsCommon.test.js | 9 ++++----- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index d984ba0..7b6ee93 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -1,12 +1,28 @@ -const { formatDataPath, - formatSchemaPathFromAJVErrorToConvertToDataPath, - typesMap } = require('../common/schemaUtilsCommon'); +const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../common/schemaUtilsCommon'); var _ = require('lodash'); const IGNORED_KEYWORDS = ['propertyNames', 'const', 'additionalItems', 'dependencies'], { validateSchemaAJV } = require('./ajvValidator'), { validateSchemaAJVDraft04 } = require('./ajvValidatorDraft04'), - specialDraft = 'http://json-schema.org/draft-04/schema#'; + specialDraft = 'http://json-schema.org/draft-04/schema#', + typesMap = { + integer: { + int32: '', + int64: '' + }, + number: { + float: '', + double: '' + }, + string: { + byte: '', + binary: '', + date: '', + 'date-time': '', + password: '' + }, + boolean: '' + }; /** * Checks if value is postman variable or not @@ -96,7 +112,6 @@ function checkValueTypesAndFormat(value, types, format) { } return defaultValue === value; }); - if (found) { return true; } @@ -210,10 +225,11 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { } if (validationError.keyword === 'type') { - let schemaDataPath = formatDataPath(formatSchemaPathFromAJVErrorToConvertToDataPath(validationError.schemaPath)), + let schemaDataPath = formatDataPath(formatSchemaPathToConverToDataPath(validationError.schemaPath)), schemaToUse = schemaDataPath ? _.get(schema, schemaDataPath) : schema, valueToValidate = dataPath ? _.get(valueToUse, dataPath) : valueToUse; - return !isTypeValue(valueToValidate, schemaToUse); + return !isTypeValue(valueToValidate, + schemaToUse); } return true; diff --git a/lib/common/schemaUtilsCommon.js b/lib/common/schemaUtilsCommon.js index ead54f8..f19923e 100644 --- a/lib/common/schemaUtilsCommon.js +++ b/lib/common/schemaUtilsCommon.js @@ -2,25 +2,7 @@ * This file contains util functions that are common between versions */ -const parse = require('../parse.js'), - typesMap = { - integer: { - int32: '', - int64: '' - }, - number: { - float: '', - double: '' - }, - string: { - byte: '', - binary: '', - date: '', - 'date-time': '', - password: '' - }, - boolean: '' - }; +const parse = require('../parse.js'); /** * Remove the # character from the beginning of a schema path @@ -149,14 +131,9 @@ module.exports = { return min; }, - /** - * Removes initial "#/" from a schema path and the last "/type" segment - * @param {string} schemaPath - The OAS 3.x specification specified in either YAML or JSON - * @returns {string} - The schemaPath with initial #/ and last "/type" removed - */ - formatSchemaPathFromAJVErrorToConvertToDataPath: function (schemaPath) { + formatSchemaPathToConverToDataPath: function (schemaPath) { return removeTypeFromLastPosition(removeSharpAndSlashFromFirstPosition(schemaPath)); - }, + } + - typesMap }; diff --git a/lib/deref.js b/lib/deref.js index e2c85c9..96bcf42 100644 --- a/lib/deref.js +++ b/lib/deref.js @@ -1,6 +1,23 @@ const _ = require('lodash'), mergeAllOf = require('json-schema-merge-allof'), - { typesMap } = require('./common/schemaUtilsCommon'), + type = { + integer: { + int32: '', + int64: '' + }, + number: { + float: '', + double: '' + }, + string: { + byte: '', + binary: '', + date: '', + 'date-time': '', + password: '' + }, + boolean: '' + }, PARAMETER_SOURCE = { REQUEST: 'REQUEST', RESPONSE: 'RESPONSE' @@ -311,8 +328,8 @@ module.exports = { if (!schema.hasOwnProperty('format')) { schema.default = '<' + schema.type + '>'; } - else if (typesMap.hasOwnProperty(schema.type)) { - schema.default = typesMap[schema.type][schema.format]; + else if (type.hasOwnProperty(schema.type)) { + schema.default = type[schema.type][schema.format]; // in case the format is a custom format (email, hostname etc.) // https://swagger.io/docs/specification/data-models/data-types/#string diff --git a/test/unit/schemaUtilsCommon.test.js b/test/unit/schemaUtilsCommon.test.js index dfa4ca2..503e8fe 100644 --- a/test/unit/schemaUtilsCommon.test.js +++ b/test/unit/schemaUtilsCommon.test.js @@ -1,5 +1,5 @@ -const schemaUtilsCommon = require('../../lib/common/schemaUtilsCommon'), - { formatDataPath, formatSchemaPathFromAJVErrorToConvertToDataPath } = require('../../lib/common/schemaUtilsCommon'), +const schemaUtilsCommon = require('../../lib/common/schemaUtilsCommon'); +const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../../lib/common/schemaUtilsCommon'), expect = require('chai').expect; describe('formatData method', function() { @@ -157,11 +157,10 @@ describe('handleExclusiveMinimum method', function() { }); }); -describe('formatSchemaPathFromAJVErrorToConvertToDataPath method', function () { +describe('formatSchemaPathToConverToDataPath method', function () { it('should return properties/automatic/items/properties/configs/items ' + 'when entry is #/properties/automatic/items/properties/configs/items/type', function () { - const result = - formatSchemaPathFromAJVErrorToConvertToDataPath('#/properties/automatic/items/properties/configs/items/type'); + const result = formatSchemaPathToConverToDataPath('#/properties/automatic/items/properties/configs/items/type'); expect(result).to.equal('properties/automatic/items/properties/configs/items'); }); }); From 30d2dc7d371822516cd3c646f23b4691d3a95c11 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 28 Feb 2022 09:54:41 -0600 Subject: [PATCH 10/13] Revert "Added support for reading schema with schemapath converted as datapath" This reverts commit d283fd81da3d0fbdac832088a1a6dab25eef7b78. --- lib/ajValidation/ajvValidation.js | 8 +++--- lib/common/schemaUtilsCommon.js | 40 +++-------------------------- test/unit/schemaUtilsCommon.test.js | 18 ++----------- 3 files changed, 8 insertions(+), 58 deletions(-) diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index 7b6ee93..b92cbd1 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -1,4 +1,4 @@ -const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../common/schemaUtilsCommon'); +const { formatDataPath } = require('../common/schemaUtilsCommon'); var _ = require('lodash'); const IGNORED_KEYWORDS = ['propertyNames', 'const', 'additionalItems', 'dependencies'], @@ -225,10 +225,8 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { } if (validationError.keyword === 'type') { - let schemaDataPath = formatDataPath(formatSchemaPathToConverToDataPath(validationError.schemaPath)), - schemaToUse = schemaDataPath ? _.get(schema, schemaDataPath) : schema, - valueToValidate = dataPath ? _.get(valueToUse, dataPath) : valueToUse; - return !isTypeValue(valueToValidate, + let schemaToUse = schema.hasOwnProperty('properties') ? _.get(schema, 'properties.' + dataPath) : schema; + return !isTypeValue(_.get(valueToUse, dataPath), schemaToUse); } diff --git a/lib/common/schemaUtilsCommon.js b/lib/common/schemaUtilsCommon.js index f19923e..d9619ad 100644 --- a/lib/common/schemaUtilsCommon.js +++ b/lib/common/schemaUtilsCommon.js @@ -4,28 +4,6 @@ const parse = require('../parse.js'); -/** - * Remove the # character from the beginning of a schema path - * @param {string} schemaPath - a defined schemaPath - * @returns {string} - the schema path with # removed - */ -function removeSharpAndSlashFromFirstPosition(schemaPath) { - return schemaPath[0] === '#' ? schemaPath.slice(2) : schemaPath; -} - -/** - * Remove the type from the last position of a schema path - * @param {string} schemaPath - a defined schemaPath - * @returns {string} - the schema path with type removed - */ -function removeTypeFromLastPosition(schemaPath) { - let splittedDataPath = schemaPath.split('/'); - if (splittedDataPath[splittedDataPath.length - 1] === 'type') { - splittedDataPath.splice(-1); - } - return splittedDataPath.join('/'); -} - module.exports = { /** @@ -76,21 +54,15 @@ module.exports = { isANumber = (value) => { return !isNaN(value); }, - formattedElements = splittedDataPath.map((element, index) => { + formattedElements = splittedDataPath.map((element) => { if (element !== '' && isANumber(element)) { return `[${element}]`; } - if (element === '' || element[0] === '.') { - return element; - } - if (index === 0 && !initialDotIfExist) { - return `${element}`; - } - return `.${element}`; + return element; }), formattedDataPath = formattedElements.join(''); - return `${formattedDataPath}`; + return `${initialDotIfExist}${formattedDataPath}`; }, handleExclusiveMaximum: function(schema, max) { @@ -129,11 +101,5 @@ module.exports = { } } return min; - }, - - formatSchemaPathToConverToDataPath: function (schemaPath) { - return removeTypeFromLastPosition(removeSharpAndSlashFromFirstPosition(schemaPath)); } - - }; diff --git a/test/unit/schemaUtilsCommon.test.js b/test/unit/schemaUtilsCommon.test.js index 503e8fe..04c9779 100644 --- a/test/unit/schemaUtilsCommon.test.js +++ b/test/unit/schemaUtilsCommon.test.js @@ -1,5 +1,5 @@ const schemaUtilsCommon = require('../../lib/common/schemaUtilsCommon'); -const { formatDataPath, formatSchemaPathToConverToDataPath } = require('../../lib/common/schemaUtilsCommon'), +const { formatDataPath } = require('../../lib/common/schemaUtilsCommon'), expect = require('chai').expect; describe('formatData method', function() { @@ -31,14 +31,6 @@ describe('formatData method', function() { expect(formattedDataPath).to.be.equal(expectedDataPath); }); - it('Should return "properties.automatic.items.properties.configs.items"' + - ' when input is "#/properties/automatic/items/properties/configs/items/type"', function() { - const input = 'properties/automatic/items/properties/configs/items', - expectedDataPath = 'properties.automatic.items.properties.configs.items', - formattedDataPath = formatDataPath(input); - expect(formattedDataPath).to.be.equal(expectedDataPath); - }); - }); describe('handleExclusiveMaximum method', function() { @@ -157,10 +149,4 @@ describe('handleExclusiveMinimum method', function() { }); }); -describe('formatSchemaPathToConverToDataPath method', function () { - it('should return properties/automatic/items/properties/configs/items ' + - 'when entry is #/properties/automatic/items/properties/configs/items/type', function () { - const result = formatSchemaPathToConverToDataPath('#/properties/automatic/items/properties/configs/items/type'); - expect(result).to.equal('properties/automatic/items/properties/configs/items'); - }); -}); + From 7e0aea4bdc7551470d578fd6797493bda33a3117 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 28 Feb 2022 09:54:44 -0600 Subject: [PATCH 11/13] Revert "WIP add support for more scenarios" This reverts commit 01ed77adf281fb7279a1dcbddb400dd9bdbdb792. --- lib/ajValidation/ajvValidation.js | 95 +----------------------- test/unit/xajvValidation.test.js | 115 ++---------------------------- 2 files changed, 9 insertions(+), 201 deletions(-) diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index b92cbd1..34b3f16 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -4,36 +4,7 @@ var _ = require('lodash'); const IGNORED_KEYWORDS = ['propertyNames', 'const', 'additionalItems', 'dependencies'], { validateSchemaAJV } = require('./ajvValidator'), { validateSchemaAJVDraft04 } = require('./ajvValidatorDraft04'), - specialDraft = 'http://json-schema.org/draft-04/schema#', - typesMap = { - integer: { - int32: '', - int64: '' - }, - number: { - float: '', - double: '' - }, - string: { - byte: '', - binary: '', - date: '', - 'date-time': '', - password: '' - }, - boolean: '' - }; - -/** - * Checks if value is postman variable or not - * - * @param {string} type - type to look for - * @param {string} format - format from schema - * @returns {Boolean} postman variable or not - */ -function getDefaultFromTypeAndFormat(type, format) { - return typesMap[type][format]; -} + specialDraft = 'http://json-schema.org/draft-04/schema#'; /** * Checks if value is postman variable or not @@ -80,68 +51,10 @@ function isTypeValueArrayCheck(value, types) { * @param {*} types - The types in the schemna * @returns {Boolean} the value is the representation of its type */ -function checkValueOnlyTypes(value, types) { +function isTypeValue(value, types) { return Array.isArray(types) ? isTypeValueArrayCheck(value, types) : compareType(value, types); } -/** - * Checks if value is the representation of its type like: - * "" - * Works in array types - * @param {string} value - Value to check for - * @param {*} types - The types in the schema - * @param {*} format - format from the schema - * @returns {Boolean} the value is the representation of its type - */ -function checkValueTypesAndFormat(value, types, format) { - let typesNotInMapp = [], - typesArray = Array.isArray(types) ? types : [types], - found = typesArray.find((type) => { - let defaultValue; - if (typesMap.hasOwnProperty(type)) { - defaultValue = getDefaultFromTypeAndFormat(type, format); - - // in case the format is a custom format (email, hostname etc.) - // https://swagger.io/docs/specification/data-models/data-types/#string - if (!defaultValue && format) { - defaultValue = '<' + format + '>'; - } - } - else { - typesNotInMapp.push(type); - } - return defaultValue === value; - }); - if (found) { - return true; - } - - found = typesNotInMapp.find((type) => { - let defaultValue; - defaultValue = '<' + type + (format ? ('-' + format) : '') + '>'; - return defaultValue === value; - }); - - return found !== undefined; -} - -/** - * Checks if value is the representation of its type like: - * "" - * Works in array types - * @param {string} value - Value to check for - * @param {*} schema - The schema portion used in validation - * @returns {Boolean} the value is the representation of its type - */ -function isTypeValue(value, schema) { - if (schema.hasOwnProperty('type') && !schema.hasOwnProperty('format')) { - return checkValueOnlyTypes(value, schema.type); - } - if (schema.hasOwnProperty('type') && schema.hasOwnProperty('format')) { - return checkValueTypesAndFormat(value, schema.type, schema.format); - } -} - /** * returns the local $schema value @@ -225,9 +138,7 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { } if (validationError.keyword === 'type') { - let schemaToUse = schema.hasOwnProperty('properties') ? _.get(schema, 'properties.' + dataPath) : schema; - return !isTypeValue(_.get(valueToUse, dataPath), - schemaToUse); + return !isTypeValue(_.get(valueToUse, dataPath), validationError.params.type); } return true; diff --git a/test/unit/xajvValidation.test.js b/test/unit/xajvValidation.test.js index 17f615a..109401d 100644 --- a/test/unit/xajvValidation.test.js +++ b/test/unit/xajvValidation.test.js @@ -358,57 +358,6 @@ describe('validateSchema', function () { result = validateSchema(schema, valueToUse); expect(result[0].instancePath).equal('/id'); }); - - it('Fix for GITHUB#479: should validate as correct input for type integer format int64', function () { - const schema = { - type: 'object', - properties: { - id: { - type: [ - 'integer' - ], - format: 'int64' - }, - hasPet: { - type: [ - 'boolean' - ] - } - } - }, - valueToUse = { - 'id': '', - 'hasPet': '' - }, - result = validateSchema(schema, valueToUse); - expect(result).to.be.empty; - }); - - it('Fix for GITHUB#479: should validate as correct input for type integer boolean format int64', function () { - const schema = { - type: 'object', - properties: { - id: { - type: [ - 'integer', - 'boolean' - ], - format: 'int64' - }, - hasPet: { - type: [ - 'boolean' - ] - } - } - }, - valueToUse = { - 'id': '', - 'hasPet': '' - }, - result = validateSchema(schema, valueToUse); - expect(result).to.be.empty; - }); }); describe('getDraftToUse', function() { @@ -436,79 +385,27 @@ describe('getDraftToUse', function() { describe('isTypeValue method', function () { it('should return true when value is and type is integer', function () { - const result = isTypeValue('', { - type: [ - 'integer' - ] - }); - expect(result).to.be.true; - }); - - it('should return true when input is type integer and format int64', function () { - const result = isTypeValue('', { - format: 'int64', - type: ['integer'] - }); - expect(result).to.be.true; - }); - - it('should return true when value is type is string format is uuid', function () { - const result = isTypeValue('', { - format: 'uuid', - type: ['string'] - }); - expect(result).to.be.true; - }); - - - it('should return true when value is type is otherType and there is not format', function () { - const result = isTypeValue('', { - type: ['otherType'] - }); - expect(result).to.be.true; - }); - - it('should return true value is type is otherType and format is otherFormat', function () { - const result = isTypeValue('', { - format: 'otherFormat', - type: ['otherType'] - }); + const result = isTypeValue('', ['integer']); expect(result).to.be.true; }); it('should return false when value is and type is boolean', function () { - const result = isTypeValue('', { - type: ['boolean'] - }); + const result = isTypeValue('', ['boolean']); expect(result).to.be.false; }); - it('should return true when value is and type is string', function () { - const result = isTypeValue('', { - type: ['string'] - }); + it('should return true when value is and type is string', function () { + const result = isTypeValue('', ['string']); expect(result).to.be.true; }); it('should return true when value is and type is ["boolean", "integer"]', function () { - const result = isTypeValue('', { - type: ['boolean', 'integer'] - }); + const result = isTypeValue('', ['boolean', 'integer']); expect(result).to.be.true; }); it('should return true when value is and type is integer not array', function () { - const result = isTypeValue('', { - type: 'integer' - }); - expect(result).to.be.true; - }); - - it('should return true when value is and type is integer not array format int64', function () { - const result = isTypeValue('', { - format: 'int64', - type: 'integer' - }); + const result = isTypeValue('', 'integer'); expect(result).to.be.true; }); From 9de5e64a583415769884d7e06718bb785fd0e1d9 Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 28 Feb 2022 09:54:46 -0600 Subject: [PATCH 12/13] Revert "values like in validation" This reverts commit 6da18650413ce2a0a9f1ffe44fc6b2cee483adb0. --- lib/ajValidation/ajvValidation.js | 47 +------- test/data/31CollectionTransactions/479.yaml | 32 ------ .../data/31CollectionTransactions/479col.json | 105 ------------------ test/unit/x31schemapack.test.js | 21 ---- test/unit/xajvValidation.test.js | 84 -------------- 5 files changed, 1 insertion(+), 288 deletions(-) delete mode 100644 test/data/31CollectionTransactions/479.yaml delete mode 100644 test/data/31CollectionTransactions/479col.json diff --git a/lib/ajValidation/ajvValidation.js b/lib/ajValidation/ajvValidation.js index 34b3f16..bd80363 100644 --- a/lib/ajValidation/ajvValidation.js +++ b/lib/ajValidation/ajvValidation.js @@ -17,45 +17,6 @@ function isPmVariable (value) { return _.isString(value) && _.startsWith(value, '{{') && _.endsWith(value, '}}'); } -/** - * Checks if value is the representation of its type like: - * "" - * - * @param {string} value - Value to check for - * @param {string} type - The type in the schemna - * @returns {Boolean} the value is the representation of its type - */ -function compareType(value, type) { - return value === '<' + type + '>'; -} - -/** - * Checks if value is the representation of its type like: - * "" - * Works in array types - * @param {string} value - Value to check for - * @param {*} types - The types in the schemna - * @returns {Boolean} the value is the representation of its type - */ -function isTypeValueArrayCheck(value, types) { - return types.find((type) => { - return compareType(value, type); - }) !== undefined; -} - -/** - * Checks if value is the representation of its type like: - * "" - * Works in array types - * @param {string} value - Value to check for - * @param {*} types - The types in the schemna - * @returns {Boolean} the value is the representation of its type - */ -function isTypeValue(value, types) { - return Array.isArray(types) ? isTypeValueArrayCheck(value, types) : compareType(value, types); -} - - /** * returns the local $schema value * @@ -136,11 +97,6 @@ function validateSchema (schema, valueToUse, options = {}, jsonSchemaDialect) { isPmVariable(dataPath === '' ? valueToUse : _.get(valueToUse, dataPath))) { return false; } - - if (validationError.keyword === 'type') { - return !isTypeValue(_.get(valueToUse, dataPath), validationError.params.type); - } - return true; }); @@ -154,6 +110,5 @@ module.exports = { validateSchema, getLocalDraft, getAjvValidator, - getDraftToUse, - isTypeValue + getDraftToUse }; diff --git a/test/data/31CollectionTransactions/479.yaml b/test/data/31CollectionTransactions/479.yaml deleted file mode 100644 index 3b9acdf..0000000 --- a/test/data/31CollectionTransactions/479.yaml +++ /dev/null @@ -1,32 +0,0 @@ -openapi: "3.1.0" -info: - version: 1.0.0 - title: Swagger Petstore - license: - name: MIT -servers: - - url: http://petstore.swagger.io/v1 -paths: - /pets/anyOf: - post: - summary: issue 479 - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/example" - responses: - default: - description: ok -components: - schemas: - example: - type: - - object - properties: - id: - type: - - integer - hasPet: - type: - - boolean diff --git a/test/data/31CollectionTransactions/479col.json b/test/data/31CollectionTransactions/479col.json deleted file mode 100644 index 715c104..0000000 --- a/test/data/31CollectionTransactions/479col.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "item": [ - { - "id": "c3a2f66d-f91e-45ec-9116-4ce926acb630", - "name": "pets", - "item": [ - { - "id": "25758366-55ed-4370-90fd-1e1be8536b0b", - "name": "issue 479", - "request": { - "name": "composite schema with anyOf keyword", - "description": {}, - "url": { - "path": [ - "pets", - "anyOf" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [] - }, - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "method": "POST", - "auth": null, - "body": { - "mode": "raw", - "raw": "{ \"id\": \"\", \"hasPet\": \"\" }", - "options": { - "raw": { - "language": "json" - } - } - } - }, - "response": [ - { - "id": "f4f6ddf5-d259-45b7-89fe-086cc22a6549", - "name": "ok", - "originalRequest": { - "url": { - "path": [ - "pets", - "anyOf" - ], - "host": [ - "{{baseUrl}}" - ], - "query": [], - "variable": [] - }, - "method": "POST", - "body": { - "mode": "raw", - "raw": "{ \"id\": \"\", \"hasPet\": \"\" }", - "options": { - "raw": { - "language": "json" - } - } - } - }, - "status": "Internal Server Error", - "code": 500, - "header": [ - { - "key": "Content-Type", - "value": "text/plain" - } - ], - "body": "", - "cookie": [], - "_postman_previewlanguage": "text" - } - ], - "event": [] - } - ], - "event": [] - } - ], - "event": [], - "variable": [ - { - "type": "string", - "value": "http://petstore.swagger.io/v1", - "key": "baseUrl" - } - ], - "info": { - "_postman_id": "b498d8c3-e6e5-4a72-92de-e5c455786a8e", - "name": "Swagger Petstore", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "description": { - "content": "", - "type": "text/plain" - } - } -} diff --git a/test/unit/x31schemapack.test.js b/test/unit/x31schemapack.test.js index 3a299fd..d1a3fcd 100644 --- a/test/unit/x31schemapack.test.js +++ b/test/unit/x31schemapack.test.js @@ -145,27 +145,6 @@ describe('Openapi 3.1 schema pack validateTransactions', function() { }); } - it('Fix for GITHUB#479: Should accept values like in validation', function() { - const collectionSource = path.join(__dirname, OPENAPI_31_COLLECTIONS + '/479col.json'), - collectionData = fs.readFileSync(collectionSource, 'utf8'), - schemaSource = path.join(__dirname, OPENAPI_31_COLLECTIONS + '/479.yaml'), - schemaData = fs.readFileSync(schemaSource, 'utf8'), - validator = new SchemaPack({ - type: 'string', - data: schemaData - }); - let transactions = []; - getAllTransactions(JSON.parse(collectionData), transactions); - - validator.validateTransaction(transactions, (err, result) => { - let requestIds = Object.keys(result.requests); - expect(err).to.be.null; - requestIds.forEach((requestId) => { - expect(result.requests[requestId].endpoints[0].matched).to.be.true; - }); - }); - }); - it('Should not generate any mismatch with a correct file', function() { const collectionSource = path.join(__dirname, OPENAPI_31_COLLECTIONS + '/compositeSchemaCollection.json'), collectionData = fs.readFileSync(collectionSource, 'utf8'), diff --git a/test/unit/xajvValidation.test.js b/test/unit/xajvValidation.test.js index 109401d..7daad7d 100644 --- a/test/unit/xajvValidation.test.js +++ b/test/unit/xajvValidation.test.js @@ -1,7 +1,6 @@ const { getLocalDraft, getAjvValidator, validateSchema, - isTypeValue, getDraftToUse } = require('../../lib/ajValidation/ajvValidation'), { validateSchemaAJVDraft04 } = require('../../lib/ajValidation/ajvValidatorDraft04'), expect = require('chai').expect; @@ -303,61 +302,6 @@ describe('validateSchema', function () { result = validateSchemaAJVDraft04(null, valueToUse); expect(result.filteredValidationError).to.be.undefined; }); - - it('Fix for GITHUB#479: should validate as correct input for type integer', function () { - const schema = { - type: 'object', - properties: { - id: { - type: [ - 'integer', - 'boolean' - ], - examples: [ - 111111 - ] - }, - hasPet: { - type: [ - 'boolean' - ] - } - } - }, - valueToUse = { - 'id': '', - 'hasPet': '' - }, - result = validateSchema(schema, valueToUse); - expect(result).to.be.empty; - }); - - it('Fix for GITHUB#479: should validate as incorrect input for type integer', function () { - const schema = { - type: 'object', - properties: { - id: { - type: [ - 'integer' - ], - examples: [ - 111111 - ] - }, - hasPet: { - type: [ - 'boolean' - ] - } - } - }, - valueToUse = { - 'id': '', - 'hasPet': '' - }, - result = validateSchema(schema, valueToUse); - expect(result[0].instancePath).equal('/id'); - }); }); describe('getDraftToUse', function() { @@ -382,31 +326,3 @@ describe('getDraftToUse', function() { expect(draftToUse).to.equal(undefined); }); }); - -describe('isTypeValue method', function () { - it('should return true when value is and type is integer', function () { - const result = isTypeValue('', ['integer']); - expect(result).to.be.true; - }); - - it('should return false when value is and type is boolean', function () { - const result = isTypeValue('', ['boolean']); - expect(result).to.be.false; - }); - - it('should return true when value is and type is string', function () { - const result = isTypeValue('', ['string']); - expect(result).to.be.true; - }); - - it('should return true when value is and type is ["boolean", "integer"]', function () { - const result = isTypeValue('', ['boolean', 'integer']); - expect(result).to.be.true; - }); - - it('should return true when value is and type is integer not array', function () { - const result = isTypeValue('', 'integer'); - expect(result).to.be.true; - }); - -}); From e39b9649f460ff2c542cc007171bbf6d84e089bf Mon Sep 17 00:00:00 2001 From: Luis Tejeda <46000487+LuisTejedaS@users.noreply.github.com> Date: Mon, 28 Feb 2022 11:08:13 -0600 Subject: [PATCH 13/13] Added null test in bodies Added null examples in request body and response body --- lib/schemaUtils.js | 2 +- test/data/valid_openapi/issue#10229.json | 26 +++++++++++++++++++++--- test/unit/base.test.js | 2 ++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/schemaUtils.js b/lib/schemaUtils.js index 91043c9..bec862d 100644 --- a/lib/schemaUtils.js +++ b/lib/schemaUtils.js @@ -406,7 +406,7 @@ module.exports = { let example = _.get(parameter, 'example'), examples = _.values(_.get(parameter, 'examples')); - if (example !== undefined && example !== null) { + if (example !== undefined) { _.set(parameter, 'schema.example', example); } else if (examples) { diff --git a/test/data/valid_openapi/issue#10229.json b/test/data/valid_openapi/issue#10229.json index 7a784f3..5dbc306 100644 --- a/test/data/valid_openapi/issue#10229.json +++ b/test/data/valid_openapi/issue#10229.json @@ -1,5 +1,5 @@ { - "openapi": "3.0.0", + "openapi": "3.1.0", "info": { "version": "1.0.0", "title": "#10229", @@ -59,7 +59,6 @@ }, "example": "" }, - { "name": "otherBoolean", "in": "query", @@ -108,6 +107,21 @@ "tags": [ "pets" ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "a": { + "type": "null", + "example": null + } + } + } + } + } + }, "responses": { "201": { "description": "Null response" @@ -117,7 +131,13 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Error" + "type": "object", + "properties": { + "a": { + "type": "null", + "example": null + } + } } } } diff --git a/test/unit/base.test.js b/test/unit/base.test.js index b289c67..7317cd3 100644 --- a/test/unit/base.test.js +++ b/test/unit/base.test.js @@ -408,6 +408,8 @@ describe('CONVERT FUNCTION TESTS ', function() { expect(conversionResult.output[0].data.item[0].item[0].request.url.query[0].value).to.equal('0'); expect(conversionResult.output[0].data.item[0].item[0].request.url.query[1].value).to.equal(''); expect(conversionResult.output[0].data.item[0].item[0].request.url.query[2].value).to.equal('false'); + expect(conversionResult.output[0].data.item[0].item[1].request.body.raw).to.equal('{\n "a": null\n}'); + expect(conversionResult.output[0].data.item[0].item[1].response[1].body).to.equal('{\n "a": null\n}'); done(); }); });