diff --git a/baked_in.go b/baked_in.go index 2a086fd..5fa0e22 100644 --- a/baked_in.go +++ b/baked_in.go @@ -84,6 +84,8 @@ var ( "gtfield": isGtField, "ltefield": isLteField, "ltfield": isLtField, + "fieldcontains": fieldContains, + "fieldexcludes": fieldExcludes, "alpha": isAlpha, "alphanum": isAlphanum, "alphaunicode": isAlphaUnicode, @@ -586,6 +588,31 @@ func contains(fl FieldLevel) bool { return strings.Contains(fl.Field().String(), fl.Param()) } +// FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value. +func fieldContains(fl FieldLevel) bool { + field := fl.Field() + + currentField, _, ok := fl.GetStructFieldOK() + + if !ok { + return false + } + + return strings.Contains(field.String(), currentField.String()) +} + +// FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value. +func fieldExcludes(fl FieldLevel) bool { + field := fl.Field() + + currentField, _, ok := fl.GetStructFieldOK() + if !ok { + return true + } + + return !strings.Contains(field.String(), currentField.String()) +} + // IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. func isNeField(fl FieldLevel) bool { diff --git a/doc.go b/doc.go index dd4fde6..64cbcdf 100644 --- a/doc.go +++ b/doc.go @@ -503,6 +503,22 @@ to the top level struct. Usage: ltecsfield=InnerStructField.Field +Field Contains Another Field + +This does the same as contains except for struct fields. It should only be used +with string types. See the behavior of reflect.Value.String() for behavior on +other types. + + Usage: containsfield=InnerStructField.Field + +Field Excludes Another Field + +This does the same as excludes except for struct fields. It should only be used +with string types. See the behavior of reflect.Value.String() for behavior on +other types. + + Usage: excludesfield=InnerStructField.Field + Unique For arrays & slices, unique will ensure that there are no duplicates. diff --git a/validator_test.go b/validator_test.go index 7213d9b..06cb617 100644 --- a/validator_test.go +++ b/validator_test.go @@ -5120,6 +5120,129 @@ func TestLtField(t *testing.T) { AssertError(t, errs, "TimeTest2.End", "TimeTest2.End", "End", "End", "ltfield") } +func TestFieldContains(t *testing.T) { + validate := New() + + type StringTest struct { + Foo string `validate:"fieldcontains=Bar"` + Bar string + } + + stringTest := &StringTest{ + Foo: "foobar", + Bar: "bar", + } + + errs := validate.Struct(stringTest) + Equal(t, errs, nil) + + stringTest = &StringTest{ + Foo: "foo", + Bar: "bar", + } + + errs = validate.Struct(stringTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "StringTest.Foo", "StringTest.Foo", "Foo", "Foo", "fieldcontains") + + errs = validate.VarWithValue("foo", "bar", "fieldcontains") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "fieldcontains") + + errs = validate.VarWithValue("bar", "foobarfoo", "fieldcontains") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "fieldcontains") + + errs = validate.VarWithValue("foobarfoo", "bar", "fieldcontains") + Equal(t, errs, nil) + + type StringTestMissingField struct { + Foo string `validate:"fieldcontains=Bar"` + } + + stringTestMissingField := &StringTestMissingField{ + Foo: "foo", + } + + errs = validate.Struct(stringTestMissingField) + NotEqual(t, errs, nil) + AssertError(t, errs, "StringTestMissingField.Foo", "StringTestMissingField.Foo", "Foo", "Foo", "fieldcontains") +} + +func TestFieldExcludes(t *testing.T) { + validate := New() + + type StringTest struct { + Foo string `validate:"fieldexcludes=Bar"` + Bar string + } + + stringTest := &StringTest{ + Foo: "foobar", + Bar: "bar", + } + + errs := validate.Struct(stringTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "StringTest.Foo", "StringTest.Foo", "Foo", "Foo", "fieldexcludes") + + stringTest = &StringTest{ + Foo: "foo", + Bar: "bar", + } + + errs = validate.Struct(stringTest) + Equal(t, errs, nil) + + errs = validate.VarWithValue("foo", "bar", "fieldexcludes") + Equal(t, errs, nil) + + errs = validate.VarWithValue("bar", "foobarfoo", "fieldexcludes") + Equal(t, errs, nil) + + errs = validate.VarWithValue("foobarfoo", "bar", "fieldexcludes") + NotEqual(t, errs, nil) + AssertError(t, errs, "", "", "", "", "fieldexcludes") + + type StringTestMissingField struct { + Foo string `validate:"fieldexcludes=Bar"` + } + + stringTestMissingField := &StringTestMissingField{ + Foo: "foo", + } + + errs = validate.Struct(stringTestMissingField) + Equal(t, errs, nil) +} + +func TestContainsAndExcludes(t *testing.T) { + validate := New() + + type ImpossibleStringTest struct { + Foo string `validate:"fieldcontains=Bar"` + Bar string `validate:"fieldexcludes=Foo"` + } + + impossibleStringTest := &ImpossibleStringTest{ + Foo: "foo", + Bar: "bar", + } + + errs := validate.Struct(impossibleStringTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "ImpossibleStringTest.Foo", "ImpossibleStringTest.Foo", "Foo", "Foo", "fieldcontains") + + impossibleStringTest = &ImpossibleStringTest{ + Foo: "bar", + Bar: "foo", + } + + errs = validate.Struct(impossibleStringTest) + NotEqual(t, errs, nil) + AssertError(t, errs, "ImpossibleStringTest.Foo", "ImpossibleStringTest.Foo", "Foo", "Foo", "fieldcontains") +} + func TestLteField(t *testing.T) { validate := New()