bump(go-openapi/validate): d509235108fcf6ab4913d2dcb3a2260c0db2108e

pull/6/head
Nikhita Raghunath 2017-11-22 16:34:36 +05:30
parent 2b530438f1
commit 66a4e5122a
17 changed files with 301 additions and 116 deletions

2
Godeps/Godeps.json generated
View File

@ -1263,7 +1263,7 @@
},
{
"ImportPath": "github.com/go-openapi/validate",
"Rev": "deaf2c9013bc1a7f4c774662259a506ba874d80f"
"Rev": "d509235108fcf6ab4913d2dcb3a2260c0db2108e"
},
{
"ImportPath": "github.com/godbus/dbus",

View File

@ -1 +0,0 @@
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.lisG21ATunZSCBP6vaqK_AZCIR18tN563RdqkAb6PGOipqTeg8R7VwZQIeDqS-2Vond6NX_KSC_D_uxxv0hBf2DiGXmwMUmP4nRXrsmbzT2qQKKIHYRDC_6jb2-FSfK14ezIe1Q07UiiJecDsN3CFEccS8E68Tdnp78p7yDwbTvpumnZmwYfyhlImtjFQv2YpyFVsjEHWK0R4e9T3ONQWcx6D2rSoxABbutrS03QwsJhHCeD9joL_gxfkFKm3CW8yWPSk2QYtx_Q1hu-tZR4IPb2tQPXPX3mtyhwBqziWgmJRDFCEjlCO5aCobiMm_9K5X05gue_DcgW163zh1P9jg.nleER2An8CUn_OuR.b77RFEFp0gC8j5yCAoARNKYmQIvWq99ibmf5ffJgdhQBF3sRYJLt_XflJ_2lsaiFOxvc45T2fnkMVy2lHFcri7F9f1BRiT_0AcDthxsecGzG8BZ9QvaM6b4Dn0rhjrOq8rsF0m3ZnbPBkkg3LV5EkbHWstMo2fgJPJhJswlGWhqJPJBDecG1nMBC8SMH32X-zVlSM-BLiaghvOGNxyb_RLZJZ3CLczIdQ2JO2UeYkOGCPGzernvkHDMpqQXc-8cmulDdHgCy87qFLy5ttGFgYbnTm92h_ChOGKZixeX0PL0pQY5wXd2xTO7Tg_Ov5E5FoVwIkwOextedVsF9iz_b_mwtCY3LXrvbJTW7zWrwBVsVyAXxT5iu0HyQ3tBVxT2GxS-yM5ApqLozcZCQg9flMyfSgThu82FfzEr0fI5vKw8zo0GdO4GBuVSppM9m6ToG6hlwyHD9g2YTZw9068hyq1_kZQhugJRjgGbpa2gyGqzx16fg0zVoupVIiq5KfvRlAQFeOVVjQwb0BWf25tJUj5tV3O9ge6dbKSXizEca33FJJwJWoXhd7DCREXUU9pBz06NCCf495BGoVbq3oLPDQc2mpcuy0XAPxSwXcc5Ts8DNs7MrxBlYdw81wMXuztIpOY4.XjKlMWl_H40XszToi2VU5g

View File

@ -1,40 +0,0 @@
clone:
path: github.com/go-openapi/validate
matrix:
GO_VERSION:
- "1.6"
build:
integration:
image: golang:$$GO_VERSION
pull: true
commands:
- go get -u github.com/axw/gocov/gocov
- go get -u gopkg.in/matm/v1/gocov-html
- go get -u github.com/cee-dub/go-junit-report
- go get -u github.com/stretchr/testify/assert
- go get -u gopkg.in/yaml.v2
- go get -u github.com/go-openapi/analysis
- go get -u github.com/go-openapi/errors
- go get -u github.com/go-openapi/loads
- go get -u github.com/go-openapi/strfmt
- go get -u github.com/go-openapi/runtime
- go test -race
- go test -v -cover -coverprofile=coverage.out -covermode=count
notify:
slack:
channel: bots
webhook_url: $$SLACK_URL
username: drone
publish:
coverage:
server: https://coverage.vmware.run
token: $$GITHUB_TOKEN
# threshold: 70
# must_increase: true
when:
matrix:
GO_VERSION: "1.6"

View File

@ -1,13 +0,0 @@
approve_by_comment: true
approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)'
reject_regex: ^[Rr]ejected
reset_on_push: false
reviewers:
members:
- casualjim
- chancez
- frapposelli
- vburenin
- pytlesk4
name: pullapprove
required: 1

