vendor: update buildkit with typed errors support

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2020-06-24 22:20:05 -07:00
parent 0269388aa7
commit 2d720a1e0b
619 changed files with 38296 additions and 104947 deletions

View File

@ -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,21 +516,21 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
// uniqueItems:
if currentSubSchema.uniqueItems {
var stringifiedItems []string
for _, v := range value {
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 isStringInSlice(stringifiedItems, *vString) {
if i, ok := stringifiedItems[*vString]; ok {
result.addInternalError(
new(ItemsMustBeUniqueError),
context,
value,
ErrorDetails{"type": TYPE_ARRAY},
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 {
// Check whether this property is described by "patternProperties"
ppMatch := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context)
pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context)
// 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},
)
if pp_has && !pp_match {
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,42 +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)
if validationResult.Valid() {
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
}
@ -834,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
}
@ -844,73 +774,71 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{
}
number := value.(json.Number)
float64Value, _ := new(big.Float).SetString(string(number))
float64Value, _ := new(big.Rat).SetString(string(number))
// multipleOf:
if currentSubSchema.multipleOf != nil {
if q := new(big.Float).Quo(float64Value, currentSubSchema.multipleOf); !q.IsInt() {
if q := new(big.Rat).Quo(float64Value, currentSubSchema.multipleOf); !q.IsInt() {
result.addInternalError(
new(MultipleOfError),
context,
resultErrorFormatJsonNumber(number),
ErrorDetails{"multiple": currentSubSchema.multipleOf},
number,
ErrorDetails{
"multiple": new(big.Float).SetRat(currentSubSchema.multipleOf),
},
)
}
}
//maximum & exclusiveMaximum:
if currentSubSchema.maximum != nil {
if currentSubSchema.exclusiveMaximum {
if float64Value.Cmp(currentSubSchema.maximum) >= 0 {
result.addInternalError(
new(NumberLTError),
context,
resultErrorFormatJsonNumber(number),
ErrorDetails{
"max": currentSubSchema.maximum,
},
)
}
} else {
if float64Value.Cmp(currentSubSchema.maximum) == 1 {
result.addInternalError(
new(NumberLTEError),
context,
resultErrorFormatJsonNumber(number),
ErrorDetails{
"max": currentSubSchema.maximum,
},
)
}
if float64Value.Cmp(currentSubSchema.maximum) == 1 {
result.addInternalError(
new(NumberLTEError),
context,
number,
ErrorDetails{
"max": new(big.Float).SetRat(currentSubSchema.maximum),
},
)
}
}
if currentSubSchema.exclusiveMaximum != nil {
if float64Value.Cmp(currentSubSchema.exclusiveMaximum) >= 0 {
result.addInternalError(
new(NumberLTError),
context,
number,
ErrorDetails{
"max": new(big.Float).SetRat(currentSubSchema.exclusiveMaximum),
},
)
}
}
//minimum & exclusiveMinimum:
if currentSubSchema.minimum != nil {
if currentSubSchema.exclusiveMinimum {
if float64Value.Cmp(currentSubSchema.minimum) <= 0 {
// if float64Value <= *currentSubSchema.minimum {
result.addInternalError(
new(NumberGTError),
context,
resultErrorFormatJsonNumber(number),
ErrorDetails{
"min": currentSubSchema.minimum,
},
)
}
} else {
if float64Value.Cmp(currentSubSchema.minimum) == -1 {
result.addInternalError(
new(NumberGTEError),
context,
resultErrorFormatJsonNumber(number),
ErrorDetails{
"min": currentSubSchema.minimum,
},
)
}
if float64Value.Cmp(currentSubSchema.minimum) == -1 {
result.addInternalError(
new(NumberGTEError),
context,
number,
ErrorDetails{
"min": new(big.Float).SetRat(currentSubSchema.minimum),
},
)
}
}
if currentSubSchema.exclusiveMinimum != nil {
if float64Value.Cmp(currentSubSchema.exclusiveMinimum) <= 0 {
result.addInternalError(
new(NumberGTError),
context,
number,
ErrorDetails{
"min": new(big.Float).SetRat(currentSubSchema.exclusiveMinimum),
},
)
}
}