Skip to content

Commit 9f99fee

Browse files
authored
Refine schema error reason message (#748)
1 parent abdca6c commit 9f99fee

8 files changed

Lines changed: 355 additions & 47 deletions

File tree

openapi3/issue136_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ components:
3131
},
3232
{
3333
dflt: `1`,
34-
err: "invalid components: invalid schema default: field must be set to string or not be present",
34+
err: "invalid components: invalid schema default: value must be a string",
3535
},
3636
} {
3737
t.Run(testcase.dflt, func(t *testing.T) {

openapi3/issue735_test.go

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
package openapi3
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
type testCase struct {
11+
name string
12+
schema *Schema
13+
value interface{}
14+
extraNotContains []interface{}
15+
options []SchemaValidationOption
16+
}
17+
18+
func TestIssue735(t *testing.T) {
19+
DefineStringFormat("uuid", FormatOfStringForUUIDOfRFC4122)
20+
DefineStringFormat("email", FormatOfStringForEmail)
21+
DefineIPv4Format()
22+
DefineIPv6Format()
23+
24+
testCases := []testCase{
25+
{
26+
name: "type string",
27+
schema: NewStringSchema(),
28+
value: 42,
29+
},
30+
{
31+
name: "type boolean",
32+
schema: NewBoolSchema(),
33+
value: 42,
34+
},
35+
{
36+
name: "type integer",
37+
schema: NewIntegerSchema(),
38+
value: "foo",
39+
},
40+
{
41+
name: "type number",
42+
schema: NewFloat64Schema(),
43+
value: "foo",
44+
},
45+
{
46+
name: "type array",
47+
schema: NewArraySchema(),
48+
value: 42,
49+
},
50+
{
51+
name: "type object",
52+
schema: NewObjectSchema(),
53+
value: 42,
54+
},
55+
{
56+
name: "min",
57+
schema: NewSchema().WithMin(100),
58+
value: 42,
59+
},
60+
{
61+
name: "max",
62+
schema: NewSchema().WithMax(0),
63+
value: 42,
64+
},
65+
{
66+
name: "exclusive min",
67+
schema: NewSchema().WithMin(100).WithExclusiveMin(true),
68+
value: 42,
69+
},
70+
{
71+
name: "exclusive max",
72+
schema: NewSchema().WithMax(0).WithExclusiveMax(true),
73+
value: 42,
74+
},
75+
{
76+
name: "multiple of",
77+
schema: &Schema{MultipleOf: Float64Ptr(5.0)},
78+
value: 42,
79+
},
80+
{
81+
name: "enum",
82+
schema: NewSchema().WithEnum(3, 5),
83+
value: 42,
84+
},
85+
{
86+
name: "min length",
87+
schema: NewSchema().WithMinLength(100),
88+
value: "foo",
89+
},
90+
{
91+
name: "max length",
92+
schema: NewSchema().WithMaxLength(0),
93+
value: "foo",
94+
},
95+
{
96+
name: "pattern",
97+
schema: NewSchema().WithPattern("[0-9]"),
98+
value: "foo",
99+
},
100+
{
101+
name: "items",
102+
schema: NewSchema().WithItems(NewStringSchema()),
103+
value: []interface{}{42},
104+
extraNotContains: []interface{}{42},
105+
},
106+
{
107+
name: "min items",
108+
schema: NewSchema().WithMinItems(100),
109+
value: []interface{}{42},
110+
extraNotContains: []interface{}{42},
111+
},
112+
{
113+
name: "max items",
114+
schema: NewSchema().WithMaxItems(0),
115+
value: []interface{}{42},
116+
extraNotContains: []interface{}{42},
117+
},
118+
{
119+
name: "unique items",
120+
schema: NewSchema().WithUniqueItems(true),
121+
value: []interface{}{42, 42},
122+
extraNotContains: []interface{}{42},
123+
},
124+
{
125+
name: "min properties",
126+
schema: NewSchema().WithMinProperties(100),
127+
value: map[string]interface{}{"foo": 42},
128+
extraNotContains: []interface{}{42},
129+
},
130+
{
131+
name: "max properties",
132+
schema: NewSchema().WithMaxProperties(0),
133+
value: map[string]interface{}{"foo": 42},
134+
extraNotContains: []interface{}{42},
135+
},
136+
{
137+
name: "additional properties other schema type",
138+
schema: NewSchema().WithAdditionalProperties(NewStringSchema()),
139+
value: map[string]interface{}{"foo": 42},
140+
extraNotContains: []interface{}{42},
141+
},
142+
{
143+
name: "additional properties false",
144+
schema: &Schema{AdditionalProperties: AdditionalProperties{
145+
Has: BoolPtr(false),
146+
}},
147+
value: map[string]interface{}{"foo": 42},
148+
extraNotContains: []interface{}{42},
149+
},
150+
{
151+
name: "invalid properties schema",
152+
schema: NewSchema().WithProperties(map[string]*Schema{
153+
"foo": NewStringSchema(),
154+
}),
155+
value: map[string]interface{}{"foo": 42},
156+
extraNotContains: []interface{}{42},
157+
},
158+
// TODO: uncomment when https://github.com/getkin/kin-openapi/issues/502 is fixed
159+
//{
160+
// name: "read only properties",
161+
// schema: NewSchema().WithProperties(map[string]*Schema{
162+
// "foo": {ReadOnly: true},
163+
// }).WithoutAdditionalProperties(),
164+
// value: map[string]interface{}{"foo": 42},
165+
// extraNotContains: []interface{}{42},
166+
// options: []SchemaValidationOption{VisitAsRequest()},
167+
//},
168+
//{
169+
// name: "write only properties",
170+
// schema: NewSchema().WithProperties(map[string]*Schema{
171+
// "foo": {WriteOnly: true},
172+
// }).WithoutAdditionalProperties(),
173+
// value: map[string]interface{}{"foo": 42},
174+
// extraNotContains: []interface{}{42},
175+
// options: []SchemaValidationOption{VisitAsResponse()},
176+
//},
177+
{
178+
name: "required properties",
179+
schema: &Schema{
180+
Properties: Schemas{
181+
"bar": NewStringSchema().NewRef(),
182+
},
183+
Required: []string{"bar"},
184+
},
185+
value: map[string]interface{}{"foo": 42},
186+
extraNotContains: []interface{}{42},
187+
},
188+
{
189+
name: "one of (matches more then one)",
190+
schema: NewOneOfSchema(
191+
&Schema{MultipleOf: Float64Ptr(6)},
192+
&Schema{MultipleOf: Float64Ptr(7)},
193+
),
194+
value: 42,
195+
},
196+
{
197+
name: "one of (no matches)",
198+
schema: NewOneOfSchema(
199+
&Schema{MultipleOf: Float64Ptr(5)},
200+
&Schema{MultipleOf: Float64Ptr(10)},
201+
),
202+
value: 42,
203+
},
204+
{
205+
name: "any of",
206+
schema: NewAnyOfSchema(
207+
&Schema{MultipleOf: Float64Ptr(5)},
208+
&Schema{MultipleOf: Float64Ptr(10)},
209+
),
210+
value: 42,
211+
},
212+
{
213+
name: "all of (match some)",
214+
schema: NewAllOfSchema(
215+
&Schema{MultipleOf: Float64Ptr(6)},
216+
&Schema{MultipleOf: Float64Ptr(5)},
217+
),
218+
value: 42,
219+
},
220+
{
221+
name: "all of (no match)",
222+
schema: NewAllOfSchema(
223+
&Schema{MultipleOf: Float64Ptr(10)},
224+
&Schema{MultipleOf: Float64Ptr(5)},
225+
),
226+
value: 42,
227+
},
228+
{
229+
name: "uuid format",
230+
schema: NewUUIDSchema(),
231+
value: "foo",
232+
},
233+
{
234+
name: "date time format",
235+
schema: NewDateTimeSchema(),
236+
value: "foo",
237+
},
238+
{
239+
name: "date format",
240+
schema: NewSchema().WithFormat("date"),
241+
value: "foo",
242+
},
243+
{
244+
name: "ipv4 format",
245+
schema: NewSchema().WithFormat("ipv4"),
246+
value: "foo",
247+
},
248+
{
249+
name: "ipv6 format",
250+
schema: NewSchema().WithFormat("ipv6"),
251+
value: "foo",
252+
},
253+
{
254+
name: "email format",
255+
schema: NewSchema().WithFormat("email"),
256+
value: "foo",
257+
},
258+
{
259+
name: "byte format",
260+
schema: NewBytesSchema(),
261+
value: "foo!",
262+
},
263+
}
264+
265+
for _, tc := range testCases {
266+
t.Run(tc.name, func(t *testing.T) {
267+
err := tc.schema.VisitJSON(tc.value, tc.options...)
268+
var schemaError = &SchemaError{}
269+
require.Error(t, err)
270+
require.ErrorAs(t, err, &schemaError)
271+
require.NotZero(t, schemaError.Reason)
272+
require.NotContains(t, schemaError.Reason, fmt.Sprint(tc.value))
273+
for _, extra := range tc.extraNotContains {
274+
require.NotContains(t, schemaError.Reason, fmt.Sprint(extra))
275+
}
276+
})
277+
}
278+
}

0 commit comments

Comments
 (0)