Skip to content

Commit

Permalink
Support for custom formats on all primitive types (#280)
Browse files Browse the repository at this point in the history
* added support for custom formats on all types

* added tests for custom formats

* moved format checking to validateCommon

* added format comment

* moved format tests
  • Loading branch information
q-uint authored and johandorland committed Nov 14, 2019
1 parent 82fcdeb commit 001aa27
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 24 deletions.
117 changes: 117 additions & 0 deletions format_checkers_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gojsonschema

import (
"encoding/json"
"github.com/stretchr/testify/assert"
"testing"
)
Expand All @@ -21,3 +22,119 @@ func TestURIReferenceFormatCheckerIsFormat(t *testing.T) {
assert.True(t, checker.IsFormat("relative"))
assert.True(t, checker.IsFormat("https://dummyhost.com/dummy-path?dummy-qp-name=dummy-qp-value"))
}

const formatSchema = `{
"type": "object",
"properties": {
"arr": {"type": "array", "items": {"type": "string"}, "format": "ArrayChecker"},
"bool": {"type": "boolean", "format": "BoolChecker"},
"int": {"format": "IntegerChecker"},
"name": {"type": "string"},
"str": {"type": "string", "format": "StringChecker"}
},
"format": "ObjectChecker",
"required": ["name"]
}`

type arrayChecker struct{}

func (c arrayChecker) IsFormat(input interface{}) bool {
arr, ok := input.([]interface{})
if !ok {
return true
}
for _, v := range arr {
if v == "x" {
return true
}
}
return false
}

type boolChecker struct{}

func (c boolChecker) IsFormat(input interface{}) bool {
b, ok := input.(bool)
if !ok {
return true
}
return b
}

type integerChecker struct{}

func (c integerChecker) IsFormat(input interface{}) bool {
number, ok := input.(json.Number)
if !ok {
return true
}
f, _ := number.Float64()
return int(f)%2 == 0
}

type objectChecker struct{}

func (c objectChecker) IsFormat(input interface{}) bool {
obj, ok := input.(map[string]interface{})
if !ok {
return true
}
return obj["name"] == "x"
}

type stringChecker struct{}

func (c stringChecker) IsFormat(input interface{}) bool {
str, ok := input.(string)
if !ok {
return true
}
return str == "o"
}

func TestCustomFormat(t *testing.T) {
FormatCheckers.
Add("ArrayChecker", arrayChecker{}).
Add("BoolChecker", boolChecker{}).
Add("IntegerChecker", integerChecker{}).
Add("ObjectChecker", objectChecker{}).
Add("StringChecker", stringChecker{})

sl := NewStringLoader(formatSchema)
validResult, err := Validate(sl, NewGoLoader(map[string]interface{}{
"arr": []string{"x", "y", "z"},
"bool": true,
"int": "2", // format not defined for string
"name": "x",
"str": "o",
}))
if err != nil {
t.Error(err)
}

if !validResult.Valid() {
for _, desc := range validResult.Errors() {
t.Error(desc)
}
}

invalidResult, err := Validate(sl, NewGoLoader(map[string]interface{}{
"arr": []string{"a", "b", "c"},
"bool": false,
"int": 1,
"name": "z",
"str": "a",
}))
if err != nil {
t.Error(err)
}

assert.Len(t, invalidResult.Errors(), 5)

FormatCheckers.
Remove("ArrayChecker").
Remove("BoolChecker").
Remove("IntegerChecker").
Remove("ObjectChecker").
Remove("StringChecker")
}
36 changes: 12 additions & 24 deletions validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,18 @@ func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{
}
}

// format:
if currentSubSchema.format != "" {
if !FormatCheckers.IsFormat(currentSubSchema.format, value) {
result.addInternalError(
new(DoesNotMatchFormatError),
context,
value,
ErrorDetails{"format": currentSubSchema.format},
)
}
}

result.incrementScore()
}

Expand Down Expand Up @@ -746,18 +758,6 @@ func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{
}
}

// format
if currentSubSchema.format != "" {
if !FormatCheckers.IsFormat(currentSubSchema.format, stringValue) {
result.addInternalError(
new(DoesNotMatchFormatError),
context,
value,
ErrorDetails{"format": currentSubSchema.format},
)
}
}

result.incrementScore()
}

Expand Down Expand Up @@ -842,17 +842,5 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{
}
}

// format
if currentSubSchema.format != "" {
if !FormatCheckers.IsFormat(currentSubSchema.format, float64Value) {
result.addInternalError(
new(DoesNotMatchFormatError),
context,
value,
ErrorDetails{"format": currentSubSchema.format},
)
}
}

result.incrementScore()
}

0 comments on commit 001aa27

Please sign in to comment.