@@ -16,14 +16,15 @@ package validators
1616import (
1717 "hpc-toolkit/pkg/config"
1818 "hpc-toolkit/pkg/modulereader"
19+ "strings"
1920 "testing"
2021
2122 "github.com/zclconf/go-cty/cty"
2223)
2324
2425func TestRegexValidator (t * testing.T ) {
25- // Fake blueprint for testing
26- bp := config.Blueprint {
26+ // Base fake blueprint/module used by subtests
27+ baseBP := config.Blueprint {
2728 BlueprintName : "test-bp" ,
2829 Groups : []config.Group {
2930 {
@@ -41,24 +42,140 @@ func TestRegexValidator(t *testing.T) {
4142 },
4243 }
4344
44- // Validation rule from metadata.yaml
45- rule := modulereader.ValidationRule {
46- Validator : "regex" ,
47- ErrorMessage : "'name' must be lowercase and start with a letter." ,
48- Inputs : map [string ]interface {}{
49- "vars" : []interface {}{"name" },
50- "pattern" : "^[a-z]([-a-z0-9]*[a-z0-9])?$" ,
51- },
52- }
53-
5445 validator := RegexValidator {}
55- err := validator .Validate (bp , bp .Groups [0 ].Modules [0 ], rule , bp .Groups [0 ], 0 )
56- if err == nil {
57- t .Errorf ("Expected validation error, but got nil" )
58- }
5946
60- expectedError := "deployment_groups[0].modules[0].settings.name: 'name' must be lowercase and start with a letter."
61- if err .Error () != expectedError {
62- t .Errorf ("Expected error message '%s', but got '%s'" , expectedError , err .Error ())
63- }
47+ t .Run ("fails_on_invalid_name" , func (t * testing.T ) {
48+ // rule targeting module.setting "name"
49+ rule := modulereader.ValidationRule {
50+ Validator : "regex" ,
51+ ErrorMessage : "'name' must be lowercase and start with a letter." ,
52+ Inputs : map [string ]interface {}{
53+ "vars" : []interface {}{"name" },
54+ "pattern" : "^[a-z]([-a-z0-9]*[a-z0-9])?$" ,
55+ },
56+ }
57+
58+ err := validator .Validate (baseBP , baseBP .Groups [0 ].Modules [0 ], rule , baseBP .Groups [0 ], 0 )
59+ if err == nil {
60+ t .Fatalf ("expected validation error, got nil" )
61+ }
62+ if ! strings .Contains (err .Error (), "must be lowercase" ) {
63+ t .Fatalf ("expected error message to contain 'must be lowercase', got: %q" , err .Error ())
64+ }
65+ })
66+
67+ t .Run ("passes_on_valid_name" , func (t * testing.T ) {
68+ // valid module.setting value
69+ bp := baseBP
70+ bp .Groups [0 ].Modules [0 ].Settings = config .NewDict (map [string ]cty.Value {
71+ "name" : cty .StringVal ("validname" ),
72+ })
73+
74+ rule := modulereader.ValidationRule {
75+ Validator : "regex" ,
76+ ErrorMessage : "'name' must be lowercase and start with a letter." ,
77+ Inputs : map [string ]interface {}{
78+ "vars" : []interface {}{"name" },
79+ "pattern" : "^[a-z]([-a-z0-9]*[a-z0-9])?$" ,
80+ },
81+ }
82+
83+ if err := validator .Validate (bp , bp .Groups [0 ].Modules [0 ], rule , bp .Groups [0 ], 0 ); err != nil {
84+ t .Fatalf ("unexpected validation error: %v" , err )
85+ }
86+ })
87+
88+ t .Run ("blueprint_scope_validates_bp_var" , func (t * testing.T ) {
89+ // blueprint-scoped rule should validate bp.Vars
90+ bp := baseBP
91+ bp .Vars = config .NewDict (map [string ]cty.Value {
92+ "global_name" : cty .StringVal ("Invalid-Name" ),
93+ })
94+
95+ rule := modulereader.ValidationRule {
96+ Validator : "regex" ,
97+ ErrorMessage : "'global_name' must be lowercase and start with a letter." ,
98+ Inputs : map [string ]interface {}{
99+ "vars" : []interface {}{"global_name" },
100+ "pattern" : "^[a-z]([-a-z0-9]*[a-z0-9])?$" ,
101+ "scope" : "blueprint" ,
102+ },
103+ }
104+
105+ err := validator .Validate (bp , bp .Groups [0 ].Modules [0 ], rule , bp .Groups [0 ], 0 )
106+ if err == nil {
107+ t .Fatalf ("expected blueprint-level validation error, got nil" )
108+ }
109+ if ! strings .Contains (err .Error (), "must be lowercase" ) {
110+ t .Fatalf ("expected blueprint error to contain message, got: %q" , err .Error ())
111+ }
112+ })
113+
114+ t .Run ("skips_inherited_by_default_and_enforce_inherited" , func (t * testing.T ) {
115+ // when module.setting equals blueprint var (inherited), default behavior should skip validation
116+ bp := baseBP
117+ // set blueprint var and module setting to the same INVALID value
118+ bp .Vars = config .NewDict (map [string ]cty.Value {
119+ "name" : cty .StringVal ("Invalid-Name" ),
120+ })
121+ bp .Groups [0 ].Modules [0 ].Settings = config .NewDict (map [string ]cty.Value {
122+ "name" : cty .StringVal ("Invalid-Name" ),
123+ })
124+
125+ // rule without enforce_inherited should skip (no error)
126+ ruleSkip := modulereader.ValidationRule {
127+ Validator : "regex" ,
128+ ErrorMessage : "'name' must be lowercase and start with a letter." ,
129+ Inputs : map [string ]interface {}{
130+ "vars" : []interface {}{"name" },
131+ "pattern" : "^[a-z]([-a-z0-9]*[a-z0-9])?$" ,
132+ },
133+ }
134+ if err := validator .Validate (bp , bp .Groups [0 ].Modules [0 ], ruleSkip , bp .Groups [0 ], 0 ); err != nil {
135+ t .Fatalf ("expected no error when inherited and enforce_inherited absent, got: %v" , err )
136+ }
137+
138+ // rule with enforce_inherited should force validation and return error
139+ ruleEnforce := modulereader.ValidationRule {
140+ Validator : "regex" ,
141+ ErrorMessage : "'name' must be lowercase and start with a letter." ,
142+ Inputs : map [string ]interface {}{
143+ "vars" : []interface {}{"name" },
144+ "pattern" : "^[a-z]([-a-z0-9]*[a-z0-9])?$" ,
145+ "enforce_inherited" : true ,
146+ },
147+ }
148+ err := validator .Validate (bp , bp .Groups [0 ].Modules [0 ], ruleEnforce , bp .Groups [0 ], 0 )
149+ if err == nil {
150+ t .Fatalf ("expected error when enforce_inherited is true, got nil" )
151+ }
152+ })
153+
154+ t .Run ("list_values_are_validated_elementwise" , func (t * testing.T ) {
155+ // module.setting is a list; validator should validate each element
156+ bp := baseBP
157+ bp .Groups [0 ].Modules [0 ].Settings = config .NewDict (map [string ]cty.Value {
158+ "tags" : cty .ListVal ([]cty.Value {
159+ cty .StringVal ("good" ),
160+ cty .StringVal ("BadTag" ),
161+ }),
162+ })
163+
164+ rule := modulereader.ValidationRule {
165+ Validator : "regex" ,
166+ ErrorMessage : "'tags' must be lowercase-only." ,
167+ Inputs : map [string ]interface {}{
168+ "vars" : []interface {}{"tags" },
169+ "pattern" : "^[a-z]+$" ,
170+ },
171+ }
172+
173+ err := validator .Validate (bp , bp .Groups [0 ].Modules [0 ], rule , bp .Groups [0 ], 0 )
174+ if err == nil {
175+ t .Fatalf ("expected validation error for list containing invalid element, got nil" )
176+ }
177+ if ! strings .Contains (err .Error (), "must be lowercase-only" ) {
178+ t .Fatalf ("unexpected error message: %q" , err .Error ())
179+ }
180+ })
64181}
0 commit comments