Skip to content

Commit

Permalink
test getkin#482: add tests for both JSON and YAML decoders
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Boitel committed Aug 1, 2022
1 parent 9755796 commit 0e13ac8
Showing 1 changed file with 101 additions and 32 deletions.
133 changes: 101 additions & 32 deletions openapi3/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"math"
"reflect"
"strings"
"testing"

"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

type schemaExample struct {
Expand Down Expand Up @@ -45,23 +45,25 @@ func testSchema(t *testing.T, example schemaExample) func(*testing.T) {
require.NoError(t, err)
require.Equal(t, dataUnserialized, dataSchema)
}
for _, value := range example.AllValid {
err := validateSchema(t, schema, value)
require.NoError(t, err)
}
for _, value := range example.AllInvalid {
err := validateSchema(t, schema, value)
require.Error(t, err)
for validateFuncIndex, validateFunc := range validateSchemaFuncs {
for index, value := range example.AllValid {
err := validateFunc(t, schema, value)
require.NoErrorf(t, err, "ValidateFunc #%d, AllValid #%d: %#v", validateFuncIndex, index, value)
}
for index, value := range example.AllInvalid {
err := validateFunc(t, schema, value)
require.Errorf(t, err, "ValidateFunc #%d, AllInvalid #%d: %#v", validateFuncIndex, index, value)
}
}
// NaN and Inf aren't valid JSON but are handled
for _, value := range []interface{}{math.NaN(), math.Inf(-1), math.Inf(+1)} {
for index, value := range []interface{}{math.NaN(), math.Inf(-1), math.Inf(+1)} {
err := schema.VisitJSON(value)
require.Error(t, err)
require.Errorf(t, err, "NaNAndInf #%d: %#v", index, value)
}
}
}

func validateSchema(t *testing.T, schema *Schema, value interface{}, opts ...SchemaValidationOption) error {
func validateSchemaJSON(t *testing.T, schema *Schema, value interface{}, opts ...SchemaValidationOption) error {
data, err := json.Marshal(value)
require.NoError(t, err)
var val interface{}
Expand All @@ -70,6 +72,22 @@ func validateSchema(t *testing.T, schema *Schema, value interface{}, opts ...Sch
return schema.VisitJSON(val, opts...)
}

func validateSchemaYAML(t *testing.T, schema *Schema, value interface{}, opts ...SchemaValidationOption) error {
data, err := yaml.Marshal(value)
require.NoError(t, err)
var val interface{}
err = yaml.Unmarshal(data, &val)
require.NoError(t, err)
return schema.VisitJSON(val, opts...)
}

type validateSchemaFunc func(t *testing.T, schema *Schema, value interface{}, opts ...SchemaValidationOption) error

var validateSchemaFuncs = []validateSchemaFunc{
validateSchemaJSON,
validateSchemaYAML,
}

var schemaExamples = []schemaExample{
{
Title: "EMPTY SCHEMA",
Expand Down Expand Up @@ -234,7 +252,56 @@ var schemaExamples = []schemaExample{
map[string]interface{}{},
},
},

{
Title: "INTEGER OPTIONAL INT64 FORMAT",
Schema: NewInt64Schema(),
Serialization: map[string]interface{}{
"type": "integer",
"format": "int64",
},
AllValid: []interface{}{
1,
256,
65536,
int64(math.MaxInt32) + 10,
int64(math.MinInt32) - 10,
},
AllInvalid: []interface{}{
nil,
false,
3.5,
true,
"",
[]interface{}{},
map[string]interface{}{},
},
},
{
Title: "INTEGER OPTIONAL INT32 FORMAT",
Schema: NewInt32Schema(),
Serialization: map[string]interface{}{
"type": "integer",
"format": "int32",
},
AllValid: []interface{}{
1,
256,
65536,
int64(math.MaxInt32),
int64(math.MaxInt32),
},
AllInvalid: []interface{}{
nil,
false,
3.5,
int64(math.MaxInt32) + 10,
int64(math.MinInt32) - 10,
true,
"",
[]interface{}{},
map[string]interface{}{},
},
},
{
Title: "STRING",
Schema: NewStringSchema().
Expand Down Expand Up @@ -350,7 +417,7 @@ var schemaExamples = []schemaExample{
AllInvalid: []interface{}{
nil,
" ",
"\n",
"\n\n", // a \n is ok for JSON but not for YAML decoder/encoder
"%",
},
},
Expand Down Expand Up @@ -1074,28 +1141,30 @@ func TestSchemasMultiError(t *testing.T) {
func testSchemaMultiError(t *testing.T, example schemaMultiErrorExample) func(*testing.T) {
return func(t *testing.T) {
schema := example.Schema
for i, value := range example.Values {
err := validateSchema(t, schema, value, MultiErrors())
require.Error(t, err)
require.IsType(t, MultiError{}, err)
for validateFuncIndex, validateFunc := range validateSchemaFuncs {
for i, value := range example.Values {
err := validateFunc(t, schema, value, MultiErrors())
require.Errorf(t, err, "ValidateFunc #%d, value #%d: %#", validateFuncIndex, i, value)
require.IsType(t, MultiError{}, err)

merr, _ := err.(MultiError)
expected := example.ExpectedErrors[i]
require.True(t, len(merr) > 0)
require.Len(t, merr, len(expected))
for _, e := range merr {
require.IsType(t, &SchemaError{}, e)
var found bool
scherr, _ := e.(*SchemaError)
for _, expectedErr := range expected {
expectedScherr, _ := expectedErr.(*SchemaError)
if reflect.DeepEqual(expectedScherr.reversePath, scherr.reversePath) &&
expectedScherr.SchemaField == scherr.SchemaField {
found = true
break
merr, _ := err.(MultiError)
expected := example.ExpectedErrors[i]
require.True(t, len(merr) > 0)
require.Len(t, merr, len(expected))
for _, e := range merr {
require.IsType(t, &SchemaError{}, e)
var found bool
scherr, _ := e.(*SchemaError)
for _, expectedErr := range expected {
expectedScherr, _ := expectedErr.(*SchemaError)
if reflect.DeepEqual(expectedScherr.reversePath, scherr.reversePath) &&
expectedScherr.SchemaField == scherr.SchemaField {
found = true
break
}
}
require.Truef(t, found, "ValidateFunc #%d, value #%d: missing %s error on %s", validateFunc, i, scherr.SchemaField, strings.Join(scherr.JSONPointer(), "."))
}
require.True(t, found, fmt.Sprintf("missing %s error on %s", scherr.SchemaField, strings.Join(scherr.JSONPointer(), ".")))
}
}
}
Expand Down

0 comments on commit 0e13ac8

Please sign in to comment.