22
vendor/github.com/go-openapi/validate/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,22 @@
language: go
go:
- 1.7
install:
- go get -u github.com/axw/gocov/gocov
- go get -u gopkg.in/matm/v1/gocov-html
- go get -u github.com/cee-dub/go-junit-report
- go get -u github.com/stretchr/testify/assert
- go get -u github.com/kr/pretty
- go get -u gopkg.in/yaml.v2
- go get -u github.com/go-openapi/analysis
- go get -u github.com/go-openapi/errors
- go get -u github.com/go-openapi/loads
- go get -u github.com/go-openapi/strfmt
- go get -u github.com/go-openapi/runtime
script:
- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
slack:
secure: EmObnQuM9Mw8J9vpFaKKHqSMN4Wsr/A9+v7ewAD5cEhA0T1P4m7MbJMiJOhxUhj/X+BFh2DamW+P2lT8mybj5wg8wnkQ2BteKA8Tawi6f9PRw2NRheO8tAi8o/npLnlmet0kc93mn+oLuqHw36w4+j5mkOl2FghkfGiUVhwrhkCP7KXQN+3TU87e+/HzQumlJ3nsE+6terVxkH3PmaUTsS5ONaODZfuxFpfb7RsoEl3skHf6d+tr+1nViLxxly7558Nc33C+W1mr0qiEvMLZ+kJ/CpGWBJ6CUJM3jm6hNe2eMuIPwEK2hxZob8c7n22VPap4K6a0bBRoydoDXaba+2sD7Ym6ivDO/DVyL44VeBBLyIiIBylDGQdZH+6SoWm90Qe/i7tnY/T5Ao5igT8f3cfQY1c3EsTfqmlDfrhmACBmwSlgkdVBLTprHL63JMY24LWmh4jhxsmMRZhCL4dze8su1w6pLN/pD1pGHtKYCEVbdTmaM3PblNRFf12XB7qosmQsgUndH4Vq3bTbU0s1pKjeDhRyLvFzvR0TBbo0pDLEoF1A/i5GVFWa7yLZNUDudQERRh7qv/xBl2excIaQ1sV4DSVm7bAE9l6Kp+yeHQJW2uN6Y3X8wu9gB9nv9l5HBze7wh8KE6PyWAOLYYqZg9/sAtsv/2GcQqXcKFF1zcA=

View File

@ -1,3 +1,3 @@
# Validation helpers [![Build Status](https://ci.vmware.run/api/badges/go-openapi/validate/status.svg)](https://ci.vmware.run/go-openapi/validate) [![Coverage](https://coverage.vmware.run/badges/go-openapi/validate/coverage.svg)](https://coverage.vmware.run/go-openapi/validate) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# Validation helpers [![Build Status](https://travis-ci.org/go-openapi/validate.svg?branch=master)](https://travis-ci.org/go-openapi/validate) [![codecov](https://codecov.io/gh/go-openapi/validate/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/validate) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/validate/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/validate?status.svg)](http://godoc.org/github.com/go-openapi/validate)

View File

@ -15,6 +15,7 @@
package validate
import (
"log"
"reflect"
"github.com/go-openapi/spec"
@ -51,7 +52,9 @@ func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool {
return false
}
r := doit()
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", f.Path, r, source, kind)
if Debug {
log.Printf("format validator for %q applies %t for %T (kind: %v)\n", f.Path, r, source, kind)
}
return r
}

View File

