Skip to content

Commit

Permalink
chore: add more unit tests and fix some code style
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Jun 26, 2022
1 parent 150c83e commit 57f2c85
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 23 deletions.
34 changes: 19 additions & 15 deletions data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,18 +188,18 @@ type StructData struct {
// source struct data, from user setting
src interface{}
// max depth for parse sub-struct. TODO WIP ...
depth int
// depth int
// from reflect source Struct
value reflect.Value
// source struct reflect.Type
valueTpy reflect.Type
// field names in the src struct
// 0:common field 1:anonymous field 2:nonAnonymous field
fieldNames map[string]int8
// cache field value info
// cache field reflect value info. key is path. eg: top.sub
fieldValues map[string]reflect.Value
// TODO field reflect values cache
fieldRftValues map[string]interface{}
// fieldRftValues map[string]interface{}
// FilterTag name in the struct tags.
//
// see GlobalOption.FilterTag
Expand Down Expand Up @@ -249,7 +249,7 @@ func (d *StructData) Create(err ...error) *Validation {
// collect field filter/validate rules from struct tags
d.parseRulesFromTag(v)

// if has custom config func
// has custom config func
if d.valueTpy.Implements(cvFaceType) {
fv := d.value.MethodByName("ConfigValidation")
fv.Call([]reflect.Value{reflect.ValueOf(v)})
Expand Down Expand Up @@ -295,9 +295,6 @@ func (d *StructData) parseRulesFromTag(v *Validation) {
for i := 0; i < vt.NumField(); i++ {
fValue := removeValuePtr(vv).Field(i)
fv := vt.Field(i)
ft := vt.Field(i).Type
ft = removeTypePtr(ft)

// skip don't exported field
name := fv.Name
if name[0] >= 'a' && name[0] <= 'z' {
Expand Down Expand Up @@ -360,6 +357,8 @@ func (d *StructData) parseRulesFromTag(v *Validation) {
}
}

ft := removeTypePtr(vt.Field(i).Type)

// collect rules from sub-struct and from arrays/slices elements
if ft != timeType {
if fValue.Type().Kind() == reflect.Ptr && fValue.IsNil() {
Expand Down Expand Up @@ -447,14 +446,12 @@ func (d *StructData) loadMessagesFromTag(trans *Translator, field, vRule, vMsg s
vName = vRule
if strings.ContainsRune(vRule, '|') {
nodes := strings.SplitN(vRule, "|", 2)
// use first validator name
vName = nodes[0]
}

// has params for validator: "minLen:5"
if strings.ContainsRune(vName, ':') {
nodes := strings.SplitN(vRule, ":", 2)
// use first validator name
vName = nodes[0]
}
}
Expand Down Expand Up @@ -499,9 +496,13 @@ func (d *StructData) Get(field string) (val interface{}, exist bool) {

// TryGet value by field name. support get sub-value by path.
func (d *StructData) TryGet(field string) (val interface{}, exist, zero bool) {
var fv reflect.Value
field = strutil.UpperFirst(field)
// try read from cache
if fv, ok := d.fieldValues[field]; ok {
return fv.Interface(), true, fv.IsZero()
}

var fv reflect.Value
// want to get sub struct field.
if strings.IndexRune(field, '.') > 0 {
fieldNodes := strings.Split(field, ".")
Expand Down Expand Up @@ -534,7 +535,7 @@ func (d *StructData) TryGet(field string) (val interface{}, exist, zero bool) {
fv = fv.MapIndex(reflect.ValueOf(fieldNode))
case reflect.Struct:
fv = fv.FieldByName(fieldNode)
default: // no sub-value
default: // no sub-value, should never have happened
return
}

Expand Down Expand Up @@ -596,6 +597,7 @@ func (d *StructData) Set(field string, val interface{}) (newVal interface{}, err
return nil, ErrNoField
}

// find from cache
fv, ok := d.fieldValues[field]
if !ok {
f := d.fieldNames[field]
Expand Down Expand Up @@ -630,6 +632,9 @@ func (d *StructData) Set(field string, val interface{}) (newVal interface{}, err
default:
return nil, ErrNoField
}

// add cache
d.fieldValues[field] = fv
}

// check whether the value of v can be changed.
Expand Down Expand Up @@ -679,7 +684,6 @@ func (d *StructData) HasField(field string) bool {
d.fieldNames[field] = fieldAtTopStruct
return true
}

return false
}

Expand Down Expand Up @@ -788,9 +792,9 @@ func (d *FormData) Encode() string {
// Set sets the key to value. It replaces any existing values.
func (d *FormData) Set(field string, val interface{}) (newVal interface{}, err error) {
newVal = val
switch val.(type) {
switch tpVal := val.(type) {
case string:
d.Form.Set(field, val.(string))
d.Form.Set(field, tpVal)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
newVal = strutil.MustString(val)
d.Form.Set(field, newVal.(string))
Expand Down Expand Up @@ -886,7 +890,7 @@ func (d FormData) Int64(key string) int64 {
// Float returns the first element in data[key] converted to a float.
func (d FormData) Float(key string) float64 {
if val := d.String(key); val != "" {
result, _ := strconv.ParseFloat(val, 0)
result, _ := strconv.ParseFloat(val, 64)
return result
}
return 0
Expand Down
29 changes: 29 additions & 0 deletions data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"
"time"

"github.com/gookit/goutil/dump"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -97,6 +98,7 @@ func TestFormData(t *testing.T) {

// form
d.Add("newKey1", "new val1")
is.NotEmpty(d.Src())
is.Equal("new val1", d.String("newKey1"))
d.Del("newKey1")
is.Equal("", d.String("newKey1"))
Expand Down Expand Up @@ -184,6 +186,33 @@ func TestStructData_Create(t *testing.T) {
is.Equal("inhere", str)
}

func TestStructData_Set(t *testing.T) {
is := assert.New(t)
u := &UserForm{
Name: "new name",
Status: 3,
UpdateAt: time.Now(),
protected: "text",
Extra: []ExtraInfo{
{"xxx", 2},
},
}

d, err := FromStruct(u)
is.Nil(err)

v := d.Validation()
is.True(v.Errors.Empty())

dump.P(d.fieldNames)

_, err = d.Set("Extra.0.Github", "new url")
is.NoError(err)
val, ok := d.Get("Extra.0.Github")
is.True(ok)
is.Equal("new url", val)
}

func TestStructData_Get_ptrVal(t *testing.T) {
type Struct1 struct {
Name string `validate:"required"`
Expand Down
5 changes: 5 additions & 0 deletions issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,11 @@ func TestIssue_140(t *testing.T) {
dump.Println(err)
assert.Error(t, err)
assert.Equal(t, "Field2 is required when Field1 is [value]", err.One())

test.Field2 = "hi"
v = validate.Struct(test)
err = v.ValidateE()
assert.Nil(t, err)
}

// https://github.com/gookit/validate/issues/143
Expand Down
4 changes: 2 additions & 2 deletions rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ type Rule struct {
filterFunc func(val interface{}) (interface{}, error)
// custom check function's mate info
checkFuncMeta *funcMeta
// custom check is empty.
emptyChecker func(val interface{}) bool
// custom check is empty. TODO
// emptyChecker func(val interface{}) bool
}

// NewRule create new Rule instance
Expand Down
7 changes: 7 additions & 0 deletions validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,10 @@ func TestStruct_nexted_field_name_tag(t *testing.T) {
assert.True(t, strings.HasPrefix(nameErrStr, "Display-Name"))
assert.True(t, strings.HasPrefix(extHomeErrStr, "ext_info.home_page"))
}

func TestStruct_create_error(t *testing.T) {
v := Struct(nil)
assert.NotEmpty(t, v.Errors)
assert.Equal(t, "invalid input data", v.Errors.One())
assert.False(t, v.Validate())
}
2 changes: 1 addition & 1 deletion validating.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (v *Validation) Validate(scene ...string) bool {
v.sceneFields = v.sceneFieldMap()

// apply filter rules before validate.
if false == v.Filtering() && v.StopOnError {
if !v.Filtering() && v.StopOnError {
return false
}

Expand Down
7 changes: 3 additions & 4 deletions validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ func (v *Validation) validatorMeta(name string) *funcMeta {
}

// if v.data is StructData instance.
if sd, ok := v.data.(*StructData); ok {
fv, ok := sd.FuncValue(name)
if v.data.Type() == sourceStruct {
fv, ok := v.data.(*StructData).FuncValue(name)
if ok {
fm := newFuncMeta(name, false, fv)
// storage it.
Expand Down Expand Up @@ -441,8 +441,7 @@ func (v *Validation) GetWithDefault(key string) (val interface{}, exist, isDefau

// Filtered get filtered value by key
func (v *Validation) Filtered(key string) interface{} {
val, _ := v.filteredData[key]
return val
return v.filteredData[key]
}

// Safe get safe value by key
Expand Down
2 changes: 1 addition & 1 deletion validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ func Enum(val, enum interface{}) bool {

// NotIn value should be not in the given enum(strings, ints, uints).
func NotIn(val, enum interface{}) bool {
return false == Enum(val, enum)
return !Enum(val, enum)
}

/*************************************************************
Expand Down

0 comments on commit 57f2c85

Please sign in to comment.