field name updates

pull/256/head
joeybloggs 8 years ago
parent e0e1af6a61
commit 7e731afde9
  1. 22
      errors.go
  2. 14
      struct_level.go
  3. 40
      validator.go
  4. 116
      validator_test.go

@ -86,7 +86,7 @@ type FieldError interface {
//
// NOTE: this field can be blank when validating a single primitive field
// using validate.Field(...) as there is no way to extract it's name
ActualNamespace() string
StructNamespace() string
// returns the fields name with the tag name taking precedence over the
// fields actual name.
@ -95,11 +95,11 @@ type FieldError interface {
// see ActualField for comparison
Field() string
// returns the fields actual name.
// returns the fields actual name from the struct, when able to determine.
//
// eq. "FirstName"
// see Field for comparison
ActualField() string
StructField() string
// returns the actual fields value in case needed for creating the error
// message
@ -131,9 +131,9 @@ type fieldError struct {
tag string
actualTag string
ns string
actualNs string
structNs string
field string
actualField string
structField string
value interface{}
param interface{}
kind reflect.Kind
@ -157,10 +157,10 @@ func (fe *fieldError) Namespace() string {
return fe.ns
}
// ActualNamespace returns the namespace for the field error, with the fields
// StructNamespace returns the namespace for the field error, with the fields
// actual name.
func (fe *fieldError) ActualNamespace() string {
return fe.actualNs
func (fe *fieldError) StructNamespace() string {
return fe.structNs
}
// Field returns the fields name with the tag name taking precedence over the
@ -169,9 +169,9 @@ func (fe *fieldError) Field() string {
return fe.field
}
// ActualField returns the fields actual name.
func (fe *fieldError) ActualField() string {
return fe.actualField
// returns the fields actual name from the struct, when able to determine.
func (fe *fieldError) StructField() string {
return fe.structField
}
// Value returns the actual fields value in case needed for creating the error

@ -10,6 +10,8 @@ type StructLevelFunc func(sl StructLevel)
type StructLevel interface {
// returns the main validation object, in case one want to call validations internally.
// this is so you don;t have to use anonymous functoins to get access to the validate
// instance.
Validator() *Validate
// returns the top level struct, if any
@ -104,7 +106,7 @@ func (v *validate) ReportError(field interface{}, fieldName, altName, tag string
}
ns := append(v.slNs, fieldName...)
nsActual := append(v.slActualNs, altName...)
nsActual := append(v.slStructNs, altName...)
switch kind {
case reflect.Invalid:
@ -114,9 +116,9 @@ func (v *validate) ReportError(field interface{}, fieldName, altName, tag string
tag: tag,
actualTag: tag,
ns: string(ns),
actualNs: string(nsActual),
structNs: string(nsActual),
field: fieldName,
actualField: altName,
structField: altName,
param: "",
kind: kind,
},
@ -129,9 +131,9 @@ func (v *validate) ReportError(field interface{}, fieldName, altName, tag string
tag: tag,
actualTag: tag,
ns: string(ns),
actualNs: string(nsActual),
structNs: string(nsActual),
field: fieldName,
actualField: altName,
structField: altName,
value: fv.Interface(),
param: "",
kind: kind,
@ -152,7 +154,7 @@ func (v *validate) ReportValidationErrors(relativeNamespace, relativeActualNames
err = errs[i].(*fieldError)
err.ns = string(append(append(v.slNs, err.ns...), err.field...))
err.actualNs = string(append(append(v.slActualNs, err.actualNs...), err.actualField...))
err.structNs = string(append(append(v.slStructNs, err.structNs...), err.structField...))
v.errs = append(v.errs, err)
}

@ -25,13 +25,13 @@ type validate struct {
slflParent reflect.Value
slCurrent reflect.Value
slNs []byte
slActualNs []byte
slStructNs []byte
flField reflect.Value
flParam string
}
// parent and current will be the same the first run of validateStruct
func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, actualNs []byte, ct *cTag) {
func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) {
first := len(ns) == 0
@ -45,8 +45,8 @@ func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, t
ns = append(ns, cs.Name...)
ns = append(ns, '.')
actualNs = append(actualNs, cs.Name...)
actualNs = append(actualNs, '.')
structNs = append(structNs, cs.Name...)
structNs = append(structNs, '.')
}
// ct is nil on top level struct, and structs as fields that have no tag info
@ -64,7 +64,7 @@ func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, t
}
}
v.traverseField(parent, current.Field(f.Idx), ns, actualNs, f, f.cTags)
v.traverseField(parent, current.Field(f.Idx), ns, structNs, f, f.cTags)
}
}
@ -76,14 +76,14 @@ func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, t
v.slflParent = parent
v.slCurrent = current
v.slNs = ns
v.slActualNs = actualNs
v.slStructNs = structNs
cs.fn(v)
}
}
// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, actualNs []byte, cf *cField, ct *cTag) {
func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) {
var typ reflect.Type
var kind reflect.Kind
@ -111,9 +111,9 @@ func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns
tag: ct.aliasTag,
actualTag: ct.tag,
ns: string(append(ns, cf.Name...)),
actualNs: string(append(actualNs, cf.AltName...)),
structNs: string(append(structNs, cf.AltName...)),
field: cf.AltName,
actualField: cf.Name,
structField: cf.Name,
param: ct.param,
kind: kind,
},
@ -127,9 +127,9 @@ func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns
tag: ct.aliasTag,
actualTag: ct.tag,
ns: string(append(ns, cf.Name...)),
actualNs: string(append(actualNs, cf.AltName...)),
structNs: string(append(structNs, cf.AltName...)),
field: cf.AltName,
actualField: cf.Name,
structField: cf.Name,
value: current.Interface(),
param: ct.param,
kind: kind,
@ -154,7 +154,7 @@ func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns
return
}
v.validateStruct(current, current, typ, append(append(ns, cf.Name...), '.'), append(append(actualNs, cf.AltName...), '.'), ct)
v.validateStruct(current, current, typ, append(append(ns, cf.Name...), '.'), append(append(structNs, cf.AltName...), '.'), ct)
return
}
}
@ -201,12 +201,12 @@ OUTER:
case reflect.Slice, reflect.Array:
for i := 0; i < current.Len(); i++ {
v.traverseField(parent, current.Index(i), ns, actualNs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct)
v.traverseField(parent, current.Index(i), ns, structNs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct)
}
case reflect.Map:
for _, key := range current.MapKeys() {
v.traverseField(parent, current.MapIndex(key), ns, actualNs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct)
v.traverseField(parent, current.MapIndex(key), ns, structNs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct)
}
default:
@ -257,9 +257,9 @@ OUTER:
tag: ct.aliasTag,
actualTag: ct.actualAliasTag,
ns: string(append(ns, cf.Name...)),
actualNs: string(append(actualNs, cf.AltName...)),
structNs: string(append(structNs, cf.AltName...)),
field: cf.AltName,
actualField: cf.Name,
structField: cf.Name,
value: current.Interface(),
param: ct.param,
kind: kind,
@ -274,9 +274,9 @@ OUTER:
tag: errTag[1:],
actualTag: errTag[1:],
ns: string(append(ns, cf.Name...)),
actualNs: string(append(actualNs, cf.AltName...)),
structNs: string(append(structNs, cf.AltName...)),
field: cf.AltName,
actualField: cf.Name,
structField: cf.Name,
value: current.Interface(),
param: ct.param,
kind: kind,
@ -305,9 +305,9 @@ OUTER:
tag: ct.aliasTag,
actualTag: ct.tag,
ns: string(append(ns, cf.Name...)),
actualNs: string(append(actualNs, cf.AltName...)),
structNs: string(append(structNs, cf.AltName...)),
field: cf.AltName,
actualField: cf.Name,
structField: cf.Name,
value: current.Interface(),
param: ct.param,
kind: kind,