@ -15,8 +15,10 @@
package validate
import (
"log"
"reflect"
"regexp"
"strings"
"github.com/go-openapi/errors"
"github.com/go-openapi/spec"
@ -45,10 +47,45 @@ func (o *objectValidator) Applies(source interface{}, kind reflect.Kind) bool {
// there is a problem in the type validator where it will be unhappy about null values
// so that requires more testing
r := reflect.TypeOf(source) == specSchemaType && (kind == reflect.Map || kind == reflect.Struct)
//fmt.Printf("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind)
if Debug {
log.Printf("object validator for %q applies %t for %T (kind: %v)\n", o.Path, r, source, kind)
}
return r
}
func (o *objectValidator) isPropertyName() bool {
p := strings.Split(o.Path, ".")
return p[len(p)-1] == "properties" && p[len(p)-2] != "properties"
}
func (o *objectValidator) checkArrayMustHaveItems(res *Result, val map[string]interface{}) {
if t, typeFound := val["type"]; typeFound {
if tpe, ok := t.(string); ok && tpe == "array" {
if _, itemsKeyFound := val["items"]; !itemsKeyFound {
res.AddErrors(errors.Required("items", o.Path))
}
}
}
}
func (o *objectValidator) checkItemsMustBeTypeArray(res *Result, val map[string]interface{}) {
if !o.isPropertyName() {
if _, itemsKeyFound := val["items"]; itemsKeyFound {
t, typeFound := val["type"]
if typeFound {
if tpe, ok := t.(string); !ok || tpe != "array" {
res.AddErrors(errors.InvalidType(o.Path, o.In, "array", nil))
}
} else {
// there is no type
res.AddErrors(errors.Required("type", o.Path))
}
}
}
}
func (o *objectValidator) precheck(res *Result, val map[string]interface{}) {
o.checkArrayMustHaveItems(res, val)
o.checkItemsMustBeTypeArray(res, val)
}
func (o *objectValidator) Validate(data interface{}) *Result {
val := data.(map[string]interface{})
numKeys := int64(len(val))
@ -61,14 +98,8 @@ func (o *objectValidator) Validate(data interface{}) *Result {
}
res := new(Result)
if len(o.Required) > 0 {
for _, k := range o.Required {
if _, ok := val[k]; !ok {
res.AddErrors(errors.Required(o.Path+"."+k, o.In))
continue
}
}
}
o.precheck(res, val)
if o.AdditionalProperties != nil && !o.AdditionalProperties.Allows {
for k := range val {
@ -99,6 +130,8 @@ func (o *objectValidator) Validate(data interface{}) *Result {
}
}
createdFromDefaults := map[string]bool{}
for pName, pSchema := range o.Properties {
rName := pName
if o.Path != "" {
@ -106,7 +139,24 @@ func (o *objectValidator) Validate(data interface{}) *Result {
}
if v, ok := val[pName]; ok {
res.Merge(NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats).Validate(v))
r := NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats).Validate(v)
res.Merge(r)
} else if pSchema.Default != nil {
createdFromDefaults[pName] = true
pName := pName // shaddow
def := pSchema.Default
res.Defaulters = append(res.Defaulters, DefaulterFunc(func() {
val[pName] = def
}))
}
}
if len(o.Required) > 0 {
for _, k := range o.Required {
if _, ok := val[k]; !ok && !createdFromDefaults[k] {
res.AddErrors(errors.Required(o.Path+"."+k, o.In))
continue
}
}
}
@ -137,9 +187,6 @@ func (o *objectValidator) validatePatternProperty(key string, value interface{},
res := validator.Validate(value)
result.Merge(res)
if res.IsValid() {
succeededOnce = true
}
}
}

View File

@ -14,12 +14,32 @@
package validate
import "github.com/go-openapi/errors"
import (
"os"
"github.com/go-openapi/errors"
)
var (
// Debug is true when the SWAGGER_DEBUG env var is not empty
Debug = os.Getenv("SWAGGER_DEBUG") != ""
)
type Defaulter interface {
Apply()
}
type DefaulterFunc func()
func (f DefaulterFunc) Apply() {
f()
}
// Result represents a validation result
type Result struct {
Errors []error
MatchCount int
Defaulters []Defaulter
}
// Merge merges this result with the other one, preserving match counts etc
@ -29,11 +49,13 @@ func (r *Result) Merge(other *Result) *Result {
}
r.AddErrors(other.Errors...)
r.MatchCount += other.MatchCount
r.Defaulters = append(r.Defaulters, other.Defaulters...)
return r
}
// AddErrors adds errors to this validation result
func (r *Result) AddErrors(errors ...error) {
// TODO: filter already existing errors
r.Errors = append(r.Errors, errors...)
}
@ -59,3 +81,9 @@ func (r *Result) AsError() error {
}
return errors.CompositeValidationError(r.Errors...)
}
func (r *Result) ApplyDefaults() {
for _, d := range r.Defaulters {
d.Apply()
}
}

