本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
6.9KB

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