podman
240 строк · 6.9 Кб
1// Copyright 2015 go-swagger maintainers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package validate
16
17import (
18"fmt"
19"reflect"
20
21"github.com/go-openapi/spec"
22"github.com/go-openapi/strfmt"
23)
24
25type schemaPropsValidator struct {
26Path string
27In string
28AllOf []spec.Schema
29OneOf []spec.Schema
30AnyOf []spec.Schema
31Not *spec.Schema
32Dependencies spec.Dependencies
33anyOfValidators []SchemaValidator
34allOfValidators []SchemaValidator
35oneOfValidators []SchemaValidator
36notValidator *SchemaValidator
37Root interface{}
38KnownFormats strfmt.Registry
39Options SchemaValidatorOptions
40}
41
42func (s *schemaPropsValidator) SetPath(path string) {
43s.Path = path
44}
45
46func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry, options ...Option) *schemaPropsValidator {
47anyValidators := make([]SchemaValidator, 0, len(anyOf))
48for _, v := range anyOf {
49v := v
50anyValidators = append(anyValidators, *NewSchemaValidator(&v, root, path, formats, options...))
51}
52allValidators := make([]SchemaValidator, 0, len(allOf))
53for _, v := range allOf {
54v := v
55allValidators = append(allValidators, *NewSchemaValidator(&v, root, path, formats, options...))
56}
57oneValidators := make([]SchemaValidator, 0, len(oneOf))
58for _, v := range oneOf {
59v := v
60oneValidators = append(oneValidators, *NewSchemaValidator(&v, root, path, formats, options...))
61}
62
63var notValidator *SchemaValidator
64if not != nil {
65notValidator = NewSchemaValidator(not, root, path, formats, options...)
66}
67
68schOptions := &SchemaValidatorOptions{}
69for _, o := range options {
70o(schOptions)
71}
72return &schemaPropsValidator{
73Path: path,
74In: in,
75AllOf: allOf,
76OneOf: oneOf,
77AnyOf: anyOf,
78Not: not,
79Dependencies: deps,
80anyOfValidators: anyValidators,
81allOfValidators: allValidators,
82oneOfValidators: oneValidators,
83notValidator: notValidator,
84Root: root,
85KnownFormats: formats,
86Options: *schOptions,
87}
88}
89
90func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool {
91r := reflect.TypeOf(source) == specSchemaType
92debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
93return r
94}
95
96func (s *schemaPropsValidator) Validate(data interface{}) *Result {
97mainResult := new(Result)
98
99// Intermediary error results
100
101// IMPORTANT! messages from underlying validators
102keepResultAnyOf := new(Result)
103keepResultOneOf := new(Result)
104keepResultAllOf := new(Result)
105
106// Validates at least one in anyOf schemas
107var firstSuccess *Result
108if len(s.anyOfValidators) > 0 {
109var bestFailures *Result
110succeededOnce := false
111for _, anyOfSchema := range s.anyOfValidators {
112result := anyOfSchema.Validate(data)
113// We keep inner IMPORTANT! errors no matter what MatchCount tells us
114keepResultAnyOf.Merge(result.keepRelevantErrors())
115if result.IsValid() {
116bestFailures = nil
117succeededOnce = true
118if firstSuccess == nil {
119firstSuccess = result
120}
121keepResultAnyOf = new(Result)
122break
123}
124// MatchCount is used to select errors from the schema with most positive checks
125if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
126bestFailures = result
127}
128}
129
130if !succeededOnce {
131mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path))
132}
133if bestFailures != nil {
134mainResult.Merge(bestFailures)
135} else if firstSuccess != nil {
136mainResult.Merge(firstSuccess)
137}
138}
139
140// Validates exactly one in oneOf schemas
141if len(s.oneOfValidators) > 0 {
142var bestFailures *Result
143var firstSuccess *Result
144validated := 0
145
146for _, oneOfSchema := range s.oneOfValidators {
147result := oneOfSchema.Validate(data)
148// We keep inner IMPORTANT! errors no matter what MatchCount tells us
149keepResultOneOf.Merge(result.keepRelevantErrors())
150if result.IsValid() {
151validated++
152bestFailures = nil
153if firstSuccess == nil {
154firstSuccess = result
155}
156keepResultOneOf = new(Result)
157continue
158}
159// MatchCount is used to select errors from the schema with most positive checks
160if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
161bestFailures = result
162}
163}
164
165if validated != 1 {
166var additionalMsg string
167if validated == 0 {
168additionalMsg = "Found none valid"
169} else {
170additionalMsg = fmt.Sprintf("Found %d valid alternatives", validated)
171}
172
173mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, additionalMsg))
174if bestFailures != nil {
175mainResult.Merge(bestFailures)
176}
177} else if firstSuccess != nil {
178mainResult.Merge(firstSuccess)
179}
180}
181
182// Validates all of allOf schemas
183if len(s.allOfValidators) > 0 {
184validated := 0
185
186for _, allOfSchema := range s.allOfValidators {
187result := allOfSchema.Validate(data)
188// We keep inner IMPORTANT! errors no matter what MatchCount tells us
189keepResultAllOf.Merge(result.keepRelevantErrors())
190// keepResultAllOf.Merge(result)
191if result.IsValid() {
192validated++
193}
194mainResult.Merge(result)
195}
196
197if validated != len(s.allOfValidators) {
198additionalMsg := ""
199if validated == 0 {
200additionalMsg = ". None validated"
201}
202
203mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, additionalMsg))
204}
205}
206
207if s.notValidator != nil {
208result := s.notValidator.Validate(data)
209// We keep inner IMPORTANT! errors no matter what MatchCount tells us
210if result.IsValid() {
211mainResult.AddErrors(mustNotValidatechemaMsg(s.Path))
212}
213}
214
215if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map {
216val := data.(map[string]interface{})
217for key := range val {
218if dep, ok := s.Dependencies[key]; ok {
219
220if dep.Schema != nil {
221mainResult.Merge(NewSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats, s.Options.Options()...).Validate(data))
222continue
223}
224
225if len(dep.Property) > 0 {
226for _, depKey := range dep.Property {
227if _, ok := val[depKey]; !ok {
228mainResult.AddErrors(hasADependencyMsg(s.Path, depKey))
229}
230}
231}
232}
233}
234}
235
236mainResult.Inc()
237// In the end we retain best failures for schema validation
238// plus, if any, composite errors which may explain special cases (tagged as IMPORTANT!).
239return mainResult.Merge(keepResultAllOf, keepResultOneOf, keepResultAnyOf)
240}
241