Skip to content

Commit

Permalink
Merge pull request #147 from itaischwartz/bugfix/fix-nested-struct-va…
Browse files Browse the repository at this point in the history
…lidation

Fix nested struct validation
  • Loading branch information
goccy authored Jul 3, 2020
2 parents 74947c4 + 4e9286d commit 152a6fb
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 31 deletions.
9 changes: 6 additions & 3 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,8 @@ func (d *Decoder) deleteStructKeys(structType reflect.Type, unknownFields map[st
continue
}

structField, ok := structFieldMap[field.Name]
if !ok {
structField, exists := structFieldMap[field.Name]
if !exists {
continue
}

Expand Down Expand Up @@ -916,7 +916,10 @@ func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
continue
}
fieldName := fieldErr.StructField()
structField := structFieldMap[fieldName]
structField, exists := structFieldMap[fieldName]
if !exists {
continue
}
node, exists := keyToNodeMap[structField.RenderName]
if exists {
// TODO: to make FieldError message cutomizable
Expand Down
90 changes: 62 additions & 28 deletions validate_test.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,79 @@
package yaml_test

import (
"fmt"
"strings"
"testing"

"github.com/goccy/go-yaml"
"gopkg.in/go-playground/validator.v9"
)

type Person struct {
Name string `validate:"required"`
Age int `validate:"gte=0,lt=120"`
}
func TestStructValidator(t *testing.T) {

func ExampleStructValidator() {
yml := `---
cases := []struct {
TestName string
YAMLContent string
ExpectedErr string
Instance interface{}
}{
{
TestName: "Test Simple Validation",
YAMLContent: `---
- name: john
age: 20
- name: tom
age: -1
- name: ken
age: 10
`
validate := validator.New()
dec := yaml.NewDecoder(
strings.NewReader(yml),
yaml.Validator(validate),
)
var v []*Person
err := dec.Decode(&v)
if err == nil {
panic("expected error")
age: 10`,
ExpectedErr: `[5:8] Key: 'Age' Error:Field validation for 'Age' failed on the 'gte' tag
2 | - name: john
3 | age: 20
4 | - name: tom
> 5 | age: -1
^
6 | - name: ken
7 | age: 10`,
Instance: &[]struct {
Name string `yaml:"name" validate:"required"`
Age int `yaml:"age" validate:"gte=0,lt=120"`
}{},
},
{
TestName: "Test Nested Validation Missing Internal Required",
YAMLContent: `---
name: john
age: 10
addr:
number: seven`,
ExpectedErr: "",
Instance: &struct {
Name string `yaml:"name" validate:"required"`
Age int `yaml:"age" validate:"gte=0,lt=120"`
Addr struct {
Number string `yaml:"number" validate:"required"`
State string `yaml:"state" validate:"required"`
} `yaml:"addr"`
}{},
},
}

for _, tc := range cases {
tc := tc // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables
t.Run(tc.TestName, func(t *testing.T) {
validate := validator.New()
dec := yaml.NewDecoder(
strings.NewReader(tc.YAMLContent),
yaml.Validator(validate),
)
err := dec.Decode(tc.Instance)
switch {
case tc.ExpectedErr != "" && err == nil:
t.Fatal("expected error")
case tc.ExpectedErr == "" && err != nil:
t.Fatalf("unexpected error: %v", err)
case tc.ExpectedErr != "" && tc.ExpectedErr != err.Error():
t.Fatalf("expected `%s` but actual `%s`", tc.ExpectedErr, err.Error())
}
})
}
fmt.Printf("%v", err)
// OUTPUT:
// [5:8] Key: 'Person.Age' Error:Field validation for 'Age' failed on the 'gte' tag
// 2 | - name: john
// 3 | age: 20
// 4 | - name: tom
// > 5 | age: -1
// ^
// 6 | - name: ken
// 7 | age: 10
}

0 comments on commit 152a6fb

Please sign in to comment.