Skip to content

Commit

Permalink
openapi3: fix integer enum schema validation after json.Number PR (#755)
Browse files Browse the repository at this point in the history
  • Loading branch information
k2tzumi authored Jan 28, 2023
1 parent 84703aa commit 6e233af
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 2 deletions.
16 changes: 14 additions & 2 deletions openapi3/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -1143,8 +1143,20 @@ func (schema *Schema) visitJSON(settings *schemaValidationSettings, value interf
func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, value interface{}) (err error) {
if enum := schema.Enum; len(enum) != 0 {
for _, v := range enum {
if reflect.DeepEqual(v, value) {
return
switch c := value.(type) {
case json.Number:
var f float64
f, err = strconv.ParseFloat(c.String(), 64)
if err != nil {
return err
}
if v == f {
return
}
default:
if reflect.DeepEqual(v, value) {
return
}
}
}
if settings.failfast {
Expand Down
175 changes: 175 additions & 0 deletions openapi3filter/validation_enum_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package openapi3filter

import (
"bytes"
"net/http"
"testing"

"github.com/stretchr/testify/require"

"github.com/getkin/kin-openapi/openapi3"
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
)

func TestValidationWithIntegerEnum(t *testing.T) {
const spec = `
openapi: 3.0.0
info:
title: Example integer enum
version: '0.1'
paths:
/sample:
put:
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
exenum:
type: integer
enum:
- 0
- 1
- 2
- 3
example: 0
nullable: true
responses:
'200':
description: Ok
`

loader := openapi3.NewLoader()
doc, err := loader.LoadFromData([]byte(spec))
require.NoError(t, err)

router, err := legacyrouter.NewRouter(doc)
require.NoError(t, err)

tests := []struct {
data []byte
wantErr bool
}{
{
[]byte(`{"exenum": 1}`),
false,
},
{
[]byte(`{"exenum": "1"}`),
true,
},
{
[]byte(`{"exenum": null}`),
false,
},
{
[]byte(`{}`),
false,
},
}

for _, tt := range tests {
body := bytes.NewReader(tt.data)
req, err := http.NewRequest("PUT", "/sample", body)
require.NoError(t, err)
req.Header.Add(headerCT, "application/json")

route, pathParams, err := router.FindRoute(req)
require.NoError(t, err)

requestValidationInput := &RequestValidationInput{
Request: req,
PathParams: pathParams,
Route: route,
}
err = ValidateRequest(loader.Context, requestValidationInput)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
}
}

func TestValidationWithStringEnum(t *testing.T) {
const spec = `
openapi: 3.0.0
info:
title: Example string enum
version: '0.1'
paths:
/sample:
put:
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
exenum:
type: string
enum:
- "0"
- "1"
- "2"
- "3"
example: "0"
responses:
'200':
description: Ok
`

loader := openapi3.NewLoader()
doc, err := loader.LoadFromData([]byte(spec))
require.NoError(t, err)

router, err := legacyrouter.NewRouter(doc)
require.NoError(t, err)

tests := []struct {
data []byte
wantErr bool
}{
{
[]byte(`{"exenum": "1"}`),
false,
},
{
[]byte(`{"exenum": 1}`),
true,
},
{
[]byte(`{"exenum": null}`),
true,
},
{
[]byte(`{}`),
false,
},
}

for _, tt := range tests {
body := bytes.NewReader(tt.data)
req, err := http.NewRequest("PUT", "/sample", body)
require.NoError(t, err)
req.Header.Add(headerCT, "application/json")

route, pathParams, err := router.FindRoute(req)
require.NoError(t, err)

requestValidationInput := &RequestValidationInput{
Request: req,
PathParams: pathParams,
Route: route,
}
err = ValidateRequest(loader.Context, requestValidationInput)
if tt.wantErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
}
}

0 comments on commit 6e233af

Please sign in to comment.