@@ -3099,3 +3099,250 @@ func TestInvalidTestValue(t *testing.T) {
30993099 require .Equal (t , "-1.0" , invalidTestValue ("number" ))
31003100 require .Equal (t , `"__invalid__"` , invalidTestValue ("object" ))
31013101}
3102+
3103+ func TestExtractValidators_ArrayValidators (t * testing.T ) {
3104+ minItems := 1
3105+ maxItems := 10
3106+
3107+ tests := []struct {
3108+ name string
3109+ metadata * ConfigMetadata
3110+ expected []Validator
3111+ }{
3112+ {
3113+ name : "minItems only" ,
3114+ metadata : & ConfigMetadata {
3115+ Type : "object" ,
3116+ Properties : map [string ]* ConfigMetadata {
3117+ "tags" : {Type : "array" , Items : & ConfigMetadata {Type : "string" }, MinItems : & minItems },
3118+ },
3119+ },
3120+ expected : []Validator {
3121+ {
3122+ FieldName : "tags" ,
3123+ FieldType : "array" ,
3124+ Rules : ValidationRules {MinItems : & minItems },
3125+ },
3126+ },
3127+ },
3128+ {
3129+ name : "maxItems only" ,
3130+ metadata : & ConfigMetadata {
3131+ Type : "object" ,
3132+ Properties : map [string ]* ConfigMetadata {
3133+ "tags" : {Type : "array" , Items : & ConfigMetadata {Type : "string" }, MaxItems : & maxItems },
3134+ },
3135+ },
3136+ expected : []Validator {
3137+ {
3138+ FieldName : "tags" ,
3139+ FieldType : "array" ,
3140+ Rules : ValidationRules {MaxItems : & maxItems },
3141+ },
3142+ },
3143+ },
3144+ {
3145+ name : "uniqueItems only" ,
3146+ metadata : & ConfigMetadata {
3147+ Type : "object" ,
3148+ Properties : map [string ]* ConfigMetadata {
3149+ "tags" : {Type : "array" , Items : & ConfigMetadata {Type : "string" }, UniqueItems : true },
3150+ },
3151+ },
3152+ expected : []Validator {
3153+ {
3154+ FieldName : "tags" ,
3155+ FieldType : "array" ,
3156+ Rules : ValidationRules {UniqueItems : true , ItemGoType : "string" },
3157+ },
3158+ },
3159+ },
3160+ {
3161+ name : "uniqueItems with integer items" ,
3162+ metadata : & ConfigMetadata {
3163+ Type : "object" ,
3164+ Properties : map [string ]* ConfigMetadata {
3165+ "ids" : {Type : "array" , Items : & ConfigMetadata {Type : "integer" }, UniqueItems : true },
3166+ },
3167+ },
3168+ expected : []Validator {
3169+ {
3170+ FieldName : "ids" ,
3171+ FieldType : "array" ,
3172+ Rules : ValidationRules {UniqueItems : true , ItemGoType : "int" },
3173+ },
3174+ },
3175+ },
3176+ {
3177+ name : "uniqueItems without items schema falls back to any" ,
3178+ metadata : & ConfigMetadata {
3179+ Type : "object" ,
3180+ Properties : map [string ]* ConfigMetadata {
3181+ "tags" : {Type : "array" , UniqueItems : true },
3182+ },
3183+ },
3184+ expected : []Validator {
3185+ {
3186+ FieldName : "tags" ,
3187+ FieldType : "array" ,
3188+ Rules : ValidationRules {UniqueItems : true },
3189+ },
3190+ },
3191+ },
3192+ {
3193+ name : "contains with enum" ,
3194+ metadata : & ConfigMetadata {
3195+ Type : "object" ,
3196+ Properties : map [string ]* ConfigMetadata {
3197+ "tags" : {
3198+ Type : "array" ,
3199+ Items : & ConfigMetadata {Type : "string" },
3200+ Contains : & ConfigMetadata {Type : "string" , Enum : []any {"production" , "staging" }},
3201+ },
3202+ },
3203+ },
3204+ expected : []Validator {
3205+ {
3206+ FieldName : "tags" ,
3207+ FieldType : "array" ,
3208+ Rules : ValidationRules {ContainsEnum : []any {"production" , "staging" }, ItemFieldType : "string" },
3209+ },
3210+ },
3211+ },
3212+ {
3213+ name : "all array validators combined" ,
3214+ metadata : & ConfigMetadata {
3215+ Type : "object" ,
3216+ Properties : map [string ]* ConfigMetadata {
3217+ "tags" : {
3218+ Type : "array" ,
3219+ Items : & ConfigMetadata {Type : "string" },
3220+ MinItems : & minItems ,
3221+ MaxItems : & maxItems ,
3222+ UniqueItems : true ,
3223+ Contains : & ConfigMetadata {Type : "string" , Enum : []any {"production" }},
3224+ },
3225+ },
3226+ },
3227+ expected : []Validator {
3228+ {
3229+ FieldName : "tags" ,
3230+ FieldType : "array" ,
3231+ Rules : ValidationRules {
3232+ MinItems : & minItems ,
3233+ MaxItems : & maxItems ,
3234+ UniqueItems : true ,
3235+ ItemGoType : "string" ,
3236+ ContainsEnum : []any {"production" },
3237+ ItemFieldType : "string" ,
3238+ },
3239+ },
3240+ },
3241+ },
3242+ {
3243+ name : "no array validators produces no validator" ,
3244+ metadata : & ConfigMetadata {
3245+ Type : "object" ,
3246+ Properties : map [string ]* ConfigMetadata {
3247+ "tags" : {Type : "array" , Items : & ConfigMetadata {Type : "string" }},
3248+ },
3249+ },
3250+ expected : []Validator {},
3251+ },
3252+ {
3253+ name : "required combined with array validators" ,
3254+ metadata : & ConfigMetadata {
3255+ Type : "object" ,
3256+ Required : []string {"tags" },
3257+ Properties : map [string ]* ConfigMetadata {
3258+ "tags" : {Type : "array" , Items : & ConfigMetadata {Type : "string" }, MinItems : & minItems },
3259+ },
3260+ },
3261+ expected : []Validator {
3262+ {
3263+ FieldName : "tags" ,
3264+ FieldType : "array" ,
3265+ Rules : ValidationRules {Required : true , MinItems : & minItems },
3266+ },
3267+ },
3268+ },
3269+ {
3270+ name : "array validators on pointer array" ,
3271+ metadata : & ConfigMetadata {
3272+ Type : "object" ,
3273+ Properties : map [string ]* ConfigMetadata {
3274+ "targets" : {Type : "array" , Items : & ConfigMetadata {Type : "string" }, IsPointer : true , MinItems : & minItems , MaxItems : & maxItems },
3275+ },
3276+ },
3277+ expected : []Validator {
3278+ {
3279+ FieldName : "targets" ,
3280+ FieldType : "array" ,
3281+ IsPointer : true ,
3282+ Rules : ValidationRules {MinItems : & minItems , MaxItems : & maxItems },
3283+ },
3284+ },
3285+ },
3286+ {
3287+ name : "contains without enum produces no containsEnum rule" ,
3288+ metadata : & ConfigMetadata {
3289+ Type : "object" ,
3290+ Properties : map [string ]* ConfigMetadata {
3291+ "tags" : {
3292+ Type : "array" ,
3293+ Items : & ConfigMetadata {Type : "string" },
3294+ Contains : & ConfigMetadata {Type : "string" },
3295+ },
3296+ },
3297+ },
3298+ expected : []Validator {},
3299+ },
3300+ }
3301+
3302+ for _ , tt := range tests {
3303+ t .Run (tt .name , func (t * testing.T ) {
3304+ result := ExtractValidators (tt .metadata )
3305+ require .Equal (t , tt .expected , result )
3306+ })
3307+ }
3308+ }
3309+
3310+ func TestValidationRules_HasValueRule_ArrayValidators (t * testing.T ) {
3311+ tests := []struct {
3312+ name string
3313+ rules ValidationRules
3314+ expected bool
3315+ }{
3316+ {
3317+ name : "minItems" ,
3318+ rules : ValidationRules {MinItems : Ptr (1 )},
3319+ expected : true ,
3320+ },
3321+ {
3322+ name : "maxItems" ,
3323+ rules : ValidationRules {MaxItems : Ptr (10 )},
3324+ expected : true ,
3325+ },
3326+ {
3327+ name : "uniqueItems" ,
3328+ rules : ValidationRules {UniqueItems : true },
3329+ expected : true ,
3330+ },
3331+ {
3332+ name : "containsEnum" ,
3333+ rules : ValidationRules {ContainsEnum : []any {"a" }},
3334+ expected : true ,
3335+ },
3336+ {
3337+ name : "all array validators" ,
3338+ rules : ValidationRules {MinItems : Ptr (1 ), MaxItems : Ptr (10 ), UniqueItems : true , ContainsEnum : []any {"a" }},
3339+ expected : true ,
3340+ },
3341+ }
3342+
3343+ for _ , tt := range tests {
3344+ t .Run (tt .name , func (t * testing.T ) {
3345+ require .Equal (t , tt .expected , tt .rules .HasValueRule ())
3346+ })
3347+ }
3348+ }
0 commit comments