@ -2,7 +2,9 @@ package validator
import (
"database/sql/driver"
"fmt"
"reflect"
"strings"
"testing"
. "gopkg.in/go-playground/assert.v1"
@ -96,7 +98,7 @@ type TestString struct {
// var validate = New(&Config{TagName: "validate"})
func AssertError(t *testing.T, err error, key, field, expectedTag string) {
func AssertError(t *testing.T, err error, key, field, actualField, expectedTag string) {
errs := err.(ValidationErrors)
@ -114,9 +116,26 @@ func AssertError(t *testing.T, err error, key, field, expectedTag string) {
EqualSkip(t, 2, found, true)
NotEqualSkip(t, 2, fe, nil)
EqualSkip(t, 2, fe.Field(), field)
EqualSkip(t, 2, fe.StructField(), actualField)
EqualSkip(t, 2, fe.Tag(), expectedTag)
}
func getError(err error, key string) FieldError {
errs := err.(ValidationErrors)
var fe FieldError
for i := 0; i < len(errs); i++ {
if errs[i].Namespace() == key {
fe = errs[i]
break
}
}
return fe
}
type valuer struct {
Name string
}
@ -301,50 +320,59 @@ func StructValidationTestStruct(sl StructLevel) {
// Inner1 *TestStructReturnValidationErrorsInner1 `json:"Inner1JSON"`
// }
// type Inner2Namespace struct {
// String []string `validate:"dive,required" json:"JSONString"`
// }
func TestNameNamespace(t *testing.T) {
// type Inner1Namespace struct {
// Inner2 *Inner2Namespace `json:"Inner2JSON"`
// }
type Inner2Namespace struct {
String []string `validate:"dive,required" json:"JSONString"`
}
// type Namespace struct {
// Inner1 *Inner1Namespace `json:"Inner1JSON"`
// }
type Inner1Namespace struct {
Inner2 *Inner2Namespace `json:"Inner2JSON"`
}
// func TestNameNamespace(t *testing.T) {
type Namespace struct {
Inner1 *Inner1Namespace `json:"Inner1JSON"`
}
// config := &Config{
// TagName: "validate",
// FieldNameTag: "json",
// }
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
// v1 := New(config)
// i2 := &Inner2Namespace{String: []string{"ok", "ok", "ok"}}
// i1 := &Inner1Namespace{Inner2: i2}
// ns := &Namespace{Inner1: i1}
if name == "-" {
return ""
}
// errs := v1.Struct(ns)
// Equal(t, errs, nil)
return name
})
// i2.String[1] = ""
i2 := &Inner2Namespace{String: []string{"ok", "ok", "ok"}}
i1 := &Inner1Namespace{Inner2: i2}
ns := &Namespace{Inner1: i1}
// errs = v1.Struct(ns)
// NotEqual(t, errs, nil)
errs := validate.Struct(ns)
Equal(t, errs, nil)
// ve := errs.(ValidationErrors)
// Equal(t, len(ve), 1)
// AssertError(t, errs, "Namespace.Inner1.Inner2.String[1]", "String[1]", "required")
i2.String[1] = ""
// fe, ok := ve["Namespace.Inner1.Inner2.String[1]"]
// Equal(t, ok, true)
errs = validate.Struct(ns)
NotEqual(t, errs, nil)
// Equal(t, fe.Field, "String[1]")
// Equal(t, fe.FieldNamespace, "Namespace.Inner1.Inner2.String[1]")
// Equal(t, fe.Name, "JSONString[1]")
// Equal(t, fe.NameNamespace, "Namespace.Inner1JSON.Inner2JSON.JSONString[1]")
// }
ve := errs.(ValidationErrors)
Equal(t, len(ve), 1)
AssertError(t, errs, "Namespace.Inner1.Inner2.String[1]", "JSONString[1]", "String[1]", "required")
fe := getError(ve, "Namespace.Inner1.Inner2.String[1]")
NotEqual(t, fe, nil)
Equal(t, fe.Field(), "JSONString[1]")
Equal(t, fe.StructField(), "String[1]")
fmt.Println(fe.Namespace())
fmt.Println(fe.StructNamespace())
Equal(t, fe.Namespace(), "Namespace.Inner1JSON.Inner2JSON.JSONString[1]")
Equal(t, fe.StructNamespace(), "Namespace.Inner1.Inner2.String[1]")
}
// func TestAnonymous(t *testing.T) {
@ -5667,16 +5695,16 @@ func TestStructInt32Validation(t *testing.T) {
Equal(t, len(errs.(ValidationErrors)), 10)
// Assert Fields
AssertError(t, errs, "TestInt32.Required", "Required", "required")
AssertError(t, errs, "TestInt32.Len", "Len", "len")
AssertError(t, errs, "TestInt32.Min", "Min", "min")
AssertError(t, errs, "TestInt32.Max", "Max", "max")
AssertError(t, errs, "TestInt32.MinMax", "MinMax", "min")
AssertError(t, errs, "TestInt32.Lt", "Lt", "lt")
AssertError(t, errs, "TestInt32.Lte", "Lte", "lte")
AssertError(t, errs, "TestInt32.Gt", "Gt", "gt")
AssertError(t, errs, "TestInt32.Gte", "Gte", "gte")
AssertError(t, errs, "TestInt32.OmitEmpty", "OmitEmpty", "max")
AssertError(t, errs, "TestInt32.Required", "Required", "Required", "required")
AssertError(t, errs, "TestInt32.Len", "Len", "Len", "len")
AssertError(t, errs, "TestInt32.Min", "Min", "Min", "min")
AssertError(t, errs, "TestInt32.Max", "Max", "Max", "max")
AssertError(t, errs, "TestInt32.MinMax", "MinMax", "MinMax", "min")
AssertError(t, errs, "TestInt32.Lt", "Lt", "Lt", "lt")
AssertError(t, errs, "TestInt32.Lte", "Lte", "Lte", "lte")
AssertError(t, errs, "TestInt32.Gt", "Gt", "Gt", "gt")
AssertError(t, errs, "TestInt32.Gte", "Gte", "Gte", "gte")
AssertError(t, errs, "TestInt32.OmitEmpty", "OmitEmpty", "OmitEmpty", "max")
}
// func TestStructUint64Validation(t *testing.T) {

Loading…
Cancel
Save