From 863ed56ac0e21e84cfbcb3d1c7115de65fa6d992 Mon Sep 17 00:00:00 2001 From: yongruilin Date: Wed, 18 Mar 2026 22:26:00 +0000 Subject: [PATCH] Add nil OldValue test coverage for union doc_tests Add tests for Union, DiscriminatedUnion, and ZeroOrOneOfUnion validating that nil oldObj (new map entry or newly-set pointer field during update) does not skip validation via ratcheting. --- .../tags/union/union/discriminated/simple/doc_test.go | 6 ++++++ .../tags/union/union/undiscriminated/simple/doc_test.go | 6 ++++++ .../tags/zerooroneof/zerooroneof/simple/doc_test.go | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/discriminated/simple/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/discriminated/simple/doc_test.go index bd2885ffb04..e7d41558f29 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/discriminated/simple/doc_test.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/discriminated/simple/doc_test.go @@ -41,4 +41,10 @@ func Test(t *testing.T) { // Test validation ratcheting st.Value(&Struct{D: DM2, M1: &M1{}, M2: &M2{}}).OldValue(&Struct{D: DM2, M1: &M1{}, M2: &M2{}}).ExpectValid() st.Value(&Struct{D: DM1}).OldValue(&Struct{D: DM1}).ExpectValid() + + // Test update with nil old value (simulates newly-set pointer field during update). + // Discriminated union validation should still detect mismatches even though oldObj is nil. + st.Value(&Struct{D: DM1}).OldValue(nil).ExpectMatches(field.ErrorMatcher{}.ByType().ByField().ByDetailSubstring().ByOrigin(), field.ErrorList{ + field.Invalid(field.NewPath("m1"), nil, "must be specified when"), + }.WithOrigin("union")) } diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/undiscriminated/simple/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/undiscriminated/simple/doc_test.go index f00b41b546f..3ca566be821 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/undiscriminated/simple/doc_test.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/union/union/undiscriminated/simple/doc_test.go @@ -52,4 +52,10 @@ func Test(t *testing.T) { st.Value(&Struct{}).OldValue(&Struct{}).ExpectValid() st.Value(&Struct{M1: &M1{}, M2: &M2{}}).OldValue(&Struct{M1: &M1{}, M2: &M2{}}).ExpectValid() st.Value(&Struct{M3: "a string", M2: &M2{}}).OldValue(&Struct{M3: "different string", M2: &M2{}}).ExpectValid() + + // Test update with nil old value (simulates new map entry or newly-set pointer field during update). + // Union validation should still detect the empty union even though oldObj is nil. + st.Value(&Struct{}).OldValue(nil).ExpectMatches(field.ErrorMatcher{}.ByType().ByField().ByDetailSubstring().ByOrigin(), field.ErrorList{ + field.Invalid(nil, nil, "must specify one of").WithOrigin("union"), + }) } diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/zerooroneof/zerooroneof/simple/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/zerooroneof/zerooroneof/simple/doc_test.go index 01a92457af9..6764fa06545 100644 --- a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/zerooroneof/zerooroneof/simple/doc_test.go +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/zerooroneof/zerooroneof/simple/doc_test.go @@ -51,4 +51,12 @@ func Test(t *testing.T) { st.Value(&Struct{}).OldValue(&Struct{}).ExpectValid() st.Value(&Struct{M1: &M1{}, M2: &M2{}}).OldValue(&Struct{M1: &M1{}, M2: &M2{}}).ExpectValid() st.Value(&Struct{M3: "a string", M2: &M2{}}).OldValue(&Struct{M3: "different string", M2: &M2{}}).ExpectValid() + + // Test update with nil old value (simulates new map entry added during update). + // Empty union is still valid for zeroOrOneOf, even with nil old value. + st.Value(&Struct{}).OldValue((*Struct)(nil)).ExpectValid() + // Multiple members set should still be caught even with nil old value. + st.Value(&Struct{M1: &M1{}, M2: &M2{}}).OldValue((*Struct)(nil)).ExpectMatches(field.ErrorMatcher{}.ByType().ByField().ByDetailSubstring().ByOrigin(), field.ErrorList{ + field.Invalid(nil, nil, "must specify at most one of").WithOrigin("zeroOrOneOf"), + }) }