add tests for completeness cases

This commit is contained in:
Alexander Zielenski 2024-05-31 11:16:48 -07:00
parent b34197dc14
commit fd656ad3b4
2 changed files with 212 additions and 22 deletions

View File

@ -99,7 +99,7 @@ func validateNestedValueValidationCompleteness(v *NestedValueValidation, s *Stru
}
if v.AdditionalProperties != nil && opts.AllowNestedAdditionalProperties {
allErrs = append(allErrs, validateNestedValueValidationCompleteness(v.AdditionalProperties, s.AdditionalProperties.Structural, sPath.Child("additionalProperties"), vPath.Child("additionalProperties"), opts)...)
allErrs = append(allErrs, validateNestedValueValidationCompleteness(v.AdditionalProperties, sAdditionalPropertiesSchema, sPath.Child("additionalProperties"), vPath.Child("additionalProperties"), opts)...)
}
return allErrs

View File

@ -18,6 +18,7 @@ package schema
import (
"reflect"
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -148,12 +149,89 @@ func TestValidateStructuralMetadataInvariants(t *testing.T) {
}
func TestValidateStructuralCompleteness(t *testing.T) {
sch := Structural{
AdditionalProperties: &StructuralOrBool{
Structural: &Structural{
Generic: Generic{
Type: "object",
type tct struct {
name string
schema Structural
options ValidationOptions
error string
}
testCases := []tct{
{
name: "allowed properties valuevalidation, additional properties structure",
schema: Structural{
AdditionalProperties: &StructuralOrBool{
Structural: &Structural{
Generic: Generic{
Type: "object",
},
Properties: map[string]Structural{
"bar": {
Generic: Generic{
Type: "string",
},
},
},
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Properties: map[string]NestedValueValidation{
"foo": {
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
},
options: ValidationOptions{
AllowValidationPropertiesWithAdditionalProperties: true,
},
},
{
name: "disallowed properties valuevalidation, additional properties structure",
schema: Structural{
AdditionalProperties: &StructuralOrBool{
Structural: &Structural{
Generic: Generic{
Type: "object",
},
Properties: map[string]Structural{
"bar": {
Generic: Generic{
Type: "string",
},
},
},
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Properties: map[string]NestedValueValidation{
"foo": {
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
},
error: `properties[foo]: Required value: because it is defined in allOf[0].properties[foo]`,
options: ValidationOptions{
AllowValidationPropertiesWithAdditionalProperties: false,
},
},
{
name: "disallowed additionalproperties valuevalidation, properties structure",
schema: Structural{
Properties: map[string]Structural{
"bar": {
Generic: Generic{
@ -161,33 +239,145 @@ func TestValidateStructuralCompleteness(t *testing.T) {
},
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
AdditionalProperties: &NestedValueValidation{
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
error: `additionalProperties: Required value: because it is defined in allOf[0].additionalProperties`,
options: ValidationOptions{
AllowNestedAdditionalProperties: true,
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Properties: map[string]NestedValueValidation{
"foo": {
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
{
name: "allowed property in valuevalidation, and in structure",
schema: Structural{
Properties: map[string]Structural{
"foo": {
Generic: Generic{
Type: "string",
},
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Properties: map[string]NestedValueValidation{
"foo": {
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
},
},
{
name: "disallowed property in valuevalidation, and in structure",
schema: Structural{
Properties: map[string]Structural{
"foo": {
Generic: Generic{
Type: "string",
},
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Properties: map[string]NestedValueValidation{
"notfoo": {
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
},
error: `properties[notfoo]: Required value: because it is defined in allOf[0].properties[notfoo]`,
},
{
name: "allowed items in valuevalidation, and in structure",
schema: Structural{
Generic: Generic{
Type: "array",
},
Items: &Structural{
Generic: Generic{
Type: "string",
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Items: &NestedValueValidation{
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
},
{
name: "disallowed items in valuevalidation, and not in structure",
schema: Structural{
Generic: Generic{
Type: "object",
},
Properties: map[string]Structural{
"foo": {
Generic: Generic{
Type: "string",
},
},
},
ValueValidation: &ValueValidation{
AllOf: []NestedValueValidation{
{
Items: &NestedValueValidation{
ValueValidation: ValueValidation{
MinLength: ptr.To[int64](2),
},
},
},
},
},
},
error: `items: Required value: because it is defined in allOf[0].items`,
},
}
for _, allowedPropertiesForAdditionalProperties := range []bool{false, true} {
errs := validateStructuralCompleteness(&sch, nil, ValidationOptions{
AllowValidationPropertiesWithAdditionalProperties: allowedPropertiesForAdditionalProperties,
})
if allowedPropertiesForAdditionalProperties {
if len(errs) != 0 {
t.Errorf("unexpected validation errors for: %#v", sch)
for _, tc := range testCases {
errs := validateStructuralCompleteness(&tc.schema, nil, tc.options)
if len(tc.error) == 0 && len(errs) != 0 {
t.Errorf("unexpected errors: %v", errs)
}
if len(tc.error) != 0 {
contains := false
for _, err := range errs {
if strings.Contains(err.Error(), tc.error) {
contains = true
break
}
}
if !contains {
t.Errorf("expected error: %s, got %v", tc.error, errs)
}
} else if len(errs) == 0 {
t.Errorf("expected validation errors for: %#v", sch)
}
}