diff options
Diffstat (limited to 'vendor/github.com/xeipuuv/gojsonschema/validation.go')
-rw-r--r-- | vendor/github.com/xeipuuv/gojsonschema/validation.go | 199 |
1 files changed, 66 insertions, 133 deletions
diff --git a/vendor/github.com/xeipuuv/gojsonschema/validation.go b/vendor/github.com/xeipuuv/gojsonschema/validation.go index 090c11e93..74091bca1 100644 --- a/vendor/github.com/xeipuuv/gojsonschema/validation.go +++ b/vendor/github.com/xeipuuv/gojsonschema/validation.go @@ -35,42 +35,29 @@ import ( "unicode/utf8" ) +// Validate loads and validates a JSON schema func Validate(ls JSONLoader, ld JSONLoader) (*Result, error) { - - var err error - // load schema - schema, err := NewSchema(ls) if err != nil { return nil, err } - - // begine validation - return schema.Validate(ld) - } +// Validate loads and validates a JSON document func (v *Schema) Validate(l JSONLoader) (*Result, error) { - - // load document - root, err := l.LoadJSON() if err != nil { return nil, err } - return v.validateDocument(root), nil } func (v *Schema) validateDocument(root interface{}) *Result { - // begin validation - result := &Result{} context := NewJsonContext(STRING_CONTEXT_ROOT, nil) v.rootSchema.validateRecursive(v.rootSchema, root, result, context) - return result } @@ -88,6 +75,19 @@ func (v *subSchema) validateRecursive(currentSubSchema *subSchema, currentNode i internalLog(" %v", currentNode) } + // Handle true/false schema as early as possible as all other fields will be nil + if currentSubSchema.pass != nil { + if !*currentSubSchema.pass { + result.addInternalError( + new(FalseError), + context, + currentNode, + ErrorDetails{}, + ) + } + return + } + // Handle referenced schemas, returns directly when a $ref is found if currentSubSchema.refSchema != nil { v.validateRecursive(currentSubSchema.refSchema, currentNode, result, context) @@ -114,11 +114,11 @@ func (v *subSchema) validateRecursive(currentSubSchema *subSchema, currentNode i } else { // Not a null value - if isJsonNumber(currentNode) { + if isJSONNumber(currentNode) { value := currentNode.(json.Number) - isInt := checkJsonInteger(value) + isInt := checkJSONInteger(value) validType := currentSubSchema.types.Contains(TYPE_NUMBER) || (isInt && currentSubSchema.types.Contains(TYPE_INTEGER)) @@ -424,11 +424,11 @@ func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{ // enum: if len(currentSubSchema.enum) > 0 { - has, err := currentSubSchema.ContainsEnum(value) + vString, err := marshalWithoutNumber(value) if err != nil { result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err}) } - if !has { + if !isStringInSlice(currentSubSchema.enum, *vString) { result.addInternalError( new(EnumError), context, @@ -516,13 +516,13 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface // uniqueItems: if currentSubSchema.uniqueItems { - var stringifiedItems []string + var stringifiedItems = make(map[string]int) for j, v := range value { vString, err := marshalWithoutNumber(v) if err != nil { result.addInternalError(new(InternalError), context, value, ErrorDetails{"err": err}) } - if i := indexStringInSlice(stringifiedItems, *vString); i > -1 { + if i, ok := stringifiedItems[*vString]; ok { result.addInternalError( new(ItemsMustBeUniqueError), context, @@ -530,7 +530,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface ErrorDetails{"type": TYPE_ARRAY, "i": i, "j": j}, ) } - stringifiedItems = append(stringifiedItems, *vString) + stringifiedItems[*vString] = j } } @@ -614,101 +614,37 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string } // additionalProperty & patternProperty: - if currentSubSchema.additionalProperties != nil { - - switch currentSubSchema.additionalProperties.(type) { - case bool: - - if !currentSubSchema.additionalProperties.(bool) { - - for pk := range value { - - found := false - for _, spValue := range currentSubSchema.propertiesChildren { - if pk == spValue.property { - found = true - } - } - - pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) - - if found { - - if pp_has && !pp_match { - result.addInternalError( - new(AdditionalPropertyNotAllowedError), - context, - value[pk], - ErrorDetails{"property": pk}, - ) - } - - } else { - - if !pp_has || !pp_match { - result.addInternalError( - new(AdditionalPropertyNotAllowedError), - context, - value[pk], - ErrorDetails{"property": pk}, - ) - } - - } - } - } - - case *subSchema: - - additionalPropertiesSchema := currentSubSchema.additionalProperties.(*subSchema) - for pk := range value { - - found := false - for _, spValue := range currentSubSchema.propertiesChildren { - if pk == spValue.property { - found = true - } - } - - pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) - - if found { - - if pp_has && !pp_match { - validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context) - result.mergeErrors(validationResult) - } - - } else { - - if !pp_has || !pp_match { - validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context) - result.mergeErrors(validationResult) - } - - } + for pk := range value { + // Check whether this property is described by "properties" + found := false + for _, spValue := range currentSubSchema.propertiesChildren { + if pk == spValue.property { + found = true } } - } else { - for pk := range value { - - pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) + // Check whether this property is described by "patternProperties" + ppMatch := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) - if pp_has && !pp_match { + // If it is not described by neither "properties" nor "patternProperties" it must pass "additionalProperties" + if !found && !ppMatch { + switch ap := currentSubSchema.additionalProperties.(type) { + case bool: + // Handle the boolean case separately as it's cleaner to return a specific error than failing to pass the false schema + if !ap { + result.addInternalError( + new(AdditionalPropertyNotAllowedError), + context, + value[pk], + ErrorDetails{"property": pk}, + ) - result.addInternalError( - new(InvalidPropertyPatternError), - context, - value[pk], - ErrorDetails{ - "property": pk, - "pattern": currentSubSchema.PatternPropertiesString(), - }, - ) + } + case *subSchema: + validationResult := ap.subValidateWithContext(value[pk], NewJsonContext(pk, context)) + result.mergeErrors(validationResult) } - } } @@ -730,40 +666,36 @@ func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string result.incrementScore() } -func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *JsonContext) (has bool, matched bool) { +func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *JsonContext) bool { if internalLogEnabled { internalLog("validatePatternProperty %s", context.String()) internalLog(" %s %v", key, value) } - has = false - - validatedkey := false + validated := false for pk, pv := range currentSubSchema.patternProperties { if matches, _ := regexp.MatchString(pk, key); matches { - has = true + validated = true subContext := NewJsonContext(key, context) validationResult := pv.subValidateWithContext(value, subContext) result.mergeErrors(validationResult) - validatedkey = true } } - if !validatedkey { - return has, false + if !validated { + return false } result.incrementScore() - - return has, true + return true } func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { // Ignore JSON numbers - if isJsonNumber(value) { + if isJSONNumber(value) { return } @@ -832,7 +764,7 @@ func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { // Ignore non numbers - if !isJsonNumber(value) { + if !isJSONNumber(value) { return } @@ -850,8 +782,10 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{ result.addInternalError( new(MultipleOfError), context, - resultErrorFormatJsonNumber(number), - ErrorDetails{"multiple": new(big.Float).SetRat(currentSubSchema.multipleOf)}, + number, + ErrorDetails{ + "multiple": new(big.Float).SetRat(currentSubSchema.multipleOf), + }, ) } } @@ -862,9 +796,9 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{ result.addInternalError( new(NumberLTEError), context, - resultErrorFormatJsonNumber(number), + number, ErrorDetails{ - "max": currentSubSchema.maximum, + "max": new(big.Float).SetRat(currentSubSchema.maximum), }, ) } @@ -874,9 +808,9 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{ result.addInternalError( new(NumberLTError), context, - resultErrorFormatJsonNumber(number), + number, ErrorDetails{ - "max": currentSubSchema.exclusiveMaximum, + "max": new(big.Float).SetRat(currentSubSchema.exclusiveMaximum), }, ) } @@ -888,22 +822,21 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{ result.addInternalError( new(NumberGTEError), context, - resultErrorFormatJsonNumber(number), + number, ErrorDetails{ - "min": currentSubSchema.minimum, + "min": new(big.Float).SetRat(currentSubSchema.minimum), }, ) } } if currentSubSchema.exclusiveMinimum != nil { if float64Value.Cmp(currentSubSchema.exclusiveMinimum) <= 0 { - // if float64Value <= *currentSubSchema.minimum { result.addInternalError( new(NumberGTError), context, - resultErrorFormatJsonNumber(number), + number, ErrorDetails{ - "min": currentSubSchema.exclusiveMinimum, + "min": new(big.Float).SetRat(currentSubSchema.exclusiveMinimum), }, ) } |