diff --git a/_examples/map-validation/main.go b/_examples/map-validation/main.go index dfcfa4f..b25816e 100644 --- a/_examples/map-validation/main.go +++ b/_examples/map-validation/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/go-playground/validator/v10" ) diff --git a/errors.go b/errors.go index 9a1b1ab..9449415 100644 --- a/errors.go +++ b/errors.go @@ -208,7 +208,13 @@ func (fe *fieldError) StructNamespace() string { // field's actual name. func (fe *fieldError) Field() string { - return fe.ns[len(fe.ns)-int(fe.fieldLen):] + nsLength, fieldLength := len(fe.ns), int(fe.fieldLen) + + if fieldLength == 0 { + return fe.ns + } + + return fe.ns[nsLength-fieldLength:] // // return fe.field // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] diff --git a/validator_instance.go b/validator_instance.go index 9493da4..44bf6bd 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -172,7 +172,7 @@ func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]interface{ errs[field] = errors.New("The field: '" + field + "' is not a map to dive") } } else if ruleStr, ok := rule.(string); ok { - err := v.VarCtx(ctx, data[field], ruleStr) + err := v.VarCtx(ctx, data[field], ruleStr, field) if err != nil { errs[field] = err } @@ -609,7 +609,7 @@ func (v *Validate) StructExceptCtx(ctx context.Context, s interface{}, fields .. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. // validate Array, Slice and maps fields which may contain more than one error func (v *Validate) Var(field interface{}, tag string) error { - return v.VarCtx(context.Background(), field, tag) + return v.VarCtx(context.Background(), field, tag, "") } // VarCtx validates a single variable using tag style validation and allows passing of contextual @@ -626,7 +626,7 @@ func (v *Validate) Var(field interface{}, tag string) error { // It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise. // You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors. // validate Array, Slice and maps fields which may contain more than one error -func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (err error) { +func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag, keyName string) (err error) { if len(tag) == 0 || tag == skipValidationTag { return nil } @@ -636,7 +636,7 @@ func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (e vd := v.pool.Get().(*validate) vd.top = val vd.isPartial = false - vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) + vd.traverseField(ctx, val, val, []byte(keyName), vd.actualNs[0:0], defaultCField, ctag) if len(vd.errs) > 0 { err = vd.errs diff --git a/validator_test.go b/validator_test.go index 1ebdea5..8ab11a9 100644 --- a/validator_test.go +++ b/validator_test.go @@ -2230,7 +2230,7 @@ func TestSQLValue2Validation(t *testing.T) { AssertError(t, errs, "", "", "", "", "required") val.Name = "Valid Name" - errs = validate.VarCtx(context.Background(), val, "required") + errs = validate.Var(val, "required") Equal(t, errs, nil) val.Name = "errorme" @@ -12264,25 +12264,69 @@ func TestCreditCardFormatValidation(t *testing.T) { } func TestMultiOrOperatorGroup(t *testing.T) { - tests := []struct { - Value int `validate:"eq=1|gte=5,eq=1|lt=7"` - expected bool - }{ - {1, true}, {2, false}, {5, true}, {6, true}, {8, false}, - } - - validate := New() - - for i, test := range tests { - errs := validate.Struct(test) - if test.expected { - if !IsEqual(errs, nil) { - t.Fatalf("Index: %d multi_group_of_OR_operators failed Error: %s", i, errs) - } - } else { - if IsEqual(errs, nil) { - t.Fatalf("Index: %d multi_group_of_OR_operators should have errs", i) - } - } - } - } + tests := []struct { + Value int `validate:"eq=1|gte=5,eq=1|lt=7"` + expected bool + }{ + {1, true}, {2, false}, {5, true}, {6, true}, {8, false}, + } + + validate := New() + + for i, test := range tests { + errs := validate.Struct(test) + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d multi_group_of_OR_operators failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d multi_group_of_OR_operators should have errs", i) + } + } + } +} + +func TestValidate_ValidateMapCtxErrorMessage(t *testing.T) { + type args struct { + data map[string]interface{} + rules map[string]interface{} + errors map[string]interface{} + } + tests := []struct { + name string + args args + }{ + { + name: "invalid_email", + args: args{ + data: map[string]interface{}{ + "email_address": "example.", + }, + rules: map[string]interface{}{ + "email_address": "omitempty,required,email", + }, + errors: map[string]interface{}{ + "email_address": "Key: 'email_address' Error:Field validation for 'email_address' failed on the 'email' tag", + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + validate := New() + got := validate.ValidateMapCtx(context.Background(), test.args.data, test.args.rules) + for key, err := range got { + fieldErrors, ok := err.(ValidationErrors) + if !ok { + t.Errorf("failed to get underlying value of interface") + } + if test.args.errors[key] != fieldErrors[0].Error() { + t.Errorf("\nwanted: '%v' \ngot: '%v' \n", test.args.errors[key], err) + } + + } + }) + } +}