Skip to content

Commit 3bf8ecc

Browse files
committed
Adding Map validation for SizeBetween (#6)
1 parent 505a9bf commit 3bf8ecc

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

mapvalidator/size_between.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package mapvalidator
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
8+
9+
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag"
10+
)
11+
12+
var _ tfsdk.AttributeValidator = sizeBetweenValidator{}
13+
14+
// sizeBetweenValidator validates that map contains at least min elements
15+
// and at most max elements.
16+
type sizeBetweenValidator struct {
17+
min int
18+
max int
19+
}
20+
21+
// Description describes the validation in plain text formatting.
22+
func (v sizeBetweenValidator) Description(ctx context.Context) string {
23+
return fmt.Sprintf("map must contain at least %d elements and at most %d elements", v.min, v.max)
24+
}
25+
26+
// MarkdownDescription describes the validation in Markdown formatting.
27+
func (v sizeBetweenValidator) MarkdownDescription(ctx context.Context) string {
28+
return v.Description(ctx)
29+
}
30+
31+
// Validate performs the validation.
32+
func (v sizeBetweenValidator) Validate(ctx context.Context, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) {
33+
elems, ok := validateMap(ctx, req, resp)
34+
if !ok {
35+
return
36+
}
37+
38+
if len(elems) < v.min || len(elems) > v.max {
39+
resp.Diagnostics.Append(validatordiag.AttributeValueDiagnostic(
40+
req.AttributePath,
41+
v.Description(ctx),
42+
fmt.Sprintf("%d", len(elems)),
43+
))
44+
45+
return
46+
}
47+
}
48+
49+
func SizeBetween(min, max int) tfsdk.AttributeValidator {
50+
return sizeBetweenValidator{
51+
min: min,
52+
max: max,
53+
}
54+
}

mapvalidator/size_between_test.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package mapvalidator
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-framework/attr"
8+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
"github.com/hashicorp/terraform-plugin-go/tftypes"
11+
)
12+
13+
func TestSizeBetweenValidator(t *testing.T) {
14+
t.Parallel()
15+
16+
type testCase struct {
17+
val attr.Value
18+
min int
19+
max int
20+
expectError bool
21+
}
22+
tests := map[string]testCase{
23+
"not a Map": {
24+
val: types.Bool{Value: true},
25+
expectError: true,
26+
},
27+
"Map unknown": {
28+
val: types.Map{
29+
Unknown: true,
30+
ElemType: types.StringType,
31+
},
32+
expectError: false,
33+
},
34+
"Map null": {
35+
val: types.Map{
36+
Null: true,
37+
ElemType: types.StringType,
38+
},
39+
expectError: false,
40+
},
41+
"Map size greater than min": {
42+
val: types.Map{
43+
ElemType: types.StringType,
44+
Elems: map[string]attr.Value{
45+
"one": types.String{Value: "first"},
46+
"two": types.String{Value: "second"},
47+
},
48+
},
49+
min: 1,
50+
max: 3,
51+
expectError: false,
52+
},
53+
"Map size equal to min": {
54+
val: types.Map{
55+
ElemType: types.StringType,
56+
Elems: map[string]attr.Value{
57+
"one": types.String{Value: "first"},
58+
},
59+
},
60+
min: 1,
61+
max: 3,
62+
expectError: false,
63+
},
64+
"Map size less than max": {
65+
val: types.Map{
66+
ElemType: types.StringType,
67+
Elems: map[string]attr.Value{
68+
"one": types.String{Value: "first"},
69+
"two": types.String{Value: "second"},
70+
},
71+
},
72+
min: 1,
73+
max: 3,
74+
expectError: false,
75+
},
76+
"Map size equal to max": {
77+
val: types.Map{
78+
ElemType: types.StringType,
79+
Elems: map[string]attr.Value{
80+
"one": types.String{Value: "first"},
81+
"two": types.String{Value: "second"},
82+
"three": types.String{Value: "third"},
83+
},
84+
},
85+
min: 1,
86+
max: 3,
87+
expectError: false,
88+
},
89+
"Map size less than min": {
90+
val: types.Map{
91+
ElemType: types.StringType,
92+
Elems: map[string]attr.Value{},
93+
},
94+
min: 1,
95+
max: 3,
96+
expectError: true,
97+
},
98+
"Map size greater than max": {
99+
val: types.Map{
100+
ElemType: types.StringType,
101+
Elems: map[string]attr.Value{
102+
"one": types.String{Value: "first"},
103+
"two": types.String{Value: "second"},
104+
"three": types.String{Value: "third"},
105+
"four": types.String{Value: "fourth"},
106+
},
107+
},
108+
min: 1,
109+
max: 3,
110+
expectError: true,
111+
},
112+
}
113+
114+
for name, test := range tests {
115+
name, test := name, test
116+
t.Run(name, func(t *testing.T) {
117+
request := tfsdk.ValidateAttributeRequest{
118+
AttributePath: tftypes.NewAttributePath().WithAttributeName("test"),
119+
AttributeConfig: test.val,
120+
}
121+
response := tfsdk.ValidateAttributeResponse{}
122+
SizeBetween(test.min, test.max).Validate(context.TODO(), request, &response)
123+
124+
if !response.Diagnostics.HasError() && test.expectError {
125+
t.Fatal("expected error, got no error")
126+
}
127+
128+
if response.Diagnostics.HasError() && !test.expectError {
129+
t.Fatalf("got unexpected error: %s", response.Diagnostics)
130+
}
131+
})
132+
}
133+
}

0 commit comments

Comments
 (0)