Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(validation): enum values should conform to their schema's type #2079

Merged
merged 7 commits into from
Jan 11, 2020
32 changes: 32 additions & 0 deletions src/plugins/validate-semantic/validators/2and3/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,35 @@ export const validate2And3TypeArrayRequiresItems = () => (system) => {
}, [])
})
}

export const validate2And3TypesInDefaultValuesMatchesWithEnum = () => (system) => {
return system.validateSelectors
.allSchemas()
.then(nodes => {
return nodes.reduce((acc, node) => {
const schemaObj = node.node
const { type, items } = schemaObj || {}
const enumeration = schemaObj.enum
var isValidFormat = true
enumeration.forEach(element => {
if (type === "array" && (!Array.isArray(element) || element === null)) {
isValidFormat = false
} else if ((type === "number" || type === "string" || type === "boolean") && !(typeof element === type)) {
isValidFormat = false
} else if (type === "integer" && !Number.isInteger(element)) {
isValidFormat = false
} else if (type === "object" && ((element == null) || !(typeof element === type))) {
isValidFormat = false
}
});
if (!isValidFormat) {
acc.push({
message: "enum value should conform to its schema's `type`",
path: [...node.path, "enum"],
level: "warning",
});
}
return acc
}, [])
})
}
309 changes: 309 additions & 0 deletions test/unit/plugins/validate-semantic/2and3/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,312 @@ describe(`validation plugin - semantic - 2and3 schemas`, () => {
})
})
})

describe(`values in Enum must be instance of the defined type`, () => {
// Numbers tests
it("should return an error for a text value in a enum number type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "number",
in: "query",
schema: {
type: "number",
enum: [1, Text, 3]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
const firstError = allErrors[0]
expect(allErrors.length).toEqual(1)
expect(firstError.level).toEqual("warning")
expect(firstError.message).toEqual("enum value should conform to its schema's `type`")
})
})

it("should return an error for a number value inside quotes in a enum number type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "number",
in: "query",
schema: {
type: "number",
enum: [1, "2", 3]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
const firstError = allErrors[0]
expect(allErrors.length).toEqual(1)
expect(firstError.level).toEqual("warning")
expect(firstError.message).toEqual("enum value should conform to its schema's `type`")
})
})

it("should not return an error when all items are number in a enum number type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "number",
in: "query",
schema: {
type: "number",
enum: [1, 2, 3]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
expect(allErrors.length).toEqual(0)
})
})

//Array Tests

it("should return an error for a non array value in a enum array type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "arraySample",
in: "query",
schema: {
type: "array",
enum: [1, 2, 3]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
const secondError = allErrors[1]
expect(allErrors.length).toEqual(2)
expect(secondError.level).toEqual("warning")
expect(secondError.message).toEqual("enum value should conform to its schema's `type`")
expect(secondError.level).toEqual("warning")
expect(secondError.message).toEqual("enum value should conform to its schema's `type`")
})
})

it("should not return an error when all items are array in a enum array type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "arraySample",
in: "query",
schema: {
type: "array",
enum: [[1,2],[3,4]]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
expect(allErrors.length).toEqual(1)
})
})

//Object Tests

it("should return an error for a non object value (array) in a enum object type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "objectSample",
in: "query",
schema: {
type: "object",
enum: [[1,3], 2, 3]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
const firstError = allErrors[0]
expect(allErrors.length).toEqual(1)
expect(firstError.level).toEqual("warning")
expect(firstError.message).toEqual("enum value should conform to its schema's `type`")
})
})

it("should return an error for a null value in a enum object type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "objectSample",
in: "query",
schema: {
type: "object",
enum: [null]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
const firstError = allErrors[0]
expect(allErrors.length).toEqual(1)
expect(firstError.level).toEqual("warning")
expect(firstError.message).toEqual("enum value should conform to its schema's `type`")
})
})

it("should not return an error when all items are array in a enum array type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "objectSample",
in: "query",
schema: {
type: "object",
enum: [{ok: "Sample"},{}]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
expect(allErrors.length).toEqual(0)
})
})

//Boolean Tests

it("should return an error for a non boolean value in a boolean array type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "booleanEnum",
in: "query",
schema: {
type: "boolean",
enum: [1, true, false]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
const firstError = allErrors[0]
expect(allErrors.length).toEqual(1)
expect(firstError.level).toEqual("warning")
expect(firstError.message).toEqual("enum value should conform to its schema's `type`")
})
})

it("should not return an error when all items are boolean in a boolean array type in OpenApi 3", () => {
const spec = {
openapi: "3.0.0",
"paths": {
"/pets": {
"get": {
"parameters": [
{
name: "booleanEnum",
in: "query",
schema: {
type: "boolean",
enum: [true, false]
}
},
]
}
}
}
}

return validateHelper(spec)
.then(system => {
const allErrors = system.errSelectors.allErrors().toJS()
expect(allErrors.length).toEqual(0)
})
})
})