Skip to content

Commit a56e62f

Browse files
committed
Adding atLeastSumOfValidator (#20)
1 parent 7c732e8 commit a56e62f

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

int64validator/at_least_sum_of.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package int64validator
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
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+
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag"
13+
)
14+
15+
var _ tfsdk.AttributeValidator = atLeastSumOfValidator{}
16+
17+
// atLeastSumOfValidator validates that an integer Attribute's value is at least the sum of one
18+
// or more integer Attributes.
19+
type atLeastSumOfValidator struct {
20+
attributesToSumPaths []*tftypes.AttributePath
21+
}
22+
23+
// Description describes the validation in plain text formatting.
24+
func (validator atLeastSumOfValidator) Description(_ context.Context) string {
25+
var attributePaths []string
26+
for _, path := range validator.attributesToSumPaths {
27+
attributePaths = append(attributePaths, path.String())
28+
}
29+
30+
return fmt.Sprintf("value must be at least sum of %s", strings.Join(attributePaths, " + "))
31+
}
32+
33+
// MarkdownDescription describes the validation in Markdown formatting.
34+
func (validator atLeastSumOfValidator) MarkdownDescription(ctx context.Context) string {
35+
return validator.Description(ctx)
36+
}
37+
38+
// Validate performs the validation.
39+
func (validator atLeastSumOfValidator) Validate(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) {
40+
i, ok := validateInt(ctx, request, response)
41+
42+
if !ok {
43+
return
44+
}
45+
46+
var sumOfAttribs int64
47+
48+
for _, path := range validator.attributesToSumPaths {
49+
var attribToSum types.Int64
50+
51+
response.Diagnostics.Append(request.Config.GetAttribute(ctx, path, &attribToSum)...)
52+
if response.Diagnostics.HasError() {
53+
return
54+
}
55+
56+
sumOfAttribs += attribToSum.Value
57+
}
58+
59+
if i < sumOfAttribs {
60+
61+
response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic(
62+
request.AttributePath,
63+
validator.Description(ctx),
64+
fmt.Sprintf("%d", i),
65+
))
66+
67+
return
68+
}
69+
}
70+
71+
// AtLeastSumOf returns an AttributeValidator which ensures that any configured
72+
// attribute value:
73+
//
74+
// - Is a number, which can be represented by a 64-bit integer.
75+
// - Is exclusively at least the sum of the given attributes.
76+
//
77+
// Null (unconfigured) and unknown (known after apply) values are skipped.
78+
func AtLeastSumOf(attributesToSum []*tftypes.AttributePath) tfsdk.AttributeValidator {
79+
return atLeastSumOfValidator{
80+
attributesToSumPaths: attributesToSum,
81+
}
82+
}
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package int64validator
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 TestAtLeastSumOfValidator(t *testing.T) {
14+
t.Parallel()
15+
16+
type testCase struct {
17+
val attr.Value
18+
attributesToSumPaths []*tftypes.AttributePath
19+
requestConfigRaw map[string]tftypes.Value
20+
expectError bool
21+
}
22+
tests := map[string]testCase{
23+
"not an Int64": {
24+
val: types.Bool{Value: true},
25+
expectError: true,
26+
},
27+
"unknown Int64": {
28+
val: types.Int64{Unknown: true},
29+
},
30+
"null Int64": {
31+
val: types.Int64{Null: true},
32+
},
33+
"valid integer as Int64 less than sum of attributes": {
34+
val: types.Int64{Value: 10},
35+
attributesToSumPaths: []*tftypes.AttributePath{
36+
tftypes.NewAttributePath().WithAttributeName("one"),
37+
tftypes.NewAttributePath().WithAttributeName("two"),
38+
},
39+
requestConfigRaw: map[string]tftypes.Value{
40+
"one": tftypes.NewValue(tftypes.Number, 15),
41+
"two": tftypes.NewValue(tftypes.Number, 15),
42+
},
43+
expectError: true,
44+
},
45+
"valid integer as Int64 equal to sum of attributes": {
46+
val: types.Int64{Value: 10},
47+
attributesToSumPaths: []*tftypes.AttributePath{
48+
tftypes.NewAttributePath().WithAttributeName("one"),
49+
tftypes.NewAttributePath().WithAttributeName("two"),
50+
},
51+
requestConfigRaw: map[string]tftypes.Value{
52+
"one": tftypes.NewValue(tftypes.Number, 5),
53+
"two": tftypes.NewValue(tftypes.Number, 5),
54+
},
55+
},
56+
"valid integer as Int64 greater than sum of attributes": {
57+
val: types.Int64{Value: 10},
58+
attributesToSumPaths: []*tftypes.AttributePath{
59+
tftypes.NewAttributePath().WithAttributeName("one"),
60+
tftypes.NewAttributePath().WithAttributeName("two"),
61+
},
62+
requestConfigRaw: map[string]tftypes.Value{
63+
"one": tftypes.NewValue(tftypes.Number, 4),
64+
"two": tftypes.NewValue(tftypes.Number, 4),
65+
},
66+
},
67+
}
68+
69+
for name, test := range tests {
70+
name, test := name, test
71+
t.Run(name, func(t *testing.T) {
72+
request := tfsdk.ValidateAttributeRequest{
73+
AttributePath: tftypes.NewAttributePath().WithAttributeName("test"),
74+
AttributeConfig: test.val,
75+
Config: tfsdk.Config{
76+
Raw: tftypes.NewValue(tftypes.Object{}, test.requestConfigRaw),
77+
Schema: tfsdk.Schema{
78+
Attributes: map[string]tfsdk.Attribute{
79+
"test": {Type: types.Int64Type},
80+
"one": {Type: types.Int64Type},
81+
"two": {Type: types.Int64Type},
82+
},
83+
},
84+
},
85+
}
86+
87+
response := tfsdk.ValidateAttributeResponse{}
88+
89+
AtLeastSumOf(test.attributesToSumPaths).Validate(context.Background(), request, &response)
90+
91+
if !response.Diagnostics.HasError() && test.expectError {
92+
t.Fatal("expected error, got no error")
93+
}
94+
95+
if response.Diagnostics.HasError() && !test.expectError {
96+
t.Fatalf("got unexpected error: %s", response.Diagnostics)
97+
}
98+
})
99+
}
100+
}

0 commit comments

Comments
 (0)