Skip to content

Commit 8c61605

Browse files
ewbankkitappilon
authored andcommitted
Convert 'MapKeyMatch' and 'MapValueMatch' to use diag.Diagnostics.
1 parent 772099c commit 8c61605

File tree

2 files changed

+90
-64
lines changed

2 files changed

+90
-64
lines changed

helper/validation/map.go

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -68,64 +68,75 @@ func MapValueLenBetween(min, max int) schema.SchemaValidateDiagFunc {
6868
}
6969
}
7070

71-
// MapKeyMatch returns a SchemaValidateFunc which tests if the provided value
71+
// MapKeyMatch returns a SchemaValidateDiagFunc which tests if the provided value
7272
// is of type map and all keys match a given regexp. Optionally an error message
7373
// can be provided to return something friendlier than "expected to match some globby regexp".
74-
func MapKeyMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc {
75-
return func(i interface{}, k string) (warnings []string, errors []error) {
76-
v, ok := i.(map[string]interface{})
77-
if !ok {
78-
errors = append(errors, fmt.Errorf("expected type of %[1]q to be Map, got %[1]T", k))
79-
return warnings, errors
80-
}
74+
func MapKeyMatch(r *regexp.Regexp, message string) schema.SchemaValidateDiagFunc {
75+
return func(v interface{}, path cty.Path) diag.Diagnostics {
76+
var diags diag.Diagnostics
8177

82-
for key := range v {
78+
for _, key := range sortedKeys(v.(map[string]interface{})) {
8379
if ok := r.MatchString(key); !ok {
84-
if message != "" {
85-
errors = append(errors, fmt.Errorf("invalid key %q for %q (%s)", key, k, message))
86-
return warnings, errors
80+
var detail string
81+
if message == "" {
82+
detail = fmt.Sprintf("Map key expected to match regular expression %q: %s", r, key)
83+
} else {
84+
detail = fmt.Sprintf("%s: %s", message, key)
8785
}
8886

89-
errors = append(errors, fmt.Errorf("invalid key %q for %q (expected to match regular expression %q)", key, k, r))
90-
return warnings, errors
87+
diags = append(diags, diag.Diagnostic{
88+
Severity: diag.Error,
89+
Summary: "Invalid map key",
90+
Detail: detail,
91+
AttributePath: append(path, cty.IndexStep{Key: cty.StringVal(key)}),
92+
})
9193
}
9294
}
9395

94-
return warnings, errors
96+
return diags
9597
}
9698
}
9799

98-
// MapValueMatch returns a SchemaValidateFunc which tests if the provided value
100+
// MapValueMatch returns a SchemaValidateDiagFunc which tests if the provided value
99101
// is of type map and all values match a given regexp. Optionally an error message
100102
// can be provided to return something friendlier than "expected to match some globby regexp".
101-
func MapValueMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc {
102-
return func(i interface{}, k string) (warnings []string, errors []error) {
103-
v, ok := i.(map[string]interface{})
104-
if !ok {
105-
errors = append(errors, fmt.Errorf("expected type of %[1]q to be Map, got %[1]T", k))
106-
return warnings, errors
107-
}
103+
func MapValueMatch(r *regexp.Regexp, message string) schema.SchemaValidateDiagFunc {
104+
return func(v interface{}, path cty.Path) diag.Diagnostics {
105+
var diags diag.Diagnostics
106+
107+
m := v.(map[string]interface{})
108+
109+
for _, key := range sortedKeys(m) {
110+
val := m[key]
108111

109-
for _, val := range v {
110112
if _, ok := val.(string); !ok {
111-
errors = append(errors, fmt.Errorf("expected all values of %[1]q to be strings, found %[2]v (type = %[2]T)", k, val))
112-
return warnings, errors
113+
diags = append(diags, diag.Diagnostic{
114+
Severity: diag.Error,
115+
Summary: "Bad map value type",
116+
Detail: fmt.Sprintf("Map values should be strings: %s => %v (type = %T)", key, val, val),
117+
AttributePath: append(path, cty.IndexStep{Key: cty.StringVal(key)}),
118+
})
119+
continue
113120
}
114-
}
115121

116-
for _, val := range v {
117122
if ok := r.MatchString(val.(string)); !ok {
118-
if message != "" {
119-
errors = append(errors, fmt.Errorf("invalid value %q for %q (%s)", val, k, message))
120-
return warnings, errors
123+
var detail string
124+
if message == "" {
125+
detail = fmt.Sprintf("Map value expected to match regular expression %q: %s => %v", r, key, val)
126+
} else {
127+
detail = fmt.Sprintf("%s: %s => %v", message, key, val)
121128
}
122129

123-
errors = append(errors, fmt.Errorf("invalid value %q for %q (expected to match regular expression %q)", val, k, r))
124-
return warnings, errors
130+
diags = append(diags, diag.Diagnostic{
131+
Severity: diag.Error,
132+
Summary: "Invalid map value",
133+
Detail: detail,
134+
AttributePath: append(path, cty.IndexStep{Key: cty.StringVal(key)}),
135+
})
125136
}
126137
}
127138

128-
return warnings, errors
139+
return diags
129140
}
130141
}
131142

helper/validation/map_test.go

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -154,87 +154,102 @@ func TestValidationMapValueLenBetween(t *testing.T) {
154154

155155
func TestValidationMapKeyMatch(t *testing.T) {
156156
cases := map[string]struct {
157-
Value interface{}
158-
Error bool
157+
Value interface{}
158+
ExpectedDiags diag.Diagnostics
159159
}{
160-
"NotMap": {
161-
Value: "the map is a lie",
162-
Error: true,
163-
},
164160
"NoMatch": {
165161
Value: map[string]interface{}{
166162
"ABC": "123",
167163
"UVWXYZ": "123456",
168164
},
169-
Error: true,
165+
ExpectedDiags: diag.Diagnostics{
166+
{
167+
Severity: diag.Error,
168+
AttributePath: append(cty.Path{}, cty.IndexStep{Key: cty.StringVal("UVWXYZ")}),
169+
},
170+
},
170171
},
171172
"AllGood": {
172173
Value: map[string]interface{}{
173174
"AB": "12",
174175
"UVABY": "12345",
175176
},
176-
Error: false,
177+
ExpectedDiags: nil,
177178
},
178179
}
179180

180181
fn := MapKeyMatch(regexp.MustCompile(".*AB.*"), "")
181182

182183
for tn, tc := range cases {
183184
t.Run(tn, func(t *testing.T) {
184-
_, errors := fn(tc.Value, tn)
185+
diags := fn(tc.Value, cty.Path{})
185186

186-
if len(errors) > 0 && !tc.Error {
187-
t.Errorf("MapKeyMatch(%s) produced an unexpected error", tc.Value)
188-
} else if len(errors) == 0 && tc.Error {
189-
t.Errorf("MapKeyMatch(%s) did not error", tc.Value)
190-
}
187+
checkDiagnostics(t, tn, diags, tc.ExpectedDiags)
191188
})
192189
}
193190
}
194191

195192
func TestValidationValueKeyMatch(t *testing.T) {
196193
cases := map[string]struct {
197-
Value interface{}
198-
Error bool
194+
Value interface{}
195+
ExpectedDiags diag.Diagnostics
199196
}{
200-
"NotMap": {
201-
Value: "the map is a lie",
202-
Error: true,
203-
},
204197
"NotStringValue": {
205198
Value: map[string]interface{}{
206-
"MNO": "123",
199+
"MNO": "ABC",
207200
"UVWXYZ": 123456,
208201
},
209-
Error: true,
202+
ExpectedDiags: diag.Diagnostics{
203+
{
204+
Severity: diag.Error,
205+
AttributePath: append(cty.Path{}, cty.IndexStep{Key: cty.StringVal("UVWXYZ")}),
206+
},
207+
},
210208
},
211209
"NoMatch": {
212210
Value: map[string]interface{}{
213211
"MNO": "ABC",
214212
"UVWXYZ": "UVWXYZ",
215213
},
216-
Error: true,
214+
ExpectedDiags: diag.Diagnostics{
215+
{
216+
Severity: diag.Error,
217+
AttributePath: append(cty.Path{}, cty.IndexStep{Key: cty.StringVal("UVWXYZ")}),
218+
},
219+
},
220+
},
221+
"BothBad": {
222+
Value: map[string]interface{}{
223+
"MNO": "123",
224+
"UVWXYZ": 123456,
225+
},
226+
ExpectedDiags: diag.Diagnostics{
227+
{
228+
Severity: diag.Error,
229+
AttributePath: append(cty.Path{}, cty.IndexStep{Key: cty.StringVal("MNO")}),
230+
},
231+
{
232+
Severity: diag.Error,
233+
AttributePath: append(cty.Path{}, cty.IndexStep{Key: cty.StringVal("UVWXYZ")}),
234+
},
235+
},
217236
},
218237
"AllGood": {
219238
Value: map[string]interface{}{
220239
"MNO": "ABC",
221240
"UVWXYZ": "UVABY",
222241
},
223-
Error: false,
242+
ExpectedDiags: nil,
224243
},
225244
}
226245

227246
fn := MapValueMatch(regexp.MustCompile(".*AB.*"), "")
228247

229248
for tn, tc := range cases {
230249
t.Run(tn, func(t *testing.T) {
231-
_, errors := fn(tc.Value, tn)
250+
diags := fn(tc.Value, cty.Path{})
232251

233-
if len(errors) > 0 && !tc.Error {
234-
t.Errorf("MapValueMatch(%s) produced an unexpected error", tc.Value)
235-
} else if len(errors) == 0 && tc.Error {
236-
t.Errorf("MapValueMatch(%s) did not error", tc.Value)
237-
}
252+
checkDiagnostics(t, tn, diags, tc.ExpectedDiags)
238253
})
239254
}
240255
}

0 commit comments

Comments
 (0)