From e8536c01910f46fd7309cb4381c221d3d73efda9 Mon Sep 17 00:00:00 2001 From: Aaron Prindle Date: Wed, 16 Jul 2025 22:01:04 +0000 Subject: [PATCH] add item + union and item + zeroroneof output tests --- .../tags/item/union/simple/doc.go | 40 ++++++++ .../tags/item/union/simple/doc_test.go | 64 +++++++++++++ .../union/simple/zz_generated.validations.go | 82 ++++++++++++++++ .../tags/item/union/typedef/doc.go | 42 +++++++++ .../tags/item/union/typedef/doc_test.go | 65 +++++++++++++ .../union/typedef/zz_generated.validations.go | 93 +++++++++++++++++++ .../tags/item/zerorooneof/simple/doc.go | 40 ++++++++ .../tags/item/zerorooneof/simple/doc_test.go | 59 ++++++++++++ .../simple/zz_generated.validations.go | 82 ++++++++++++++++ .../tags/item/zerorooneof/typedef/doc.go | 42 +++++++++ .../tags/item/zerorooneof/typedef/doc_test.go | 61 ++++++++++++ .../typedef/zz_generated.validations.go | 93 +++++++++++++++++++ 12 files changed, 763 insertions(+) create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc_test.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/zz_generated.validations.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc_test.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/zz_generated.validations.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc_test.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/zz_generated.validations.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc_test.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/zz_generated.validations.go diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc.go new file mode 100644 index 00000000000..efc0e477112 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc.go @@ -0,0 +1,40 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:validation-gen=TypeMeta +// +k8s:validation-gen-scheme-registry=k8s.io/code-generator/cmd/validation-gen/testscheme.Scheme + +// This is a test package. +package unionsimple + +import "k8s.io/code-generator/cmd/validation-gen/testscheme" + +var localSchemeBuilder = testscheme.New() + +type Struct struct { + TypeMeta int `json:"typeMeta"` + + // +k8s:listType=map + // +k8s:listMapKey=name + // +k8s:item(name: "succeeded")=+k8s:unionMember + // +k8s:item(name: "failed")=+k8s:unionMember + Tasks []Task `json:"tasks"` +} + +type Task struct { + Name string `json:"name"` + State string `json:"state"` +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc_test.go new file mode 100644 index 00000000000..0b527b5db53 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/doc_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unionsimple + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func Test(t *testing.T) { + st := localSchemeBuilder.Test(t) + + st.Value(&Struct{ + Tasks: []Task{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "other", State: "Other"}, + }, + }).ExpectValid() + + invalidBothSet := &Struct{ + Tasks: []Task{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "failed", State: "Failed"}, + }, + } + + st.Value(invalidBothSet).ExpectMatches( + field.ErrorMatcher{}, + field.ErrorList{ + field.Invalid(field.NewPath("tasks"), "{Tasks[{\"name\": \"failed\"}], Tasks[{\"name\": \"succeeded\"}]}", + "must specify exactly one of: `Tasks[{\"name\": \"succeeded\"}]`, `Tasks[{\"name\": \"failed\"}]`"), + }, + ) + + invalidEmpty := &Struct{ + Tasks: []Task{}, + } + st.Value(invalidEmpty).ExpectMatches( + field.ErrorMatcher{}, + field.ErrorList{ + field.Invalid(field.NewPath("tasks"), "", + "must specify one of: `Tasks[{\"name\": \"succeeded\"}]`, `Tasks[{\"name\": \"failed\"}]`"), + }, + ) + + // Test ratcheting. + st.Value(invalidEmpty).OldValue(invalidEmpty).ExpectValid() + st.Value(invalidBothSet).OldValue(invalidBothSet).ExpectValid() +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/zz_generated.validations.go new file mode 100644 index 00000000000..ae08269ad87 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/simple/zz_generated.validations.go @@ -0,0 +1,82 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package unionsimple + +import ( + context "context" + fmt "fmt" + + equality "k8s.io/apimachinery/pkg/api/equality" + operation "k8s.io/apimachinery/pkg/api/operation" + safe "k8s.io/apimachinery/pkg/api/safe" + validate "k8s.io/apimachinery/pkg/api/validate" + field "k8s.io/apimachinery/pkg/util/validation/field" + testscheme "k8s.io/code-generator/cmd/validation-gen/testscheme" +) + +func init() { localSchemeBuilder.Register(RegisterValidations) } + +// RegisterValidations adds validation functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterValidations(scheme *testscheme.Scheme) error { + scheme.AddValidationFunc((*Struct)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_Struct(ctx, op, nil /* fldPath */, obj.(*Struct), safe.Cast[*Struct](oldObj)) + } + return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} + }) + return nil +} + +var unionMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_union_simple_Struct_Tasks_ = validate.NewUnionMembership([2]string{"Tasks[{\"name\": \"succeeded\"}]", ""}, [2]string{"Tasks[{\"name\": \"failed\"}]", ""}) + +func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Struct) (errs field.ErrorList) { + // field Struct.TypeMeta has no validation + + // field Struct.Tasks + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []Task) (errs field.ErrorList) { + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil // no changes + } + errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a Task, b Task) bool { return a.Name == b.Name })...) + errs = append(errs, validate.Union(ctx, op, fldPath, obj, oldObj, unionMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_union_simple_Struct_Tasks_, func(list []Task) bool { + for i := range list { + if list[i].Name == "failed" { + return true + } + } + return false + }, func(list []Task) bool { + for i := range list { + if list[i].Name == "succeeded" { + return true + } + } + return false + })...) + return + }(fldPath.Child("tasks"), obj.Tasks, safe.Field(oldObj, func(oldObj *Struct) []Task { return oldObj.Tasks }))...) + + return errs +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc.go new file mode 100644 index 00000000000..2be86a48131 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc.go @@ -0,0 +1,42 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:validation-gen=TypeMeta +// +k8s:validation-gen-scheme-registry=k8s.io/code-generator/cmd/validation-gen/testscheme.Scheme + +// This is a test package. +package uniontypedef + +import "k8s.io/code-generator/cmd/validation-gen/testscheme" + +var localSchemeBuilder = testscheme.New() + +type Struct struct { + TypeMeta int `json:"typeMeta"` + + Tasks TaskList `json:"tasks"` +} + +// +k8s:listType=map +// +k8s:listMapKey=name +// +k8s:item(name: "succeeded")=+k8s:unionMember +// +k8s:item(name: "failed")=+k8s:unionMember +type TaskList []Task + +type Task struct { + Name string `json:"name"` + State string `json:"state"` +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc_test.go new file mode 100644 index 00000000000..9cde6477314 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/doc_test.go @@ -0,0 +1,65 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package uniontypedef + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func Test(t *testing.T) { + st := localSchemeBuilder.Test(t) + + st.Value(&Struct{ + Tasks: TaskList{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "other", State: "Other"}, + }, + }).ExpectValid() + + invalidBothSet := &Struct{ + Tasks: []Task{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "failed", State: "Failed"}, + }, + } + + st.Value(invalidBothSet).ExpectMatches( + field.ErrorMatcher{}, + field.ErrorList{ + field.Invalid(field.NewPath("tasks"), "{TaskList[{\"name\": \"failed\"}], TaskList[{\"name\": \"succeeded\"}]}", + "must specify exactly one of: `TaskList[{\"name\": \"succeeded\"}]`, `TaskList[{\"name\": \"failed\"}]`"), + }, + ) + + invalidEmpty := &Struct{ + Tasks: TaskList{}, + } + st.Value(invalidEmpty).ExpectMatches( + field.ErrorMatcher{}, + field.ErrorList{ + field.Invalid(field.NewPath("tasks"), "", + "must specify one of: `TaskList[{\"name\": \"succeeded\"}]`, `TaskList[{\"name\": \"failed\"}]`"), + }, + ) + + // Test ratcheting. + st.Value(invalidEmpty).OldValue(invalidEmpty).ExpectValid() + + st.Value(invalidBothSet).OldValue(invalidBothSet).ExpectValid() +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/zz_generated.validations.go new file mode 100644 index 00000000000..31d6adc4c4c --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/union/typedef/zz_generated.validations.go @@ -0,0 +1,93 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package uniontypedef + +import ( + context "context" + fmt "fmt" + + equality "k8s.io/apimachinery/pkg/api/equality" + operation "k8s.io/apimachinery/pkg/api/operation" + safe "k8s.io/apimachinery/pkg/api/safe" + validate "k8s.io/apimachinery/pkg/api/validate" + field "k8s.io/apimachinery/pkg/util/validation/field" + testscheme "k8s.io/code-generator/cmd/validation-gen/testscheme" +) + +func init() { localSchemeBuilder.Register(RegisterValidations) } + +// RegisterValidations adds validation functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterValidations(scheme *testscheme.Scheme) error { + scheme.AddValidationFunc((*Struct)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_Struct(ctx, op, nil /* fldPath */, obj.(*Struct), safe.Cast[*Struct](oldObj)) + } + return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} + }) + return nil +} + +func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Struct) (errs field.ErrorList) { + // field Struct.TypeMeta has no validation + + // field Struct.Tasks + errs = append(errs, + func(fldPath *field.Path, obj, oldObj TaskList) (errs field.ErrorList) { + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil // no changes + } + errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a Task, b Task) bool { return a.Name == b.Name })...) + errs = append(errs, Validate_TaskList(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("tasks"), obj.Tasks, safe.Field(oldObj, func(oldObj *Struct) TaskList { return oldObj.Tasks }))...) + + return errs +} + +var unionMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_union_typedef_TaskList_ = validate.NewUnionMembership([2]string{"TaskList[{\"name\": \"succeeded\"}]", ""}, [2]string{"TaskList[{\"name\": \"failed\"}]", ""}) + +func Validate_TaskList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj TaskList) (errs field.ErrorList) { + // type TaskList + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil // no changes + } + errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a Task, b Task) bool { return a.Name == b.Name })...) + errs = append(errs, validate.Union(ctx, op, fldPath, obj, oldObj, unionMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_union_typedef_TaskList_, func(list TaskList) bool { + for i := range list { + if list[i].Name == "failed" { + return true + } + } + return false + }, func(list TaskList) bool { + for i := range list { + if list[i].Name == "succeeded" { + return true + } + } + return false + })...) + + return errs +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc.go new file mode 100644 index 00000000000..f636a785f32 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc.go @@ -0,0 +1,40 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:validation-gen=TypeMeta +// +k8s:validation-gen-scheme-registry=k8s.io/code-generator/cmd/validation-gen/testscheme.Scheme + +// This is a test package. +package zeroroneofsimple + +import "k8s.io/code-generator/cmd/validation-gen/testscheme" + +var localSchemeBuilder = testscheme.New() + +type Struct struct { + TypeMeta int `json:"typeMeta"` + + // +k8s:listType=map + // +k8s:listMapKey=name + // +k8s:item(name: "succeeded")=+k8s:zeroOrOneOfMember + // +k8s:item(name: "failed")=+k8s:zeroOrOneOfMember + Tasks []Task `json:"tasks"` +} + +type Task struct { + Name string `json:"name"` + State string `json:"state"` +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc_test.go new file mode 100644 index 00000000000..a2ace70a135 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/doc_test.go @@ -0,0 +1,59 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package zeroroneofsimple + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func Test(t *testing.T) { + st := localSchemeBuilder.Test(t) + + st.Value(&Struct{ + Tasks: []Task{ + {Name: "other", State: "Other"}, + }, + }).ExpectValid() + + st.Value(&Struct{ + Tasks: []Task{ + {Name: "succeeded", State: "Succeeded"}, + }, + }).ExpectValid() + + st.Value(&Struct{ + Tasks: []Task{}, + }).ExpectValid() + + invalidBothSet := &Struct{ + Tasks: []Task{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "failed", State: "Failed"}, + }, + } + st.Value(invalidBothSet).ExpectMatches( + field.ErrorMatcher{}.ByType().ByField().ByOrigin(), + field.ErrorList{ + field.Invalid(field.NewPath("tasks"), nil, "").WithOrigin("zeroOrOneOf"), + }, + ) + + // Test ratcheting. + st.Value(invalidBothSet).OldValue(invalidBothSet).ExpectValid() +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/zz_generated.validations.go new file mode 100644 index 00000000000..a93ba1d5e9a --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/simple/zz_generated.validations.go @@ -0,0 +1,82 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package zeroroneofsimple + +import ( + context "context" + fmt "fmt" + + equality "k8s.io/apimachinery/pkg/api/equality" + operation "k8s.io/apimachinery/pkg/api/operation" + safe "k8s.io/apimachinery/pkg/api/safe" + validate "k8s.io/apimachinery/pkg/api/validate" + field "k8s.io/apimachinery/pkg/util/validation/field" + testscheme "k8s.io/code-generator/cmd/validation-gen/testscheme" +) + +func init() { localSchemeBuilder.Register(RegisterValidations) } + +// RegisterValidations adds validation functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterValidations(scheme *testscheme.Scheme) error { + scheme.AddValidationFunc((*Struct)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_Struct(ctx, op, nil /* fldPath */, obj.(*Struct), safe.Cast[*Struct](oldObj)) + } + return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} + }) + return nil +} + +var zeroOrOneOfMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_zerorooneof_simple_Struct_Tasks_ = validate.NewUnionMembership([2]string{"Tasks[{\"name\": \"succeeded\"}]", ""}, [2]string{"Tasks[{\"name\": \"failed\"}]", ""}) + +func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Struct) (errs field.ErrorList) { + // field Struct.TypeMeta has no validation + + // field Struct.Tasks + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []Task) (errs field.ErrorList) { + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil // no changes + } + errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a Task, b Task) bool { return a.Name == b.Name })...) + errs = append(errs, validate.ZeroOrOneOfUnion(ctx, op, fldPath, obj, oldObj, zeroOrOneOfMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_zerorooneof_simple_Struct_Tasks_, func(list []Task) bool { + for i := range list { + if list[i].Name == "failed" { + return true + } + } + return false + }, func(list []Task) bool { + for i := range list { + if list[i].Name == "succeeded" { + return true + } + } + return false + })...) + return + }(fldPath.Child("tasks"), obj.Tasks, safe.Field(oldObj, func(oldObj *Struct) []Task { return oldObj.Tasks }))...) + + return errs +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc.go new file mode 100644 index 00000000000..19e40b895ac --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc.go @@ -0,0 +1,42 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:validation-gen=TypeMeta +// +k8s:validation-gen-scheme-registry=k8s.io/code-generator/cmd/validation-gen/testscheme.Scheme + +// This is a test package. +package zeroroneooftypedef + +import "k8s.io/code-generator/cmd/validation-gen/testscheme" + +var localSchemeBuilder = testscheme.New() + +type Struct struct { + TypeMeta int `json:"typeMeta"` + + Tasks TaskList `json:"tasks"` +} + +// +k8s:listType=map +// +k8s:listMapKey=name +// +k8s:item(name: "succeeded")=+k8s:zeroOrOneOfMember +// +k8s:item(name: "failed")=+k8s:zeroOrOneOfMember +type TaskList []Task + +type Task struct { + Name string `json:"name"` + State string `json:"state"` +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc_test.go new file mode 100644 index 00000000000..b0b8ce0c391 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/doc_test.go @@ -0,0 +1,61 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package zeroroneooftypedef + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func Test(t *testing.T) { + st := localSchemeBuilder.Test(t) + + st.Value(&Struct{ + Tasks: TaskList{ + {Name: "other", State: "Other"}, + }, + }).ExpectValid() + + st.Value(&Struct{ + Tasks: TaskList{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "other", State: "Other"}, + }, + }).ExpectValid() + + st.Value(&Struct{ + Tasks: TaskList{}, + }).ExpectValid() + + invalidBothSet := &Struct{ + Tasks: TaskList{ + {Name: "succeeded", State: "Succeeded"}, + {Name: "failed", State: "Failed"}, + }, + } + + st.Value(invalidBothSet).ExpectMatches( + field.ErrorMatcher{}.ByType().ByField().ByOrigin(), + field.ErrorList{ + field.Invalid(field.NewPath("tasks"), nil, "").WithOrigin("zeroOrOneOf"), + }, + ) + + // Test ratcheting. + st.Value(invalidBothSet).OldValue(invalidBothSet).ExpectValid() +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/zz_generated.validations.go new file mode 100644 index 00000000000..4792c95283e --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/item/zerorooneof/typedef/zz_generated.validations.go @@ -0,0 +1,93 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package zeroroneooftypedef + +import ( + context "context" + fmt "fmt" + + equality "k8s.io/apimachinery/pkg/api/equality" + operation "k8s.io/apimachinery/pkg/api/operation" + safe "k8s.io/apimachinery/pkg/api/safe" + validate "k8s.io/apimachinery/pkg/api/validate" + field "k8s.io/apimachinery/pkg/util/validation/field" + testscheme "k8s.io/code-generator/cmd/validation-gen/testscheme" +) + +func init() { localSchemeBuilder.Register(RegisterValidations) } + +// RegisterValidations adds validation functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterValidations(scheme *testscheme.Scheme) error { + scheme.AddValidationFunc((*Struct)(nil), func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_Struct(ctx, op, nil /* fldPath */, obj.(*Struct), safe.Cast[*Struct](oldObj)) + } + return field.ErrorList{field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath()))} + }) + return nil +} + +func Validate_Struct(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *Struct) (errs field.ErrorList) { + // field Struct.TypeMeta has no validation + + // field Struct.Tasks + errs = append(errs, + func(fldPath *field.Path, obj, oldObj TaskList) (errs field.ErrorList) { + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil // no changes + } + errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a Task, b Task) bool { return a.Name == b.Name })...) + errs = append(errs, Validate_TaskList(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("tasks"), obj.Tasks, safe.Field(oldObj, func(oldObj *Struct) TaskList { return oldObj.Tasks }))...) + + return errs +} + +var zeroOrOneOfMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_zerorooneof_typedef_TaskList_ = validate.NewUnionMembership([2]string{"TaskList[{\"name\": \"succeeded\"}]", ""}, [2]string{"TaskList[{\"name\": \"failed\"}]", ""}) + +func Validate_TaskList(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj TaskList) (errs field.ErrorList) { + // type TaskList + if op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil // no changes + } + errs = append(errs, validate.Unique(ctx, op, fldPath, obj, oldObj, func(a Task, b Task) bool { return a.Name == b.Name })...) + errs = append(errs, validate.ZeroOrOneOfUnion(ctx, op, fldPath, obj, oldObj, zeroOrOneOfMembershipFor_k8s_io_code_generator_cmd_validation_gen_output_tests_tags_item_zerorooneof_typedef_TaskList_, func(list TaskList) bool { + for i := range list { + if list[i].Name == "failed" { + return true + } + } + return false + }, func(list TaskList) bool { + for i := range list { + if list[i].Name == "succeeded" { + return true + } + } + return false + })...) + + return errs +}