mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
518 lines
14 KiB
Go
518 lines
14 KiB
Go
// Copyright 2015 go-swagger maintainers
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package validate
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/go-openapi/errors"
|
|
"github.com/go-openapi/spec"
|
|
"github.com/go-openapi/strfmt"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type email struct {
|
|
Address string
|
|
}
|
|
|
|
type paramFactory func(string) *spec.Parameter
|
|
|
|
var paramFactories = []paramFactory{
|
|
spec.QueryParam,
|
|
spec.HeaderParam,
|
|
spec.PathParam,
|
|
spec.FormDataParam,
|
|
}
|
|
|
|
var stringItems = new(spec.Items)
|
|
|
|
func init() {
|
|
stringItems.Type = "string"
|
|
}
|
|
|
|
func requiredError(param *spec.Parameter) *errors.Validation {
|
|
return errors.Required(param.Name, param.In)
|
|
}
|
|
|
|
func maxErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.ExceedsMaximum(path, in, *items.Maximum, items.ExclusiveMaximum)
|
|
}
|
|
|
|
func minErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.ExceedsMinimum(path, in, *items.Minimum, items.ExclusiveMinimum)
|
|
}
|
|
|
|
func multipleOfErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.NotMultipleOf(path, in, *items.MultipleOf)
|
|
}
|
|
|
|
func requiredErrorItems(path, in string) *errors.Validation {
|
|
return errors.Required(path, in)
|
|
}
|
|
|
|
func maxLengthErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.TooLong(path, in, *items.MaxLength)
|
|
}
|
|
|
|
func minLengthErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.TooShort(path, in, *items.MinLength)
|
|
}
|
|
|
|
func patternFailItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.FailedPattern(path, in, items.Pattern)
|
|
}
|
|
|
|
func enumFailItems(path, in string, items *spec.Items, data interface{}) *errors.Validation {
|
|
return errors.EnumFail(path, in, data, items.Enum)
|
|
}
|
|
|
|
func minItemsErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.TooFewItems(path, in, *items.MinItems)
|
|
}
|
|
|
|
func maxItemsErrorItems(path, in string, items *spec.Items) *errors.Validation {
|
|
return errors.TooManyItems(path, in, *items.MaxItems)
|
|
}
|
|
|
|
func duplicatesErrorItems(path, in string) *errors.Validation {
|
|
return errors.DuplicateItems(path, in)
|
|
}
|
|
|
|
func TestNumberItemsValidation(t *testing.T) {
|
|
|
|
values := [][]interface{}{
|
|
[]interface{}{23, 49, 56, 21, 14, 35, 28, 7, 42},
|
|
[]interface{}{uint(23), uint(49), uint(56), uint(21), uint(14), uint(35), uint(28), uint(7), uint(42)},
|
|
[]interface{}{float64(23), float64(49), float64(56), float64(21), float64(14), float64(35), float64(28), float64(7), float64(42)},
|
|
}
|
|
|
|
for i, v := range values {
|
|
items := spec.NewItems()
|
|
items.WithMaximum(makeFloat(v[1]), false)
|
|
items.WithMinimum(makeFloat(v[3]), false)
|
|
items.WithMultipleOf(makeFloat(v[7]))
|
|
items.WithEnum(v[3], v[6], v[8], v[1])
|
|
items.Typed("integer", "int32")
|
|
parent := spec.QueryParam("factors").CollectionOf(items, "")
|
|
path := fmt.Sprintf("factors.%d", i)
|
|
validator := newItemsValidator(parent.Name, parent.In, items, parent, strfmt.Default)
|
|
|
|
// MultipleOf
|
|
err := validator.Validate(i, v[0])
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, multipleOfErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// Maximum
|
|
err = validator.Validate(i, v[1])
|
|
assert.True(t, err == nil || err.IsValid())
|
|
err = validator.Validate(i, v[2])
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, maxErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// ExclusiveMaximum
|
|
items.ExclusiveMaximum = true
|
|
// requires a new items validator because this is set a creation time
|
|
validator = newItemsValidator(parent.Name, parent.In, items, parent, strfmt.Default)
|
|
err = validator.Validate(i, v[1])
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, maxErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// Minimum
|
|
err = validator.Validate(i, v[3])
|
|
assert.True(t, err == nil || err.IsValid())
|
|
err = validator.Validate(i, v[4])
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, minErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// ExclusiveMinimum
|
|
items.ExclusiveMinimum = true
|
|
// requires a new items validator because this is set a creation time
|
|
validator = newItemsValidator(parent.Name, parent.In, items, parent, strfmt.Default)
|
|
err = validator.Validate(i, v[3])
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, minErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// Enum
|
|
err = validator.Validate(i, v[5])
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, enumFailItems(path, validator.in, items, v[5]), err.Errors[0].Error())
|
|
|
|
// Valid passes
|
|
err = validator.Validate(i, v[6])
|
|
assert.True(t, err == nil || err.IsValid())
|
|
}
|
|
|
|
}
|
|
|
|
func TestStringItemsValidation(t *testing.T) {
|
|
items := spec.NewItems().WithMinLength(3).WithMaxLength(5).WithPattern(`^[a-z]+$`).Typed("string", "")
|
|
items.WithEnum("aaa", "bbb", "ccc")
|
|
parent := spec.QueryParam("tags").CollectionOf(items, "")
|
|
path := parent.Name + ".1"
|
|
validator := newItemsValidator(parent.Name, parent.In, items, parent, strfmt.Default)
|
|
|
|
// required
|
|
err := validator.Validate(1, "")
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, minLengthErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// MaxLength
|
|
err = validator.Validate(1, "abcdef")
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, maxLengthErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// MinLength
|
|
err = validator.Validate(1, "a")
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, minLengthErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// Pattern
|
|
err = validator.Validate(1, "a394")
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, patternFailItems(path, validator.in, items), err.Errors[0].Error())
|
|
|
|
// Enum
|
|
err = validator.Validate(1, "abcde")
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, enumFailItems(path, validator.in, items, "abcde"), err.Errors[0].Error())
|
|
|
|
// Valid passes
|
|
err = validator.Validate(1, "bbb")
|
|
assert.True(t, err == nil || err.IsValid())
|
|
}
|
|
|
|
func TestArrayItemsValidation(t *testing.T) {
|
|
items := spec.NewItems().CollectionOf(stringItems, "").WithMinItems(1).WithMaxItems(5).UniqueValues()
|
|
items.WithEnum("aaa", "bbb", "ccc")
|
|
parent := spec.QueryParam("tags").CollectionOf(items, "")
|
|
path := parent.Name + ".1"
|
|
validator := newItemsValidator(parent.Name, parent.In, items, parent, strfmt.Default)
|
|
|
|
// MinItems
|
|
err := validator.Validate(1, []string{})
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, minItemsErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
// MaxItems
|
|
err = validator.Validate(1, []string{"a", "b", "c", "d", "e", "f"})
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, maxItemsErrorItems(path, validator.in, items), err.Errors[0].Error())
|
|
// UniqueItems
|
|
err = validator.Validate(1, []string{"a", "a"})
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, duplicatesErrorItems(path, validator.in), err.Errors[0].Error())
|
|
|
|
// Enum
|
|
err = validator.Validate(1, []string{"a", "b", "c"})
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, enumFailItems(path, validator.in, items, []string{"a", "b", "c"}), err.Errors[0].Error())
|
|
|
|
// Items
|
|
strItems := spec.NewItems().WithMinLength(3).WithMaxLength(5).WithPattern(`^[a-z]+$`).Typed("string", "")
|
|
items = spec.NewItems().CollectionOf(strItems, "").WithMinItems(1).WithMaxItems(5).UniqueValues()
|
|
validator = newItemsValidator(parent.Name, parent.In, items, parent, strfmt.Default)
|
|
|
|
err = validator.Validate(1, []string{"aa", "bbb", "ccc"})
|
|
assert.True(t, err.HasErrors())
|
|
assert.EqualError(t, minLengthErrorItems(path+".0", parent.In, strItems), err.Errors[0].Error())
|
|
}
|
|
|
|
// PetStoreJSONMessage json raw message for Petstore20
|
|
var PetStoreJSONMessage = json.RawMessage([]byte(PetStore20))
|
|
|
|
// PetStore20 json doc for swagger 2.0 pet store
|
|
const PetStore20 = `{
|
|
"swagger": "2.0",
|
|
"info": {
|
|
"version": "1.0.0",
|
|
"title": "Swagger Petstore",
|
|
"contact": {
|
|
"name": "Wordnik API Team",
|
|
"url": "http://developer.wordnik.com"
|
|
},
|
|
"license": {
|
|
"name": "Creative Commons 4.0 International",
|
|
"url": "http://creativecommons.org/licenses/by/4.0/"
|
|
}
|
|
},
|
|
"host": "petstore.swagger.wordnik.com",
|
|
"basePath": "/api",
|
|
"schemes": [
|
|
"http"
|
|
],
|
|
"paths": {
|
|
"/pets": {
|
|
"get": {
|
|
"security": [
|
|
{
|
|
"basic": []
|
|
}
|
|
],
|
|
"tags": [ "Pet Operations" ],
|
|
"operationId": "getAllPets",
|
|
"parameters": [
|
|
{
|
|
"name": "status",
|
|
"in": "query",
|
|
"description": "The status to filter by",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"name": "limit",
|
|
"in": "query",
|
|
"description": "The maximum number of results to return",
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
],
|
|
"summary": "Finds all pets in the system",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Pet response",
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/definitions/Pet"
|
|
}
|
|
}
|
|
},
|
|
"default": {
|
|
"description": "Unexpected error",
|
|
"schema": {
|
|
"$ref": "#/definitions/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"security": [
|
|
{
|
|
"basic": []
|
|
}
|
|
],
|
|
"tags": [ "Pet Operations" ],
|
|
"operationId": "createPet",
|
|
"summary": "Creates a new pet",
|
|
"consumes": ["application/x-yaml"],
|
|
"produces": ["application/x-yaml"],
|
|
"parameters": [
|
|
{
|
|
"name": "pet",
|
|
"in": "body",
|
|
"description": "The Pet to create",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/definitions/newPet"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Created Pet response",
|
|
"schema": {
|
|
"$ref": "#/definitions/Pet"
|
|
}
|
|
},
|
|
"default": {
|
|
"description": "Unexpected error",
|
|
"schema": {
|
|
"$ref": "#/definitions/Error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/pets/{id}": {
|
|
"delete": {
|
|
"security": [
|
|
{
|
|
"apiKey": []
|
|
}
|
|
],
|
|
"description": "Deletes the Pet by id",
|
|
"operationId": "deletePet",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "ID of pet to delete",
|
|
"required": true,
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "pet deleted"
|
|
},
|
|
"default": {
|
|
"description": "unexpected error",
|
|
"schema": {
|
|
"$ref": "#/definitions/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"get": {
|
|
"tags": [ "Pet Operations" ],
|
|
"operationId": "getPetById",
|
|
"summary": "Finds the pet by id",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Pet response",
|
|
"schema": {
|
|
"$ref": "#/definitions/Pet"
|
|
}
|
|
},
|
|
"default": {
|
|
"description": "Unexpected error",
|
|
"schema": {
|
|
"$ref": "#/definitions/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "ID of pet",
|
|
"required": true,
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"definitions": {
|
|
"Category": {
|
|
"id": "Category",
|
|
"properties": {
|
|
"id": {
|
|
"format": "int64",
|
|
"type": "integer"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Pet": {
|
|
"id": "Pet",
|
|
"properties": {
|
|
"category": {
|
|
"$ref": "#/definitions/Category"
|
|
},
|
|
"id": {
|
|
"description": "unique identifier for the pet",
|
|
"format": "int64",
|
|
"maximum": 100.0,
|
|
"minimum": 0.0,
|
|
"type": "integer"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"photoUrls": {
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
},
|
|
"status": {
|
|
"description": "pet status in the store",
|
|
"enum": [
|
|
"available",
|
|
"pending",
|
|
"sold"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"tags": {
|
|
"items": {
|
|
"$ref": "#/definitions/Tag"
|
|
},
|
|
"type": "array"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name"
|
|
]
|
|
},
|
|
"newPet": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/definitions/Pet"
|
|
},
|
|
{
|
|
"required": [
|
|
"name"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"Tag": {
|
|
"id": "Tag",
|
|
"properties": {
|
|
"id": {
|
|
"format": "int64",
|
|
"type": "integer"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Error": {
|
|
"required": [
|
|
"code",
|
|
"message"
|
|
],
|
|
"properties": {
|
|
"code": {
|
|
"type": "integer",
|
|
"format": "int32"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"consumes": [
|
|
"application/json",
|
|
"application/xml"
|
|
],
|
|
"produces": [
|
|
"application/json",
|
|
"application/xml",
|
|
"text/plain",
|
|
"text/html"
|
|
],
|
|
"securityDefinitions": {
|
|
"basic": {
|
|
"type": "basic"
|
|
},
|
|
"apiKey": {
|
|
"type": "apiKey",
|
|
"in": "header",
|
|
"name": "X-API-KEY"
|
|
}
|
|
}
|
|
}
|
|
`
|