View File

@ -15,6 +15,8 @@
package validate
import (
"encoding/json"
"log"
"reflect"
"github.com/go-openapi/spec"
@ -80,12 +82,16 @@ func (s *SchemaValidator) Applies(source interface{}, kind reflect.Kind) bool {
// Validate validates the data against the schema
func (s *SchemaValidator) Validate(data interface{}) *Result {
result := new(Result)
if s == nil {
return result
}
if data == nil {
v := s.validators[0].Validate(data)
v.Merge(s.validators[6].Validate(data))
return v
}
result := new(Result)
tpe := reflect.TypeOf(data)
kind := tpe.Kind()
@ -98,8 +104,35 @@ func (s *SchemaValidator) Validate(data interface{}) *Result {
d = swag.ToDynamicJSON(data)
}
isnumber := s.Schema.Type.Contains("number") || s.Schema.Type.Contains("integer")
if num, ok := data.(json.Number); ok && isnumber {
if s.Schema.Type.Contains("integer") { // avoid lossy conversion
in, erri := num.Int64()
if erri != nil {
result.AddErrors(erri)
result.Inc()
return result
}
d = in
} else {
nf, errf := num.Float64()
if errf != nil {
result.AddErrors(errf)
result.Inc()
return result
}
d = nf
}
tpe = reflect.TypeOf(d)
kind = tpe.Kind()
}
for _, v := range s.validators {
if !v.Applies(s.Schema, kind) {
if Debug {
log.Printf("%T does not apply for %v", v, kind)
}
continue
}
@ -117,10 +150,9 @@ func (s *SchemaValidator) typeValidator() valueValidator {
func (s *SchemaValidator) commonValidator() valueValidator {
return &basicCommonValidator{
Path: s.Path,
In: s.in,
Default: s.Schema.Default,
Enum: s.Schema.Enum,
Path: s.Path,
In: s.in,
Enum: s.Schema.Enum,
}
}
@ -155,7 +187,6 @@ func (s *SchemaValidator) stringValidator() valueValidator {
return &stringValidator{
Path: s.Path,
In: s.in,
Default: s.Schema.Default,
MaxLength: s.Schema.MaxLength,
MinLength: s.Schema.MinLength,
Pattern: s.Schema.Pattern,
@ -164,9 +195,8 @@ func (s *SchemaValidator) stringValidator() valueValidator {
func (s *SchemaValidator) formatValidator() valueValidator {
return &formatValidator{
Path: s.Path,
In: s.in,
//Default: s.Schema.Default,
Path: s.Path,
In: s.in,
Format: s.Schema.Format,
KnownFormats: s.KnownFormats,
}

View File

@ -15,6 +15,7 @@
package validate
import (
"log"
"reflect"
"github.com/go-openapi/errors"
@ -80,12 +81,15 @@ func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.
func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool {
r := reflect.TypeOf(source) == specSchemaType
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
if Debug {
log.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
}
return r
}
func (s *schemaPropsValidator) Validate(data interface{}) *Result {
mainResult := new(Result)
var firstSuccess *Result
if len(s.anyOfValidators) > 0 {
var bestFailures *Result
succeededOnce := false
@ -94,6 +98,9 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result {
if result.IsValid() {
bestFailures = nil
succeededOnce = true
if firstSuccess == nil {
firstSuccess = result
}
break
}
if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
@ -106,11 +113,14 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result {
}
if bestFailures != nil {
mainResult.Merge(bestFailures)
} else if firstSuccess != nil {
mainResult.Merge(firstSuccess)
}
}
if len(s.oneOfValidators) > 0 {
var bestFailures *Result
var firstSuccess *Result
validated := 0
for _, oneOfSchema := range s.oneOfValidators {
@ -118,6 +128,9 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result {
if result.IsValid() {
validated++
bestFailures = nil
if firstSuccess == nil {
firstSuccess = result
}
continue
}
if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
@ -130,6 +143,8 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result {
if bestFailures != nil {
mainResult.Merge(bestFailures)
}
} else if firstSuccess != nil {
mainResult.Merge(firstSuccess)
}
}

View File

@ -67,6 +67,9 @@ func (s *schemaSliceValidator) Validate(data interface{}) *Result {
itemsSize = int64(len(s.Items.Schemas))
for i := int64(0); i < itemsSize; i++ {
validator := NewSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats)
if val.Len() <= int(i) {
break
}
result.Merge(validator.Validate(val.Index(int(i)).Interface()))
}

View File

@ -19,6 +19,7 @@ import (
"fmt"
"log"
"regexp"
"strconv"
"strings"
"github.com/go-openapi/analysis"
@ -193,6 +194,13 @@ func (s *SpecValidator) validateDuplicatePropertyNames() *Result {
return res
}
func (s *SpecValidator) resolveRef(ref *spec.Ref) (*spec.Schema, error) {
if s.spec.SpecFilePath() != "" {
return spec.ResolveRefWithBase(s.spec.Spec(), ref, &spec.ExpandOptions{RelativeBase: s.spec.SpecFilePath()})
}
return spec.ResolveRef(s.spec.Spec(), ref)
}
func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema, knowns map[string]struct{}) []dupProp {
var dups []dupProp
@ -200,7 +208,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema,
schc := &sch
for schc.Ref.String() != "" {
// gather property names
reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref)
reso, err := s.resolveRef(&schc.Ref)
if err != nil {
panic(err)
}
@ -236,7 +244,7 @@ func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, kno
schn := nm
schc := &sch
for schc.Ref.String() != "" {
reso, err := spec.ResolveRef(s.spec.Spec(), &schc.Ref)
reso, err := s.resolveRef(&schc.Ref)
if err != nil {
panic(err)
}
@ -335,15 +343,15 @@ func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID str
return errors.New(422, "%s for %q is a collection without an element type", prefix, opID)
}
schemas := schema.Items.Schemas
if schema.Items.Schema != nil {
schemas = []spec.Schema{*schema.Items.Schema}
}
for _, sch := range schemas {
if err := s.validateSchemaItems(sch, prefix, opID); err != nil {
return err
schema = *schema.Items.Schema
if _, err := regexp.Compile(schema.Pattern); err != nil {
return errors.New(422, "%s for %q has invalid items pattern: %q", prefix, opID, schema.Pattern)
}
return s.validateSchemaItems(schema, prefix, opID)
}
return nil
}
@ -524,8 +532,15 @@ func (s *SpecValidator) validateParameters() *Result {
}
var fromPath []string
for _, i := range params {
fromPath = append(fromPath, knowns[i])
knowns[i] = "!"
knownsi := knowns[i]
iparams := extractPathParams(knownsi)
if len(iparams) > 0 {
fromPath = append(fromPath, iparams...)
for _, iparam := range iparams {
knownsi = strings.Replace(knownsi, iparam, "!", 1)
}
knowns[i] = knownsi
}
}
knownPath := strings.Join(knowns, "/")
if orig, ok := knownPaths[knownPath]; ok {
@ -544,7 +559,9 @@ func (s *SpecValidator) validateParameters() *Result {
for pr.Ref.String() != "" {
obj, _, err := pr.Ref.GetPointer().Get(sw)
if err != nil {
log.Println(err)
if Debug {
log.Println(err)
}
res.AddErrors(err)
break PARAMETERS
}
@ -575,6 +592,10 @@ func (s *SpecValidator) validateParameters() *Result {
pr = obj.(spec.Parameter)
}
if _, err := regexp.Compile(pr.Pattern); err != nil {
res.AddErrors(errors.New(422, "operation %q has invalid pattern in param %q: %q", op.ID, pr.Name, pr.Pattern))
}
if pr.In == "body" {
if firstBodyParam != "" {
res.AddErrors(errors.New(422, "operation %q has more than 1 body param (accepted: %q, dropped: %q)", op.ID, firstBodyParam, pr.Name))
@ -595,18 +616,35 @@ func (s *SpecValidator) validateParameters() *Result {
func parsePath(path string) (segments []string, params []int) {
for i, p := range strings.Split(path, "/") {
segments = append(segments, p)
if len(p) > 0 && p[0] == '{' && p[len(p)-1] == '}' {
if d0 := strings.Index(p, "{"); d0 >= 0 && d0 < strings.Index(p, "}") {
params = append(params, i)
}
}
return
}
func extractPathParams(segment string) (params []string) {
for {
d0 := strings.IndexByte(segment, '{')
if d0 < 0 {
break
}
d1 := strings.IndexByte(segment[d0:], '}')
if d1 > 0 {
params = append(params, segment[d0:d0+d1+1])
} else {
break
}
segment = segment[d1:]
}
return params
}
func (s *SpecValidator) validateReferencesValid() *Result {
// each reference must point to a valid object
res := new(Result)
for _, r := range s.analyzer.AllRefs() {
if !r.IsValidURI() {
if !r.IsValidURI(s.spec.SpecFilePath()) {
res.AddErrors(errors.New(404, "invalid ref %q", r.String()))
}
}
@ -698,7 +736,9 @@ func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result {
}
// check simple paramters first
if param.Default != nil && param.Schema == nil {
//fmt.Println(param.Name, "in", param.In, "has a default without a schema")
if Debug {
log.Println(param.Name, "in", param.In, "has a default without a schema")
}
// check param valid
res.Merge(NewParamValidator(&param, s.KnownFormats).Validate(param.Default))
}
@ -721,9 +761,15 @@ func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result {
if h.Items != nil {
res.Merge(s.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items))
}
if _, err := regexp.Compile(h.Pattern); err != nil {
res.AddErrors(errors.New(422, "operation %q has invalid pattern in default header %q: %q", op.ID, nm, h.Pattern))
}
}
if dr.Schema != nil {
res.Merge(s.validateDefaultValueSchemaAgainstSchema("default", "response", dr.Schema))
}
}
for _, r := range op.Responses.StatusCodeResponses {
for code, r := range op.Responses.StatusCodeResponses {
for nm, h := range r.Headers {
if h.Default != nil {
res.Merge(NewHeaderValidator(nm, &h, s.KnownFormats).Validate(h.Default))
@ -731,6 +777,12 @@ func (s *SpecValidator) validateDefaultValueValidAgainstSchema() *Result {
if h.Items != nil {
res.Merge(s.validateDefaultValueItemsAgainstSchema(nm, "header", &h, h.Items))
}
if _, err := regexp.Compile(h.Pattern); err != nil {
res.AddErrors(errors.New(422, "operation %q has invalid pattern in %v's header %q: %q", op.ID, code, nm, h.Pattern))
}
}
if r.Schema != nil {
res.Merge(s.validateDefaultValueSchemaAgainstSchema(strconv.Itoa(code), "response", r.Schema))
}
}
@ -758,6 +810,9 @@ func (s *SpecValidator) validateDefaultValueSchemaAgainstSchema(path, in string,
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.items[%d]", path, i), in, &sch))
}
}
if _, err := regexp.Compile(schema.Pattern); err != nil {
res.AddErrors(errors.New(422, "%s in %s has invalid pattern: %q", path, in, schema.Pattern))
}
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
res.Merge(s.validateDefaultValueSchemaAgainstSchema(fmt.Sprintf("%s.additionalItems", path), in, schema.AdditionalItems.Schema))
}
@ -787,6 +842,9 @@ func (s *SpecValidator) validateDefaultValueItemsAgainstSchema(path, in string,
if items.Items != nil {
res.Merge(s.validateDefaultValueItemsAgainstSchema(path+"[0]", in, root, items.Items))
}
if _, err := regexp.Compile(items.Pattern); err != nil {
res.AddErrors(errors.New(422, "%s in %s has invalid pattern: %q", path, in, items.Pattern))
}
}
return res
}

View File

@ -15,6 +15,7 @@
package validate
import (
"log"
"reflect"
"strings"
@ -32,16 +33,6 @@ type typeValidator struct {
Path string
}
var jsonTypeNames = map[string]struct{}{
"array": struct{}{},
"boolean": struct{}{},
"integer": struct{}{},
"null": struct{}{},
"number": struct{}{},
"object": struct{}{},
"string": struct{}{},
}
func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) {
switch data.(type) {
case []byte:
@ -121,7 +112,9 @@ func (t *typeValidator) SetPath(path string) {
func (t *typeValidator) Applies(source interface{}, kind reflect.Kind) bool {
stpe := reflect.TypeOf(source)
r := (len(t.Type) > 0 || t.Format != "") && (stpe == specSchemaType || stpe == specParameterType || stpe == specHeaderType)
//fmt.Printf("type validator for %q applies %t for %T (kind: %v)\n", t.Path, r, source, kind)
if Debug {
log.Printf("type validator for %q applies %t for %T (kind: %v)\n", t.Path, r, source, kind)
}
return r
}
@ -140,7 +133,9 @@ func (t *typeValidator) Validate(data interface{}) *Result {
kind := val.Kind()
schType, format := t.schemaInfoForType(data)
//fmt.Println("path:", t.Path, "schType:", schType, "format:", format, "expType:", t.Type, "expFmt:", t.Format, "kind:", val.Kind().String())
if Debug {
log.Println("path:", t.Path, "schType:", schType, "format:", format, "expType:", t.Type, "expFmt:", t.Format, "kind:", val.Kind().String())
}
isLowerInt := t.Format == "int64" && format == "int32"
isLowerFloat := t.Format == "float64" && format == "float32"
isFloatInt := schType == "number" && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains("integer")

15
vendor/github.com/go-openapi/validate/update-fixtures.sh generated vendored Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
set -eu -o pipefail
dir=$(git rev-parse --show-toplevel)
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
function finish {
rm -rf "$scratch"
}
trap finish EXIT SIGHUP SIGINT SIGTERM
cd "$scratch"
git clone https://github.com/json-schema-org/JSON-Schema-Test-Suite Suite
cp -r Suite/tests/draft4/* "$dir/fixtures/jsonschema_suite"
cp -a Suite/remotes "$dir/fixtures/jsonschema_suite"

View File

@ -16,6 +16,7 @@ package validate
import (
"fmt"
"log"
"reflect"
"github.com/go-openapi/errors"
@ -156,8 +157,15 @@ func (b *basicCommonValidator) Applies(source interface{}, kind reflect.Kind) bo
func (b *basicCommonValidator) Validate(data interface{}) (res *Result) {
if len(b.Enum) > 0 {
for _, enumValue := range b.Enum {
if data != nil && reflect.DeepEqual(enumValue, data) {
return nil
actualType := reflect.TypeOf(enumValue)
if actualType == nil {
continue
}
expectedValue := reflect.ValueOf(data)
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) {
return nil
}
}
}
return sErr(errors.EnumFail(b.Path, b.In, data, b.Enum))
@ -474,10 +482,14 @@ func (n *numberValidator) Applies(source interface{}, kind reflect.Kind) bool {
isInt := kind >= reflect.Int && kind <= reflect.Uint64
isFloat := kind == reflect.Float32 || kind == reflect.Float64
r := isInt || isFloat
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, r, source, kind)
if Debug {
log.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, r, source, kind)
}
return r
}
// fmt.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind)
if Debug {
log.Printf("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind)
}
return false
}
@ -536,15 +548,22 @@ func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool {
switch source.(type) {
case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header:
r := kind == reflect.String
// fmt.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
if Debug {
log.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
}
return r
}
// fmt.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind)
if Debug {
log.Printf("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind)
}
return false
}
func (s *stringValidator) Validate(val interface{}) *Result {
data := val.(string)
data, ok := val.(string)
if !ok {
return sErr(errors.InvalidType(s.Path, s.In, "string", val))
}
if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") {
if err := RequiredString(s.Path, s.In, data); err != nil {

View File

@ -196,7 +196,11 @@ func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Vali
// MultipleOf validates if the provided number is a multiple of the factor
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
if !swag.IsFloat64AJSONInteger(data / factor) {
mult := data / factor
if factor < 1 {
mult = 1 / factor * data
}
if !swag.IsFloat64AJSONInteger(mult) {
return errors.NotMultipleOf(path, in, factor)
}
return nil