Skip to content

feat(validation-gen): Improve validation test helpers for validation-gen #132217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ func (m ErrorMatcher) Render(e *Error) string {
}
if m.matchValue {
comma()
buf.WriteString(fmt.Sprintf("Value=%v", e.BadValue))
if s, ok := e.BadValue.(string); ok {
buf.WriteString(fmt.Sprintf("Value=%q", s))
} else {
buf.WriteString(fmt.Sprintf("Value=%v", e.BadValue))
}
}
if m.matchOrigin || m.requireOriginWhenInvalid && e.Type == ErrorTypeInvalid {
comma()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
func TestSubfieldObjectMetaValidationWithValidateFalse(t *testing.T) {
st := localSchemeBuilder.Test(t)

st.Value(&Struct{}).
// check for subfield +k8s:validateFalse validation on Struct.(other.StructType).StringField
ExpectValidateFalse("subfield Struct.(other.StructType).StringField")
st.Value(&Struct{}).ExpectValidateFalseByPath(map[string][]string{
"other.StructType.stringField": {"subfield Struct.(other.StructType).StringField"},
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (s *ValidationTestBuilder) ValidateFixtures() {
}
s.ValueFuzzed(v)
vt := &ValidationTester{ValidationTestBuilder: s, value: v}
byPath := vt.ValidateFalseArgsByPath()
byPath := vt.validateFalseArgsByPath()
got[t.String()] = byPath
}

Expand Down Expand Up @@ -311,27 +311,6 @@ func (v *ValidationTester) ExpectValid() *ValidationTester {
return v
}

// ExpectValidAt validates the value and calls t.Errorf for any validation errors at the given path.
// Returns ValidationTester to support call chaining.
func (v *ValidationTester) ExpectValidAt(fldPath *field.Path) *ValidationTester {
v.T.Helper()

v.T.Run(fmt.Sprintf("%T.%v", v.value, fldPath), func(t *testing.T) {
t.Helper()

var got field.ErrorList
for _, e := range v.validate() {
if e.Field == fldPath.String() {
got = append(got, e)
}
}
if len(got) > 0 {
t.Errorf("want no errors at %v, got: %v", fldPath, got)
}
})
return v
}

// ExpectInvalid validates the value and calls t.Errorf if want does not match the actual errors.
// Returns ValidationTester to support call chaining.
func (v *ValidationTester) ExpectInvalid(want ...*field.Error) *ValidationTester {
Expand All @@ -340,40 +319,26 @@ func (v *ValidationTester) ExpectInvalid(want ...*field.Error) *ValidationTester
return v.expectInvalid(byFullError, want...)
}

// ExpectValidateFalse validates the value and calls t.Errorf if the actual errors do not
// match the given validateFalseArgs. For example, if the value to validate has a
// single `+validateFalse="type T1"` tag, ExpectValidateFalse("type T1") will pass.
// Returns ValidationTester to support call chaining.
func (v *ValidationTester) ExpectValidateFalse(validateFalseArgs ...string) *ValidationTester {
v.T.Helper()

var want []*field.Error
for _, s := range validateFalseArgs {
want = append(want, field.Invalid(nil, "", fmt.Sprintf("forced failure: %s", s)))
}
return v.expectInvalid(byDetail, want...)
}

func (v *ValidationTester) ExpectValidateFalseByPath(validateFalseArgsByPath map[string][]string) *ValidationTester {
func (v *ValidationTester) ExpectValidateFalseByPath(expectedByPath map[string][]string) *ValidationTester {
v.T.Helper()

v.T.Run(fmt.Sprintf("%T", v.value), func(t *testing.T) {
t.Helper()

byPath := v.ValidateFalseArgsByPath()
actualByPath := v.validateFalseArgsByPath()
// ensure args are sorted
for _, args := range validateFalseArgsByPath {
for _, args := range expectedByPath {
sort.Strings(args)
}
if !cmp.Equal(validateFalseArgsByPath, byPath) {
t.Errorf("validateFalse args, grouped by field path, differed from expected:\n%s\n", cmp.Diff(validateFalseArgsByPath, byPath, cmpopts.SortMaps(stdcmp.Less[string])))
if !cmp.Equal(expectedByPath, actualByPath) {
t.Errorf("validateFalse args, grouped by field path, differed from expected:\n%s\n", cmp.Diff(expectedByPath, actualByPath, cmpopts.SortMaps(stdcmp.Less[string])))
}

})
return v
}

func (v *ValidationTester) ValidateFalseArgsByPath() map[string][]string {
func (v *ValidationTester) validateFalseArgsByPath() map[string][]string {
byPath := map[string][]string{}
errs := v.validate()
for _, e := range errs {
Expand Down Expand Up @@ -452,6 +417,17 @@ func (v *ValidationTester) ExpectRegexpsByPath(regexpStringsByPath map[string][]
return v
}

func (v *ValidationTester) ExpectMatches(matcher field.ErrorMatcher, expected field.ErrorList) *ValidationTester {
v.Helper()

v.Run(fmt.Sprintf("%T", v.value), func(t *testing.T) {
t.Helper()
actual := v.validate()
matcher.Test(t, expected, actual)
})
return v
}

func (v *ValidationTester) getErrorsByPath() map[string][]string {
byPath := map[string][]string{}
errs := v.validate()
Expand Down Expand Up @@ -526,10 +502,6 @@ func (v *ValidationTester) expectInvalid(matcher matcher, errs ...*field.Error)

type matcher func(err *field.Error) string

func byDetail(err *field.Error) string {
return err.Detail
}

func byFullError(err *field.Error) string {
return err.Error()
}
Expand Down