Skip to content

Commit

Permalink
POC: Implement an Object validator
Browse files Browse the repository at this point in the history
- leverages Schema validation to validate a sub document using Schema
- allows you to create arrays of objects which have their fields
  validated correctly.
  • Loading branch information
Yan-Fa Li authored and yanfali committed Jul 28, 2016
1 parent 98db8f2 commit 1f2820a
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
51 changes: 51 additions & 0 deletions schema/object.go
@@ -0,0 +1,51 @@
package schema

import (
"errors"
"fmt"
)

// Object validates objects which are defined by Schemas.
type Object struct {
Schema *Schema
}

// Compile implements Compiler interface
func (v *Object) Compile() error {
if v.Schema == nil {
return fmt.Errorf("No schema defined for object")
}

if err := compileDependencies(*v.Schema, v.Schema); err != nil {
return err
}
return nil
}

// ErrorMap to return lots of errors
type ErrorMap struct {
Details map[string][]interface{}
}

func (e ErrorMap) Error() string {
errorString := ""
for key, value := range e.Details {
errorString += fmt.Sprintf("%s: %s,", key, value)
}
return errorString
}

// Validate implements FieldValidator interface
func (v Object) Validate(value interface{}) (interface{}, error) {
dict, ok := value.(map[string]interface{})
if !ok {
return nil, errors.New("not a dict")
}
dest, errs := v.Schema.Validate(nil, dict)
if len(errs) > 0 {
errMap := ErrorMap{}
errMap.Details = errs
return nil, errMap
}
return dest, nil
}
130 changes: 130 additions & 0 deletions schema/object_test.go
@@ -0,0 +1,130 @@
package schema

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestInvalidObjectValidatorCompile(t *testing.T) {
v := &Object{}
err := v.Compile()
assert.Error(t, err)
}

func TestObjectValidatorCompile(t *testing.T) {
v := &Object{
Schema: &Schema{},
}
err := v.Compile()
assert.NoError(t, err)
}

func TestObjectWithSchemaValidatorCompile(t *testing.T) {
v := &Object{
Schema: &Schema{
Fields: Fields{
"test": Field{
Validator: String{},
},
},
},
}
err := v.Compile()
assert.NoError(t, err)
}

func TestObjectValidator(t *testing.T) {
obj := make(map[string]interface{})
obj["test"] = "hello"
v := &Object{
Schema: &Schema{
Fields: Fields{
"test": Field{
Validator: String{},
},
},
},
}
doc, err := v.Validate(obj)
assert.NoError(t, err)
assert.Equal(t, obj, doc)
}

func TestInvalidObjectValidator(t *testing.T) {
obj := make(map[string]interface{})
obj["test"] = 1
v := &Object{
Schema: &Schema{
Fields: Fields{
"test": Field{
Validator: String{},
},
},
},
}
_, err := v.Validate(obj)
assert.Error(t, err)
}

func TestErrorObjectCast(t *testing.T) {
obj := make(map[string]interface{})
obj["test"] = 1
v := &Object{
Schema: &Schema{
Fields: Fields{
"test": Field{
Validator: String{},
},
},
},
}
_, err := v.Validate(obj)
switch errMap := err.(type) {
case ErrorMap:
assert.True(t, true)
assert.Equal(t, len(errMap.Details), 1)
default:
assert.True(t, false)
}
}

func TestArrayOfObject(t *testing.T) {
obj := make(map[string]interface{})
obj["test"] = "a"
objb := make(map[string]interface{})
objb["test"] = "b"
value := &Object{
Schema: &Schema{
Fields: Fields{
"test": Field{
Validator: String{},
},
},
},
}
array := Array{ValuesValidator: value}
a := []interface{}{obj, objb}
_, err := array.Validate(a)
assert.NoError(t, err)
}

func TestErrorArrayOfObject(t *testing.T) {
obj := make(map[string]interface{})
obj["test"] = "a"
objb := make(map[string]interface{})
objb["test"] = 1
value := &Object{
Schema: &Schema{
Fields: Fields{
"test": Field{
Validator: String{},
},
},
},
}
array := Array{ValuesValidator: value}
a := []interface{}{obj, objb}
_, err := array.Validate(a)
assert.Error(t, err)
}

0 comments on commit 1f2820a

Please sign in to comment.