From d6f0260c7f23606bca3454715dfff8b3b8727a5e Mon Sep 17 00:00:00 2001 From: Lalit Chauhan Date: Wed, 18 Mar 2026 08:49:16 +0000 Subject: [PATCH] Add tests for +k8s:required and +k8s:forbidden validation tags --- .../output_tests/tags/forbidden/doc.go | 91 ++++ .../output_tests/tags/forbidden/doc_test.go | 91 ++++ .../forbidden/zz_generated.validations.go | 432 +++++++++++++++++ .../output_tests/tags/required/doc.go | 115 +++++ .../output_tests/tags/required/doc_test.go | 127 +++++ .../tags/required/zz_generated.validations.go | 452 ++++++++++++++++++ 6 files changed, 1308 insertions(+) create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc_test.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/zz_generated.validations.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc_test.go create mode 100644 staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/zz_generated.validations.go diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc.go new file mode 100644 index 00000000000..05e0b1fe1d7 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc.go @@ -0,0 +1,91 @@ +/* +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. +*/ + +// +k8s:validation-gen=TypeMeta +// +k8s:validation-gen-scheme-registry=k8s.io/code-generator/cmd/validation-gen/testscheme.Scheme + +// This is a test package. +// +k8s:validation-gen-nolint +package forbidden + +import "k8s.io/code-generator/cmd/validation-gen/testscheme" + +var localSchemeBuilder = testscheme.New() + +type Struct struct { + TypeMeta int + + // +k8s:forbidden + StringField string `json:"stringField"` + + // +k8s:forbidden + StringPtrField *string `json:"stringPtrField"` + + // +k8s:forbidden + StringTypedefField StringType `json:"stringTypedefField"` + + // +k8s:forbidden + StringTypedefPtrField *StringType `json:"stringTypedefPtrField"` + + // +k8s:forbidden + IntField int `json:"intField"` + + // +k8s:forbidden + IntPtrField *int `json:"intPtrField"` + + // +k8s:forbidden + IntTypedefField IntType `json:"intTypedefField"` + + // +k8s:forbidden + IntTypedefPtrField *IntType `json:"intTypedefPtrField"` + + // +k8s:forbidden + BoolField bool `json:"boolField"` + + // +k8s:forbidden + FloatField float64 `json:"floatField"` + + // +k8s:forbidden + ByteField byte `json:"byteField"` + + // +k8s:forbidden + OtherStructPtrField *OtherStruct `json:"otherStructPtrField"` + + // +k8s:forbidden + SliceField []string `json:"sliceField"` + + // +k8s:forbidden + SliceTypedefField SliceType `json:"sliceTypedefField"` + + // +k8s:forbidden + ByteArrayField []byte `json:"byteArrayField"` + + // +k8s:forbidden + MapField map[string]string `json:"mapField"` + + // +k8s:forbidden + MapTypedefField MapType `json:"mapTypedefField"` +} + +type StringType string + +type IntType int + +type OtherStruct struct{} + +type SliceType []string + +type MapType map[string]string diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc_test.go new file mode 100644 index 00000000000..dba35b58655 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/doc_test.go @@ -0,0 +1,91 @@ +/* +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. +*/ + +package forbidden + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/utils/ptr" +) + +func Test(t *testing.T) { + st := localSchemeBuilder.Test(t) + + st.Value(&Struct{ + // All zero-values (nil slices/maps). + }).ExpectValid() + + st.Value(&Struct{ + // Explicit zero-values and empty slices/maps. + StringField: "", + StringPtrField: nil, + StringTypedefField: "", + StringTypedefPtrField: nil, + IntField: 0, + IntPtrField: nil, + IntTypedefField: 0, + IntTypedefPtrField: nil, + BoolField: false, + FloatField: 0.0, + ByteField: 0, + OtherStructPtrField: nil, + SliceField: []string{}, + SliceTypedefField: SliceType{}, + ByteArrayField: []byte{}, + MapField: map[string]string{}, + MapTypedefField: MapType{}, + }).ExpectValid() + + st.Value(&Struct{ + StringField: "abc", + StringPtrField: ptr.To("xyz"), + StringTypedefField: StringType("abc"), + StringTypedefPtrField: ptr.To(StringType("xyz")), + IntField: 123, + IntPtrField: ptr.To(456), + IntTypedefField: IntType(123), + IntTypedefPtrField: ptr.To(IntType(456)), + BoolField: true, + FloatField: 1.23, + ByteField: 'a', + OtherStructPtrField: &OtherStruct{}, + SliceField: []string{"a", "b"}, + SliceTypedefField: SliceType([]string{"a", "b"}), + ByteArrayField: []byte("abc"), + MapField: map[string]string{"a": "b", "c": "d"}, + MapTypedefField: MapType(map[string]string{"a": "b", "c": "d"}), + }).ExpectMatches(field.ErrorMatcher{}.ByType().ByField(), field.ErrorList{ + field.Forbidden(field.NewPath("stringField"), ""), + field.Forbidden(field.NewPath("stringPtrField"), ""), + field.Forbidden(field.NewPath("stringTypedefField"), ""), + field.Forbidden(field.NewPath("stringTypedefPtrField"), ""), + field.Forbidden(field.NewPath("intField"), ""), + field.Forbidden(field.NewPath("intPtrField"), ""), + field.Forbidden(field.NewPath("intTypedefField"), ""), + field.Forbidden(field.NewPath("intTypedefPtrField"), ""), + field.Forbidden(field.NewPath("boolField"), ""), + field.Forbidden(field.NewPath("floatField"), ""), + field.Forbidden(field.NewPath("byteField"), ""), + field.Forbidden(field.NewPath("otherStructPtrField"), ""), + field.Forbidden(field.NewPath("sliceField"), ""), + field.Forbidden(field.NewPath("sliceTypedefField"), ""), + field.Forbidden(field.NewPath("byteArrayField"), ""), + field.Forbidden(field.NewPath("mapField"), ""), + field.Forbidden(field.NewPath("mapTypedefField"), ""), + }) +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/zz_generated.validations.go new file mode 100644 index 00000000000..788c54a9e25 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/forbidden/zz_generated.validations.go @@ -0,0 +1,432 @@ +//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 forbidden + +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 { + // type Struct + 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 +} + +// Validate_Struct validates an instance of Struct according +// to declarative validation rules in the API schema. +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.StringField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("stringField"), &obj.StringField, safe.Field(oldObj, func(oldObj *Struct) *string { return &oldObj.StringField }), oldObj != nil)...) + + // field Struct.StringPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("stringPtrField"), obj.StringPtrField, safe.Field(oldObj, func(oldObj *Struct) *string { return oldObj.StringPtrField }), oldObj != nil)...) + + // field Struct.StringTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *StringType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("stringTypedefField"), &obj.StringTypedefField, safe.Field(oldObj, func(oldObj *Struct) *StringType { return &oldObj.StringTypedefField }), oldObj != nil)...) + + // field Struct.StringTypedefPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *StringType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("stringTypedefPtrField"), obj.StringTypedefPtrField, safe.Field(oldObj, func(oldObj *Struct) *StringType { return oldObj.StringTypedefPtrField }), oldObj != nil)...) + + // field Struct.IntField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *int, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("intField"), &obj.IntField, safe.Field(oldObj, func(oldObj *Struct) *int { return &oldObj.IntField }), oldObj != nil)...) + + // field Struct.IntPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *int, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("intPtrField"), obj.IntPtrField, safe.Field(oldObj, func(oldObj *Struct) *int { return oldObj.IntPtrField }), oldObj != nil)...) + + // field Struct.IntTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *IntType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("intTypedefField"), &obj.IntTypedefField, safe.Field(oldObj, func(oldObj *Struct) *IntType { return &oldObj.IntTypedefField }), oldObj != nil)...) + + // field Struct.IntTypedefPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *IntType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("intTypedefPtrField"), obj.IntTypedefPtrField, safe.Field(oldObj, func(oldObj *Struct) *IntType { return oldObj.IntTypedefPtrField }), oldObj != nil)...) + + // field Struct.BoolField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *bool, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("boolField"), &obj.BoolField, safe.Field(oldObj, func(oldObj *Struct) *bool { return &oldObj.BoolField }), oldObj != nil)...) + + // field Struct.FloatField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *float64, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("floatField"), &obj.FloatField, safe.Field(oldObj, func(oldObj *Struct) *float64 { return &oldObj.FloatField }), oldObj != nil)...) + + // field Struct.ByteField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *byte, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("byteField"), &obj.ByteField, safe.Field(oldObj, func(oldObj *Struct) *byte { return &oldObj.ByteField }), oldObj != nil)...) + + // field Struct.OtherStructPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *OtherStruct, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("otherStructPtrField"), obj.OtherStructPtrField, safe.Field(oldObj, func(oldObj *Struct) *OtherStruct { return oldObj.OtherStructPtrField }), oldObj != nil)...) + + // field Struct.SliceField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("sliceField"), obj.SliceField, safe.Field(oldObj, func(oldObj *Struct) []string { return oldObj.SliceField }), oldObj != nil)...) + + // field Struct.SliceTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj SliceType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("sliceTypedefField"), obj.SliceTypedefField, safe.Field(oldObj, func(oldObj *Struct) SliceType { return oldObj.SliceTypedefField }), oldObj != nil)...) + + // field Struct.ByteArrayField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []byte, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("byteArrayField"), obj.ByteArrayField, safe.Field(oldObj, func(oldObj *Struct) []byte { return oldObj.ByteArrayField }), oldObj != nil)...) + + // field Struct.MapField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj map[string]string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenMap(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalMap(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("mapField"), obj.MapField, safe.Field(oldObj, func(oldObj *Struct) map[string]string { return oldObj.MapField }), oldObj != nil)...) + + // field Struct.MapTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj MapType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.ForbiddenMap(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalMap(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + }(fldPath.Child("mapTypedefField"), obj.MapTypedefField, safe.Field(oldObj, func(oldObj *Struct) MapType { return oldObj.MapTypedefField }), oldObj != nil)...) + + return errs +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc.go new file mode 100644 index 00000000000..5a2b1102e79 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc.go @@ -0,0 +1,115 @@ +/* +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. +*/ + +// +k8s:validation-gen=TypeMeta +// +k8s:validation-gen-scheme-registry=k8s.io/code-generator/cmd/validation-gen/testscheme.Scheme + +// This is a test package. +// +k8s:validation-gen-nolint +package required + +import "k8s.io/code-generator/cmd/validation-gen/testscheme" + +var localSchemeBuilder = testscheme.New() + +type Struct struct { + TypeMeta int + + // +k8s:required + // +k8s:validateFalse="field Struct.StringField" + StringField string `json:"stringField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.StringPtrField" + StringPtrField *string `json:"stringPtrField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.StringTypedefField" + StringTypedefField StringType `json:"stringTypedefField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.StringTypedefPtrField" + StringTypedefPtrField *StringType `json:"stringTypedefPtrField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.IntField" + IntField int `json:"intField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.IntPtrField" + IntPtrField *int `json:"intPtrField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.IntTypedefField" + IntTypedefField IntType `json:"intTypedefField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.IntTypedefPtrField" + IntTypedefPtrField *IntType `json:"intTypedefPtrField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.BoolField" + BoolField bool `json:"boolField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.FloatField" + FloatField float64 `json:"floatField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.ByteField" + ByteField byte `json:"byteField"` + + // non-pointer struct fields cannot be required or optional + + // +k8s:required + // +k8s:validateFalse="field Struct.OtherStructPtrField" + OtherStructPtrField *OtherStruct `json:"otherStructPtrField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.SliceField" + SliceField []string `json:"sliceField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.SliceTypedefField" + SliceTypedefField SliceType `json:"sliceTypedefField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.ByteArrayField" + ByteArrayField []byte `json:"byteArrayField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.MapField" + MapField map[string]string `json:"mapField"` + + // +k8s:required + // +k8s:validateFalse="field Struct.MapTypedefField" + MapTypedefField MapType `json:"mapTypedefField"` +} + +// +k8s:validateFalse="type StringType" +type StringType string + +// +k8s:validateFalse="type IntType" +type IntType int + +// +k8s:validateFalse="type OtherStruct" +type OtherStruct struct{} + +// +k8s:validateFalse="type SliceType" +type SliceType []string + +// +k8s:validateFalse="type MapType" +type MapType map[string]string diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc_test.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc_test.go new file mode 100644 index 00000000000..175a8c3fd33 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/doc_test.go @@ -0,0 +1,127 @@ +/* +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. +*/ + +package required + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/utils/ptr" +) + +func Test(t *testing.T) { + st := localSchemeBuilder.Test(t) + + st.Value(&Struct{ + // All zero-values (nil slices/maps). + }).ExpectMatches(field.ErrorMatcher{}.ByType().ByField(), field.ErrorList{ + field.Required(field.NewPath("stringField"), ""), + field.Required(field.NewPath("stringPtrField"), ""), + field.Required(field.NewPath("stringTypedefField"), ""), + field.Required(field.NewPath("stringTypedefPtrField"), ""), + field.Required(field.NewPath("intField"), ""), + field.Required(field.NewPath("intPtrField"), ""), + field.Required(field.NewPath("intTypedefField"), ""), + field.Required(field.NewPath("intTypedefPtrField"), ""), + field.Required(field.NewPath("boolField"), ""), + field.Required(field.NewPath("floatField"), ""), + field.Required(field.NewPath("byteField"), ""), + field.Required(field.NewPath("otherStructPtrField"), ""), + field.Required(field.NewPath("sliceField"), ""), + field.Required(field.NewPath("sliceTypedefField"), ""), + field.Required(field.NewPath("byteArrayField"), ""), + field.Required(field.NewPath("mapField"), ""), + field.Required(field.NewPath("mapTypedefField"), ""), + }) + + st.Value(&Struct{ + // Explicit zero-values and empty slices/maps. + StringField: "", + StringPtrField: nil, + StringTypedefField: "", + StringTypedefPtrField: nil, + IntField: 0, + IntPtrField: nil, + IntTypedefField: 0, + IntTypedefPtrField: nil, + BoolField: false, + FloatField: 0.0, + ByteField: 0, + OtherStructPtrField: nil, + SliceField: []string{}, + SliceTypedefField: SliceType{}, + ByteArrayField: []byte{}, + MapField: map[string]string{}, + MapTypedefField: MapType{}, + }).ExpectMatches(field.ErrorMatcher{}.ByType().ByField(), field.ErrorList{ + field.Required(field.NewPath("stringField"), ""), + field.Required(field.NewPath("stringPtrField"), ""), + field.Required(field.NewPath("stringTypedefField"), ""), + field.Required(field.NewPath("stringTypedefPtrField"), ""), + field.Required(field.NewPath("intField"), ""), + field.Required(field.NewPath("intPtrField"), ""), + field.Required(field.NewPath("intTypedefField"), ""), + field.Required(field.NewPath("intTypedefPtrField"), ""), + field.Required(field.NewPath("boolField"), ""), + field.Required(field.NewPath("floatField"), ""), + field.Required(field.NewPath("byteField"), ""), + field.Required(field.NewPath("otherStructPtrField"), ""), + field.Required(field.NewPath("sliceField"), ""), + field.Required(field.NewPath("sliceTypedefField"), ""), + field.Required(field.NewPath("byteArrayField"), ""), + field.Required(field.NewPath("mapField"), ""), + field.Required(field.NewPath("mapTypedefField"), ""), + }) + + st.Value(&Struct{ + StringField: "abc", + StringPtrField: ptr.To("xyz"), + StringTypedefField: StringType("abc"), + StringTypedefPtrField: ptr.To(StringType("xyz")), + IntField: 123, + IntPtrField: ptr.To(456), + IntTypedefField: IntType(123), + IntTypedefPtrField: ptr.To(IntType(456)), + BoolField: true, + FloatField: 1.23, + ByteField: 'a', + OtherStructPtrField: &OtherStruct{}, + SliceField: []string{"a", "b"}, + SliceTypedefField: SliceType([]string{"a", "b"}), + ByteArrayField: []byte("abc"), + MapField: map[string]string{"a": "b", "c": "d"}, + MapTypedefField: MapType(map[string]string{"a": "b", "c": "d"}), + }).ExpectValidateFalseByPath(map[string][]string{ + "stringField": {"field Struct.StringField"}, + "stringPtrField": {"field Struct.StringPtrField"}, + "stringTypedefField": {"field Struct.StringTypedefField", "type StringType"}, + "stringTypedefPtrField": {"field Struct.StringTypedefPtrField", "type StringType"}, + "intField": {"field Struct.IntField"}, + "intPtrField": {"field Struct.IntPtrField"}, + "intTypedefField": {"field Struct.IntTypedefField", "type IntType"}, + "intTypedefPtrField": {"field Struct.IntTypedefPtrField", "type IntType"}, + "boolField": {"field Struct.BoolField"}, + "floatField": {"field Struct.FloatField"}, + "byteField": {"field Struct.ByteField"}, + "otherStructPtrField": {"type OtherStruct", "field Struct.OtherStructPtrField"}, + "sliceField": {"field Struct.SliceField"}, + "sliceTypedefField": {"field Struct.SliceTypedefField", "type SliceType"}, + "byteArrayField": {"field Struct.ByteArrayField"}, + "mapField": {"field Struct.MapField"}, + "mapTypedefField": {"field Struct.MapTypedefField", "type MapType"}, + }) +} diff --git a/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/zz_generated.validations.go b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/zz_generated.validations.go new file mode 100644 index 00000000000..74c14382916 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/validation-gen/output_tests/tags/required/zz_generated.validations.go @@ -0,0 +1,452 @@ +//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 required + +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 { + // type Struct + 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 +} + +// Validate_IntType validates an instance of IntType according +// to declarative validation rules in the API schema. +func Validate_IntType(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *IntType) (errs field.ErrorList) { + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "type IntType")...) + + return errs +} + +// Validate_MapType validates an instance of MapType according +// to declarative validation rules in the API schema. +func Validate_MapType(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj MapType) (errs field.ErrorList) { + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "type MapType")...) + + return errs +} + +// Validate_OtherStruct validates an instance of OtherStruct according +// to declarative validation rules in the API schema. +func Validate_OtherStruct(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *OtherStruct) (errs field.ErrorList) { + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "type OtherStruct")...) + + return errs +} + +// Validate_SliceType validates an instance of SliceType according +// to declarative validation rules in the API schema. +func Validate_SliceType(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj SliceType) (errs field.ErrorList) { + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "type SliceType")...) + + return errs +} + +// Validate_StringType validates an instance of StringType according +// to declarative validation rules in the API schema. +func Validate_StringType(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *StringType) (errs field.ErrorList) { + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "type StringType")...) + + return errs +} + +// Validate_Struct validates an instance of Struct according +// to declarative validation rules in the API schema. +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.StringField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.StringField")...) + return + }(fldPath.Child("stringField"), &obj.StringField, safe.Field(oldObj, func(oldObj *Struct) *string { return &oldObj.StringField }), oldObj != nil)...) + + // field Struct.StringPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.StringPtrField")...) + return + }(fldPath.Child("stringPtrField"), obj.StringPtrField, safe.Field(oldObj, func(oldObj *Struct) *string { return oldObj.StringPtrField }), oldObj != nil)...) + + // field Struct.StringTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *StringType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.StringTypedefField")...) + // call the type's validation function + errs = append(errs, Validate_StringType(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("stringTypedefField"), &obj.StringTypedefField, safe.Field(oldObj, func(oldObj *Struct) *StringType { return &oldObj.StringTypedefField }), oldObj != nil)...) + + // field Struct.StringTypedefPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *StringType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.StringTypedefPtrField")...) + // call the type's validation function + errs = append(errs, Validate_StringType(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("stringTypedefPtrField"), obj.StringTypedefPtrField, safe.Field(oldObj, func(oldObj *Struct) *StringType { return oldObj.StringTypedefPtrField }), oldObj != nil)...) + + // field Struct.IntField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *int, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.IntField")...) + return + }(fldPath.Child("intField"), &obj.IntField, safe.Field(oldObj, func(oldObj *Struct) *int { return &oldObj.IntField }), oldObj != nil)...) + + // field Struct.IntPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *int, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.IntPtrField")...) + return + }(fldPath.Child("intPtrField"), obj.IntPtrField, safe.Field(oldObj, func(oldObj *Struct) *int { return oldObj.IntPtrField }), oldObj != nil)...) + + // field Struct.IntTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *IntType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.IntTypedefField")...) + // call the type's validation function + errs = append(errs, Validate_IntType(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("intTypedefField"), &obj.IntTypedefField, safe.Field(oldObj, func(oldObj *Struct) *IntType { return &oldObj.IntTypedefField }), oldObj != nil)...) + + // field Struct.IntTypedefPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *IntType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.IntTypedefPtrField")...) + // call the type's validation function + errs = append(errs, Validate_IntType(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("intTypedefPtrField"), obj.IntTypedefPtrField, safe.Field(oldObj, func(oldObj *Struct) *IntType { return oldObj.IntTypedefPtrField }), oldObj != nil)...) + + // field Struct.BoolField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *bool, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.BoolField")...) + return + }(fldPath.Child("boolField"), &obj.BoolField, safe.Field(oldObj, func(oldObj *Struct) *bool { return &oldObj.BoolField }), oldObj != nil)...) + + // field Struct.FloatField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *float64, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.FloatField")...) + return + }(fldPath.Child("floatField"), &obj.FloatField, safe.Field(oldObj, func(oldObj *Struct) *float64 { return &oldObj.FloatField }), oldObj != nil)...) + + // field Struct.ByteField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *byte, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.ByteField")...) + return + }(fldPath.Child("byteField"), &obj.ByteField, safe.Field(oldObj, func(oldObj *Struct) *byte { return &oldObj.ByteField }), oldObj != nil)...) + + // field Struct.OtherStructPtrField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj *OtherStruct, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.OtherStructPtrField")...) + // call the type's validation function + errs = append(errs, Validate_OtherStruct(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("otherStructPtrField"), obj.OtherStructPtrField, safe.Field(oldObj, func(oldObj *Struct) *OtherStruct { return oldObj.OtherStructPtrField }), oldObj != nil)...) + + // field Struct.SliceField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.SliceField")...) + return + }(fldPath.Child("sliceField"), obj.SliceField, safe.Field(oldObj, func(oldObj *Struct) []string { return oldObj.SliceField }), oldObj != nil)...) + + // field Struct.SliceTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj SliceType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.SliceTypedefField")...) + // call the type's validation function + errs = append(errs, Validate_SliceType(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("sliceTypedefField"), obj.SliceTypedefField, safe.Field(oldObj, func(oldObj *Struct) SliceType { return oldObj.SliceTypedefField }), oldObj != nil)...) + + // field Struct.ByteArrayField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj []byte, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredSlice(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.ByteArrayField")...) + return + }(fldPath.Child("byteArrayField"), obj.ByteArrayField, safe.Field(oldObj, func(oldObj *Struct) []byte { return oldObj.ByteArrayField }), oldObj != nil)...) + + // field Struct.MapField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj map[string]string, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredMap(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.MapField")...) + return + }(fldPath.Child("mapField"), obj.MapField, safe.Field(oldObj, func(oldObj *Struct) map[string]string { return oldObj.MapField }), oldObj != nil)...) + + // field Struct.MapTypedefField + errs = append(errs, + func(fldPath *field.Path, obj, oldObj MapType, oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredMap(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + errs = append(errs, validate.FixedResult(ctx, op, fldPath, obj, oldObj, false, "field Struct.MapTypedefField")...) + // call the type's validation function + errs = append(errs, Validate_MapType(ctx, op, fldPath, obj, oldObj)...) + return + }(fldPath.Child("mapTypedefField"), obj.MapTypedefField, safe.Field(oldObj, func(oldObj *Struct) MapType { return oldObj.MapTypedefField }), oldObj != nil)...) + + return errs +}