Skip to content

Commit

Permalink
Add native support for true and false schema
Browse files Browse the repository at this point in the history
  • Loading branch information
johandorland committed Aug 16, 2019
1 parent d5a76c7 commit be09369
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 11 deletions.
9 changes: 9 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ type errorTemplate struct {
}

type (

// FalseError. ErrorDetails: -
FalseError struct {
ResultErrorFields
}

// RequiredError indicates that a required field is missing
// ErrorDetails: property string
RequiredError struct {
Expand Down Expand Up @@ -208,6 +214,9 @@ func newError(err ResultError, context *JsonContext, value interface{}, locale l
var t string
var d string
switch err.(type) {
case *FalseError:
t = "false"
d = locale.False()
case *RequiredError:
t = "required"
d = locale.Required()
Expand Down
9 changes: 9 additions & 0 deletions locales.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ package gojsonschema
type (
// locale is an interface for defining custom error strings
locale interface {

// False returns a format-string for "false" schema validation errors
False() string

// Required returns a format-string for "required" schema validation errors
Required() string

Expand Down Expand Up @@ -188,6 +192,11 @@ type (
DefaultLocale struct{}
)

// False returns a format-string for "false" schema validation errors
func (l DefaultLocale) False() string {
return "False always fails validation"
}

// Required returns a format-string for "required" schema validation errors
func (l DefaultLocale) Required() string {
return `{{.property}} is required`
Expand Down
13 changes: 5 additions & 8 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,8 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
// As of draft 6 "true" is equivalent to an empty schema "{}" and false equals "{"not":{}}"
if *currentSchema.draft >= Draft6 && isKind(documentNode, reflect.Bool) {
b := documentNode.(bool)
if b {
documentNode = map[string]interface{}{}
} else {
documentNode = map[string]interface{}{"not": true}
}
currentSchema.pass = &b
return nil
}

if !isKind(documentNode, reflect.Map) {
Expand Down Expand Up @@ -813,7 +810,7 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
// validation : all

if existsMapKey(m, KEY_CONST) && *currentSchema.draft >= Draft6 {
is,err := marshalWithoutNumber(m[KEY_CONST])
is, err := marshalWithoutNumber(m[KEY_CONST])
if err != nil {
return err
}
Expand All @@ -823,7 +820,7 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
if existsMapKey(m, KEY_ENUM) {
if isKind(m[KEY_ENUM], reflect.Slice) {
for _, v := range m[KEY_ENUM].([]interface{}) {
is,err := marshalWithoutNumber(v)
is, err := marshalWithoutNumber(v)
if err != nil {
return err
}
Expand Down Expand Up @@ -919,7 +916,7 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
if existsMapKey(m, KEY_IF) {
if isKind(m[KEY_IF], reflect.Map, reflect.Bool) {
newSchema := &subSchema{property: KEY_IF, parent: currentSchema, ref: currentSchema.ref}
currentSchema._if = newSchema
currentSchema._if = newSchema
err := d.parseSchema(m[KEY_IF], newSchema)
if err != nil {
return err
Expand Down
37 changes: 36 additions & 1 deletion schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,41 @@ func TestFragmentLoader(t *testing.T) {
}
}

func TestAdditionalPropertiesErrorMessage(t *testing.T) {
schema := `{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"Device": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}`
text := `{
"Device":{
"Color" : true
}
}`
loader := NewBytesLoader([]byte(schema))
result, err := Validate(loader, NewBytesLoader([]byte(text)))
if err != nil {
t.Fatal(err)
}

if len(result.Errors()) != 1 {
t.Fatal("Expected 1 error but got", len(result.Errors()))
}

expected := "Device.Color: Invalid type. Expected: string, given: boolean"
actual := result.Errors()[0].String()
if actual != expected {
t.Fatalf("Expected '%s' but got '%s'", expected, actual)
}
}

// Inspired by http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3
const locationIndependentSchema = `{
"definitions": {
Expand Down Expand Up @@ -312,7 +347,7 @@ func TestLocationIndependentIdentifier(t *testing.T) {
t.Errorf("Got error: %s", err.Error())
}

if len(result.Errors()) != 2 || result.Errors()[0].Type() != "number_not" || result.Errors()[1].Type() != "number_all_of" {
if len(result.Errors()) != 2 || result.Errors()[0].Type() != "false" || result.Errors()[1].Type() != "number_all_of" {
t.Errorf("Got invalid validation result.")
}
}
Expand Down
7 changes: 5 additions & 2 deletions subSchema.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
package gojsonschema

import (
"github.com/xeipuuv/gojsonreference"
"math/big"
"regexp"
"github.com/xeipuuv/gojsonreference"
)

// Constants
Expand Down Expand Up @@ -86,6 +86,9 @@ type subSchema struct {

property string

// Quick pass/fail for boolean schemas
pass *bool

// Types associated with the subSchema
types jsonSchemaType

Expand Down Expand Up @@ -143,4 +146,4 @@ type subSchema struct {
_if *subSchema // if/else are golang keywords
_then *subSchema
_else *subSchema
}
}
13 changes: 13 additions & 0 deletions validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,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)
Expand Down

0 comments on commit be09369

Please sign in to comment.