diff --git a/src/plugins/validation/2and3/semantic-validators/schema-ibm.js b/src/plugins/validation/2and3/semantic-validators/schema-ibm.js index 181f36da3..0175594f7 100644 --- a/src/plugins/validation/2and3/semantic-validators/schema-ibm.js +++ b/src/plugins/validation/2and3/semantic-validators/schema-ibm.js @@ -79,7 +79,7 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { }); schemas.forEach(({ schema, path }) => { - let res = generateFormatErrors(schema, path, config); + let res = generateFormatErrors(schema, path, config, isOAS3); errors.push(...res.error); warnings.push(...res.warning); @@ -104,7 +104,7 @@ module.exports.validate = function({ jsSpec, isOAS3 }, config) { // Flag as an error any property that does not have a recognized "type" and "format" according to the // [Swagger 2.0 spec](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types) -function generateFormatErrors(schema, contextPath, config) { +function generateFormatErrors(schema, contextPath, config, isOAS3) { const result = {}; result.error = []; result.warning = []; @@ -125,7 +125,7 @@ function generateFormatErrors(schema, contextPath, config) { } checkStatus = config.invalid_type_format_pair; - if (checkStatus !== 'off' && !formatValid(schema)) { + if (checkStatus !== 'off' && !formatValid(schema, contextPath, isOAS3)) { const path = contextPath.concat(['type']); const message = 'Property type+format is not well-defined.'; result[checkStatus].push({ path, message }); @@ -134,7 +134,7 @@ function generateFormatErrors(schema, contextPath, config) { return result; } -function formatValid(property) { +function formatValid(property, path, isOAS3) { if (property.$ref) { return true; } @@ -169,6 +169,12 @@ function formatValid(property) { case 'array': valid = true; break; + case 'file': + // schemas of type file are allowed in swagger2 for responses and parameters + // of type 'formData' - the violating parameters are caught by parameters-ibm + // note: type file is only allowed for root schemas (not properties, etc.) + valid = !isOAS3 && isRootSchema(path); + break; default: valid = false; } @@ -303,3 +309,17 @@ function checkEnumValues(schema, contextPath, config) { return result; } + +// NOTE: this function is Swagger 2 specific and would need to be adapted to be used with OAS +function isRootSchema(path) { + const current = path[path.length - 1]; + const parent = path[path.length - 2]; + + // `schema` can only exist in parameter or response objects + // root schemas can also appear under a variable key in the `definitions` section + // if it is the top level `definitions` section (rather than some property named "definitions"), + // the path length will be 2 + return ( + current === 'schema' || (parent === 'definitions' && path.length === 2) + ); +} diff --git a/test/plugins/validation/2and3/schema-ibm.js b/test/plugins/validation/2and3/schema-ibm.js index fb4bad1af..9b5a37c5a 100644 --- a/test/plugins/validation/2and3/schema-ibm.js +++ b/test/plugins/validation/2and3/schema-ibm.js @@ -159,6 +159,105 @@ describe('validation plugin - semantic - schema-ibm - Swagger 2', () => { expect(res.warnings.length).toEqual(0); }); + it('should non return an error for a response schema of type file', () => { + const config = { + schemas: { + invalid_type_format_pair: 'error' + } + }; + + const spec = { + paths: { + '/pets': { + get: { + responses: { + '200': { + description: 'legal response', + schema: { + type: 'file' + } + } + } + } + } + } + }; + + const res = validate({ jsSpec: spec }, config); + expect(res.errors.length).toEqual(0); + expect(res.warnings.length).toEqual(0); + }); + + it('should non return an error for a definition with root type of file', () => { + const config = { + schemas: { + invalid_type_format_pair: 'error' + } + }; + + const spec = { + definitions: { + SomeSchema: { + type: 'file', + description: 'file schema, used for parameter or response' + } + } + }; + + const res = validate({ jsSpec: spec }, config); + expect(res.errors.length).toEqual(0); + expect(res.warnings.length).toEqual(0); + }); + + it('should return an error for a response schema with non-root type file', () => { + const config = { + schemas: { + invalid_type_format_pair: 'error' + } + }; + + const spec = { + paths: { + '/pets': { + get: { + responses: { + '200': { + description: 'legal response', + schema: { + properties: { + this_is_bad: { + type: 'file', + description: 'non-root type of file is bad' + } + } + } + } + } + } + } + } + }; + + const res = validate({ jsSpec: spec }, config); + expect(res.errors.length).toEqual(1); + expect(res.errors[0].path).toEqual([ + 'paths', + '/pets', + 'get', + 'responses', + '200', + 'schema', + 'properties', + 'this_is_bad', + 'type' + ]); + expect(res.errors[0].message).toEqual( + 'Property type+format is not well-defined.' + ); + + expect(res.warnings.length).toEqual(0); + }); + it('should return a warning when a property name is not snake case', () => { const config = { schemas: { @@ -574,7 +673,7 @@ describe('validation plugin - semantic - schema-ibm - OpenAPI 3', () => { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ jsSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(1); expect(res.errors[0].path).toEqual([ 'components', @@ -593,6 +692,52 @@ describe('validation plugin - semantic - schema-ibm - OpenAPI 3', () => { expect(res.warnings.length).toEqual(0); }); + it('should return an error for a response schema of type file', () => { + const config = { + schemas: { + invalid_type_format_pair: 'error' + } + }; + + const spec = { + paths: { + '/pets': { + get: { + responses: { + '200': { + content: { + 'application/json': { + schema: { + type: 'file' + } + } + } + } + } + } + } + } + }; + + const res = validate({ jsSpec: spec, isOAS3: true }, config); + expect(res.errors.length).toEqual(1); + expect(res.errors[0].path).toEqual([ + 'paths', + '/pets', + 'get', + 'responses', + '200', + 'content', + 'application/json', + 'schema', + 'type' + ]); + expect(res.errors[0].message).toEqual( + 'Property type+format is not well-defined.' + ); + expect(res.warnings.length).toEqual(0); + }); + it('should not validate an example when it contains the resemblence of a problem', () => { const config = { schemas: { @@ -638,7 +783,7 @@ describe('validation plugin - semantic - schema-ibm - OpenAPI 3', () => { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ jsSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(1); expect(res.errors[0].path).toEqual([ 'paths', @@ -704,7 +849,7 @@ describe('validation plugin - semantic - schema-ibm - OpenAPI 3', () => { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ jsSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(1); expect(res.warnings[0].path).toEqual([ @@ -750,7 +895,7 @@ describe('validation plugin - semantic - schema-ibm - OpenAPI 3', () => { } }; - const res = validate({ jsSpec: spec }, config); + const res = validate({ jsSpec: spec, isOAS3: true }, config); expect(res.errors.length).toEqual(0); expect(res.warnings.length).toEqual(1); expect(res.warnings[0].path).toEqual([