Skip to content

Commit d5c7ac5

Browse files
authored
Fix lost error types in oneOf (#658)
1 parent 9ea22ae commit d5c7ac5

File tree

3 files changed

+98
-12
lines changed

3 files changed

+98
-12
lines changed

openapi3/errors.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ import (
1010
type MultiError []error
1111

1212
func (me MultiError) Error() string {
13+
return spliceErr(" | ", me)
14+
}
15+
16+
func spliceErr(sep string, errs []error) string {
1317
buff := &bytes.Buffer{}
14-
for i, e := range me {
18+
for i, e := range errs {
1519
buff.WriteString(e.Error())
16-
if i != len(me)-1 {
17-
buff.WriteString(" | ")
20+
if i != len(errs)-1 {
21+
buff.WriteString(sep)
1822
}
1923
}
2024
return buff.String()
@@ -43,3 +47,13 @@ func (me MultiError) As(target interface{}) bool {
4347
}
4448
return false
4549
}
50+
51+
type multiErrorForOneOf MultiError
52+
53+
func (meo multiErrorForOneOf) Error() string {
54+
return spliceErr(" Or ", meo)
55+
}
56+
57+
func (meo multiErrorForOneOf) Unwrap() error {
58+
return MultiError(meo)
59+
}

openapi3/issue657_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package openapi3_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/getkin/kin-openapi/openapi3"
9+
)
10+
11+
func TestOneOf_Warning_Errors(t *testing.T) {
12+
t.Parallel()
13+
14+
loader := openapi3.NewLoader()
15+
spec := `
16+
components:
17+
schemas:
18+
Something:
19+
type: object
20+
properties:
21+
field:
22+
title: Some field
23+
oneOf:
24+
- title: First rule
25+
type: string
26+
minLength: 10
27+
maxLength: 10
28+
- title: Second rule
29+
type: string
30+
minLength: 15
31+
maxLength: 15
32+
`[1:]
33+
34+
doc, err := loader.LoadFromData([]byte(spec))
35+
require.NoError(t, err)
36+
37+
tests := [...]struct {
38+
name string
39+
value string
40+
checkErr require.ErrorAssertionFunc
41+
}{
42+
{
43+
name: "valid value",
44+
value: "ABCDE01234",
45+
checkErr: require.NoError,
46+
},
47+
{
48+
name: "valid value",
49+
value: "ABCDE0123456789",
50+
checkErr: require.NoError,
51+
},
52+
{
53+
name: "no valid value",
54+
value: "ABCDE",
55+
checkErr: func(t require.TestingT, err error, i ...interface{}) {
56+
require.Equal(t, "doesn't match schema due to: minimum string length is 10\nSchema:\n {\n \"maxLength\": 10,\n \"minLength\": 10,\n \"title\": \"First rule\",\n \"type\": \"string\"\n }\n\nValue:\n \"ABCDE\"\n Or minimum string length is 15\nSchema:\n {\n \"maxLength\": 15,\n \"minLength\": 15,\n \"title\": \"Second rule\",\n \"type\": \"string\"\n }\n\nValue:\n \"ABCDE\"\n", err.Error())
57+
58+
wErr := &openapi3.MultiError{}
59+
require.ErrorAs(t, err, wErr)
60+
61+
require.Len(t, *wErr, 2)
62+
63+
require.Equal(t, "minimum string length is 10", (*wErr)[0].(*openapi3.SchemaError).Reason)
64+
require.Equal(t, "minimum string length is 15", (*wErr)[1].(*openapi3.SchemaError).Reason)
65+
},
66+
},
67+
}
68+
69+
for _, test := range tests {
70+
test := test
71+
t.Run(test.name, func(t *testing.T) {
72+
t.Parallel()
73+
74+
err = doc.Components.Schemas["Something"].Value.Properties["field"].Value.VisitJSON(test.value)
75+
76+
test.checkErr(t, err)
77+
})
78+
}
79+
}

openapi3/schema.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
926926

927927
var (
928928
ok = 0
929-
validationErrors = []error{}
929+
validationErrors = multiErrorForOneOf{}
930930
matchedOneOfIdx = 0
931931
tempValue = value
932932
)
@@ -955,14 +955,7 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
955955

956956
if ok != 1 {
957957
if len(validationErrors) > 1 {
958-
errorMessage := ""
959-
for _, err := range validationErrors {
960-
if errorMessage != "" {
961-
errorMessage += " Or "
962-
}
963-
errorMessage += err.Error()
964-
}
965-
return errors.New("doesn't match schema due to: " + errorMessage)
958+
return fmt.Errorf("doesn't match schema due to: %w", validationErrors)
966959
}
967960
if settings.failfast {
968961
return errSchema

0 commit comments

Comments
 (0)