schema_props.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. package validate
  15. import (
  16. "fmt"
  17. "reflect"
  18. "github.com/go-openapi/spec"
  19. "github.com/go-openapi/strfmt"
  20. )
  21. type schemaPropsValidator struct {
  22. Path string
  23. In string
  24. AllOf []spec.Schema
  25. OneOf []spec.Schema
  26. AnyOf []spec.Schema
  27. Not *spec.Schema
  28. Dependencies spec.Dependencies
  29. anyOfValidators []SchemaValidator
  30. allOfValidators []SchemaValidator
  31. oneOfValidators []SchemaValidator
  32. notValidator *SchemaValidator
  33. Root interface{}
  34. KnownFormats strfmt.Registry
  35. }
  36. func (s *schemaPropsValidator) SetPath(path string) {
  37. s.Path = path
  38. }
  39. func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry) *schemaPropsValidator {
  40. anyValidators := make([]SchemaValidator, 0, len(anyOf))
  41. for _, v := range anyOf {
  42. anyValidators = append(anyValidators, *NewSchemaValidator(&v, root, path, formats))
  43. }
  44. allValidators := make([]SchemaValidator, 0, len(allOf))
  45. for _, v := range allOf {
  46. allValidators = append(allValidators, *NewSchemaValidator(&v, root, path, formats))
  47. }
  48. oneValidators := make([]SchemaValidator, 0, len(oneOf))
  49. for _, v := range oneOf {
  50. oneValidators = append(oneValidators, *NewSchemaValidator(&v, root, path, formats))
  51. }
  52. var notValidator *SchemaValidator
  53. if not != nil {
  54. notValidator = NewSchemaValidator(not, root, path, formats)
  55. }
  56. return &schemaPropsValidator{
  57. Path: path,
  58. In: in,
  59. AllOf: allOf,
  60. OneOf: oneOf,
  61. AnyOf: anyOf,
  62. Not: not,
  63. Dependencies: deps,
  64. anyOfValidators: anyValidators,
  65. allOfValidators: allValidators,
  66. oneOfValidators: oneValidators,
  67. notValidator: notValidator,
  68. Root: root,
  69. KnownFormats: formats,
  70. }
  71. }
  72. func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool {
  73. r := reflect.TypeOf(source) == specSchemaType
  74. debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
  75. return r
  76. }
  77. func (s *schemaPropsValidator) Validate(data interface{}) *Result {
  78. mainResult := new(Result)
  79. // Intermediary error results
  80. // IMPORTANT! messages from underlying validators
  81. keepResultAnyOf := new(Result)
  82. keepResultOneOf := new(Result)
  83. keepResultAllOf := new(Result)
  84. // Validates at least one in anyOf schemas
  85. var firstSuccess *Result
  86. if len(s.anyOfValidators) > 0 {
  87. var bestFailures *Result
  88. succeededOnce := false
  89. for _, anyOfSchema := range s.anyOfValidators {
  90. result := anyOfSchema.Validate(data)
  91. // We keep inner IMPORTANT! errors no matter what MatchCount tells us
  92. keepResultAnyOf.Merge(result.keepRelevantErrors())
  93. if result.IsValid() {
  94. bestFailures = nil
  95. succeededOnce = true
  96. if firstSuccess == nil {
  97. firstSuccess = result
  98. }
  99. keepResultAnyOf = new(Result)
  100. break
  101. }
  102. // MatchCount is used to select errors from the schema with most positive checks
  103. if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
  104. bestFailures = result
  105. }
  106. }
  107. if !succeededOnce {
  108. mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path))
  109. }
  110. if bestFailures != nil {
  111. mainResult.Merge(bestFailures)
  112. } else if firstSuccess != nil {
  113. mainResult.Merge(firstSuccess)
  114. }
  115. }
  116. // Validates exactly one in oneOf schemas
  117. if len(s.oneOfValidators) > 0 {
  118. var bestFailures *Result
  119. var firstSuccess *Result
  120. validated := 0
  121. for _, oneOfSchema := range s.oneOfValidators {
  122. result := oneOfSchema.Validate(data)
  123. // We keep inner IMPORTANT! errors no matter what MatchCount tells us
  124. keepResultOneOf.Merge(result.keepRelevantErrors())
  125. if result.IsValid() {
  126. validated++
  127. bestFailures = nil
  128. if firstSuccess == nil {
  129. firstSuccess = result
  130. }
  131. keepResultOneOf = new(Result)
  132. continue
  133. }
  134. // MatchCount is used to select errors from the schema with most positive checks
  135. if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
  136. bestFailures = result
  137. }
  138. }
  139. if validated != 1 {
  140. additionalMsg := ""
  141. if validated == 0 {
  142. additionalMsg = "Found none valid"
  143. } else {
  144. additionalMsg = fmt.Sprintf("Found %d valid alternatives", validated)
  145. }
  146. mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, additionalMsg))
  147. if bestFailures != nil {
  148. mainResult.Merge(bestFailures)
  149. }
  150. } else if firstSuccess != nil {
  151. mainResult.Merge(firstSuccess)
  152. }
  153. }
  154. // Validates all of allOf schemas
  155. if len(s.allOfValidators) > 0 {
  156. validated := 0
  157. for _, allOfSchema := range s.allOfValidators {
  158. result := allOfSchema.Validate(data)
  159. // We keep inner IMPORTANT! errors no matter what MatchCount tells us
  160. keepResultAllOf.Merge(result.keepRelevantErrors())
  161. //keepResultAllOf.Merge(result)
  162. if result.IsValid() {
  163. validated++
  164. }
  165. mainResult.Merge(result)
  166. }
  167. if validated != len(s.allOfValidators) {
  168. additionalMsg := ""
  169. if validated == 0 {
  170. additionalMsg = ". None validated"
  171. }
  172. mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, additionalMsg))
  173. }
  174. }
  175. if s.notValidator != nil {
  176. result := s.notValidator.Validate(data)
  177. // We keep inner IMPORTANT! errors no matter what MatchCount tells us
  178. if result.IsValid() {
  179. mainResult.AddErrors(mustNotValidatechemaMsg(s.Path))
  180. }
  181. }
  182. if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map {
  183. val := data.(map[string]interface{})
  184. for key := range val {
  185. if dep, ok := s.Dependencies[key]; ok {
  186. if dep.Schema != nil {
  187. mainResult.Merge(NewSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats).Validate(data))
  188. continue
  189. }
  190. if len(dep.Property) > 0 {
  191. for _, depKey := range dep.Property {
  192. if _, ok := val[depKey]; !ok {
  193. mainResult.AddErrors(hasADependencyMsg(s.Path, depKey))
  194. }
  195. }
  196. }
  197. }
  198. }
  199. }
  200. mainResult.Inc()
  201. // In the end we retain best failures for schema validation
  202. // plus, if any, composite errors which may explain special cases (tagged as IMPORTANT!).
  203. return mainResult.Merge(keepResultAllOf, keepResultOneOf, keepResultAnyOf)
  204. }