1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17 import (
18 "fmt"
19 "reflect"
20
21 "github.com/go-openapi/spec"
22 "github.com/go-openapi/strfmt"
23 )
24
25 type schemaPropsValidator struct {
26 Path string
27 In string
28 AllOf []spec.Schema
29 OneOf []spec.Schema
30 AnyOf []spec.Schema
31 Not *spec.Schema
32 Dependencies spec.Dependencies
33 anyOfValidators []*SchemaValidator
34 allOfValidators []*SchemaValidator
35 oneOfValidators []*SchemaValidator
36 notValidator *SchemaValidator
37 Root interface{}
38 KnownFormats strfmt.Registry
39 Options *SchemaValidatorOptions
40 }
41
42 func (s *schemaPropsValidator) SetPath(path string) {
43 s.Path = path
44 }
45
46 func newSchemaPropsValidator(
47 path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry,
48 opts *SchemaValidatorOptions) *schemaPropsValidator {
49 if opts == nil {
50 opts = new(SchemaValidatorOptions)
51 }
52
53 anyValidators := make([]*SchemaValidator, 0, len(anyOf))
54 for i := range anyOf {
55 anyValidators = append(anyValidators, newSchemaValidator(&anyOf[i], root, path, formats, opts))
56 }
57 allValidators := make([]*SchemaValidator, 0, len(allOf))
58 for i := range allOf {
59 allValidators = append(allValidators, newSchemaValidator(&allOf[i], root, path, formats, opts))
60 }
61 oneValidators := make([]*SchemaValidator, 0, len(oneOf))
62 for i := range oneOf {
63 oneValidators = append(oneValidators, newSchemaValidator(&oneOf[i], root, path, formats, opts))
64 }
65
66 var notValidator *SchemaValidator
67 if not != nil {
68 notValidator = newSchemaValidator(not, root, path, formats, opts)
69 }
70
71 var s *schemaPropsValidator
72 if opts.recycleValidators {
73 s = pools.poolOfSchemaPropsValidators.BorrowValidator()
74 } else {
75 s = new(schemaPropsValidator)
76 }
77
78 s.Path = path
79 s.In = in
80 s.AllOf = allOf
81 s.OneOf = oneOf
82 s.AnyOf = anyOf
83 s.Not = not
84 s.Dependencies = deps
85 s.anyOfValidators = anyValidators
86 s.allOfValidators = allValidators
87 s.oneOfValidators = oneValidators
88 s.notValidator = notValidator
89 s.Root = root
90 s.KnownFormats = formats
91 s.Options = opts
92
93 return s
94 }
95
96 func (s *schemaPropsValidator) Applies(source interface{}, _ reflect.Kind) bool {
97 _, isSchema := source.(*spec.Schema)
98 return isSchema
99 }
100
101 func (s *schemaPropsValidator) Validate(data interface{}) *Result {
102 var mainResult *Result
103 if s.Options.recycleResult {
104 mainResult = pools.poolOfResults.BorrowResult()
105 } else {
106 mainResult = new(Result)
107 }
108
109
110
111
112 var keepResultAnyOf, keepResultOneOf, keepResultAllOf *Result
113
114 if s.Options.recycleValidators {
115 defer func() {
116 s.redeemChildren()
117 s.redeem()
118
119
120 }()
121 }
122
123 if len(s.anyOfValidators) > 0 {
124 keepResultAnyOf = pools.poolOfResults.BorrowResult()
125 s.validateAnyOf(data, mainResult, keepResultAnyOf)
126 }
127
128 if len(s.oneOfValidators) > 0 {
129 keepResultOneOf = pools.poolOfResults.BorrowResult()
130 s.validateOneOf(data, mainResult, keepResultOneOf)
131 }
132
133 if len(s.allOfValidators) > 0 {
134 keepResultAllOf = pools.poolOfResults.BorrowResult()
135 s.validateAllOf(data, mainResult, keepResultAllOf)
136 }
137
138 if s.notValidator != nil {
139 s.validateNot(data, mainResult)
140 }
141
142 if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map {
143 s.validateDependencies(data, mainResult)
144 }
145
146 mainResult.Inc()
147
148
149
150 return mainResult.Merge(keepResultAllOf, keepResultOneOf, keepResultAnyOf)
151 }
152
153 func (s *schemaPropsValidator) validateAnyOf(data interface{}, mainResult, keepResultAnyOf *Result) {
154
155 var bestFailures *Result
156
157 for i, anyOfSchema := range s.anyOfValidators {
158 result := anyOfSchema.Validate(data)
159 if s.Options.recycleValidators {
160 s.anyOfValidators[i] = nil
161 }
162
163 keepResultAnyOf.Merge(result.keepRelevantErrors())
164
165 if result.IsValid() {
166 if bestFailures != nil && bestFailures.wantsRedeemOnMerge {
167 pools.poolOfResults.RedeemResult(bestFailures)
168 }
169
170 _ = keepResultAnyOf.cleared()
171 mainResult.Merge(result)
172
173 return
174 }
175
176
177 if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
178 if bestFailures != nil && bestFailures.wantsRedeemOnMerge {
179 pools.poolOfResults.RedeemResult(bestFailures)
180 }
181 bestFailures = result
182
183 continue
184 }
185
186 if result.wantsRedeemOnMerge {
187 pools.poolOfResults.RedeemResult(result)
188 }
189 }
190
191 mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path))
192 mainResult.Merge(bestFailures)
193 }
194
195 func (s *schemaPropsValidator) validateOneOf(data interface{}, mainResult, keepResultOneOf *Result) {
196
197 var (
198 firstSuccess, bestFailures *Result
199 validated int
200 )
201
202 for i, oneOfSchema := range s.oneOfValidators {
203 result := oneOfSchema.Validate(data)
204 if s.Options.recycleValidators {
205 s.oneOfValidators[i] = nil
206 }
207
208
209 keepResultOneOf.Merge(result.keepRelevantErrors())
210
211 if result.IsValid() {
212 validated++
213 _ = keepResultOneOf.cleared()
214
215 if firstSuccess == nil {
216 firstSuccess = result
217 } else if result.wantsRedeemOnMerge {
218 pools.poolOfResults.RedeemResult(result)
219 }
220
221 continue
222 }
223
224
225 if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
226 if bestFailures != nil && bestFailures.wantsRedeemOnMerge {
227 pools.poolOfResults.RedeemResult(bestFailures)
228 }
229 bestFailures = result
230 } else if result.wantsRedeemOnMerge {
231 pools.poolOfResults.RedeemResult(result)
232 }
233 }
234
235 switch validated {
236 case 0:
237 mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, "Found none valid"))
238 mainResult.Merge(bestFailures)
239
240 case 1:
241 mainResult.Merge(firstSuccess)
242 if bestFailures != nil && bestFailures.wantsRedeemOnMerge {
243 pools.poolOfResults.RedeemResult(bestFailures)
244 }
245 default:
246 mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, fmt.Sprintf("Found %d valid alternatives", validated)))
247 mainResult.Merge(bestFailures)
248 if firstSuccess != nil && firstSuccess.wantsRedeemOnMerge {
249 pools.poolOfResults.RedeemResult(firstSuccess)
250 }
251 }
252 }
253
254 func (s *schemaPropsValidator) validateAllOf(data interface{}, mainResult, keepResultAllOf *Result) {
255
256 var validated int
257
258 for i, allOfSchema := range s.allOfValidators {
259 result := allOfSchema.Validate(data)
260 if s.Options.recycleValidators {
261 s.allOfValidators[i] = nil
262 }
263
264 keepResultAllOf.Merge(result.keepRelevantErrors())
265 if result.IsValid() {
266 validated++
267 }
268 mainResult.Merge(result)
269 }
270
271 switch validated {
272 case 0:
273 mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, ". None validated"))
274 case len(s.allOfValidators):
275 default:
276 mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, ""))
277 }
278 }
279
280 func (s *schemaPropsValidator) validateNot(data interface{}, mainResult *Result) {
281 result := s.notValidator.Validate(data)
282 if s.Options.recycleValidators {
283 s.notValidator = nil
284 }
285
286 if result.IsValid() {
287 mainResult.AddErrors(mustNotValidatechemaMsg(s.Path))
288 }
289 if result.wantsRedeemOnMerge {
290 pools.poolOfResults.RedeemResult(result)
291 }
292 }
293
294 func (s *schemaPropsValidator) validateDependencies(data interface{}, mainResult *Result) {
295 val := data.(map[string]interface{})
296 for key := range val {
297 dep, ok := s.Dependencies[key]
298 if !ok {
299 continue
300 }
301
302 if dep.Schema != nil {
303 mainResult.Merge(
304 newSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats, s.Options).Validate(data),
305 )
306 continue
307 }
308
309 if len(dep.Property) > 0 {
310 for _, depKey := range dep.Property {
311 if _, ok := val[depKey]; !ok {
312 mainResult.AddErrors(hasADependencyMsg(s.Path, depKey))
313 }
314 }
315 }
316 }
317 }
318
319 func (s *schemaPropsValidator) redeem() {
320 pools.poolOfSchemaPropsValidators.RedeemValidator(s)
321 }
322
323 func (s *schemaPropsValidator) redeemChildren() {
324 for _, v := range s.anyOfValidators {
325 if v == nil {
326 continue
327 }
328 v.redeemChildren()
329 v.redeem()
330 }
331 s.anyOfValidators = nil
332
333 for _, v := range s.allOfValidators {
334 if v == nil {
335 continue
336 }
337 v.redeemChildren()
338 v.redeem()
339 }
340 s.allOfValidators = nil
341
342 for _, v := range s.oneOfValidators {
343 if v == nil {
344 continue
345 }
346 v.redeemChildren()
347 v.redeem()
348 }
349 s.oneOfValidators = nil
350
351 if s.notValidator != nil {
352 s.notValidator.redeemChildren()
353 s.notValidator.redeem()
354 s.notValidator = nil
355 }
356 }
357
View as plain text