-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding atLeastSumOf, atMostSumOf and equalToSumOf int64 validators (#20)
- Loading branch information
1 parent
81783a7
commit 9b4e4c0
Showing
6 changed files
with
679 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package int64validator | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/tfsdk" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag" | ||
) | ||
|
||
var _ tfsdk.AttributeValidator = atLeastSumOfValidator{} | ||
|
||
// atLeastSumOfValidator validates that an integer Attribute's value is at least the sum of one | ||
// or more integer Attributes. | ||
type atLeastSumOfValidator struct { | ||
attributesToSumPaths []*tftypes.AttributePath | ||
} | ||
|
||
// Description describes the validation in plain text formatting. | ||
func (validator atLeastSumOfValidator) Description(_ context.Context) string { | ||
var attributePaths []string | ||
for _, path := range validator.attributesToSumPaths { | ||
attributePaths = append(attributePaths, path.String()) | ||
} | ||
|
||
return fmt.Sprintf("value must be at least sum of %s", strings.Join(attributePaths, " + ")) | ||
} | ||
|
||
// MarkdownDescription describes the validation in Markdown formatting. | ||
func (validator atLeastSumOfValidator) MarkdownDescription(ctx context.Context) string { | ||
return validator.Description(ctx) | ||
} | ||
|
||
// Validate performs the validation. | ||
func (validator atLeastSumOfValidator) Validate(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) { | ||
i, ok := validateInt(ctx, request, response) | ||
|
||
if !ok { | ||
return | ||
} | ||
|
||
var sumOfAttribs int64 | ||
|
||
for _, path := range validator.attributesToSumPaths { | ||
var attribToSum types.Int64 | ||
|
||
response.Diagnostics.Append(request.Config.GetAttribute(ctx, path, &attribToSum)...) | ||
if response.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
sumOfAttribs += attribToSum.Value | ||
} | ||
|
||
if i < sumOfAttribs { | ||
|
||
response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic( | ||
request.AttributePath, | ||
validator.Description(ctx), | ||
fmt.Sprintf("%d", i), | ||
)) | ||
|
||
return | ||
} | ||
} | ||
|
||
// AtLeastSumOf returns an AttributeValidator which ensures that any configured | ||
// attribute value: | ||
// | ||
// - Is a number, which can be represented by a 64-bit integer. | ||
// - Is exclusively at least the sum of the given attributes. | ||
// | ||
// Null (unconfigured) and unknown (known after apply) values are skipped. | ||
func AtLeastSumOf(attributesToSum []*tftypes.AttributePath) tfsdk.AttributeValidator { | ||
return atLeastSumOfValidator{ | ||
attributesToSumPaths: attributesToSum, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package int64validator | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
"github.com/hashicorp/terraform-plugin-framework/tfsdk" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
) | ||
|
||
func TestAtLeastSumOfValidator(t *testing.T) { | ||
t.Parallel() | ||
|
||
type testCase struct { | ||
val attr.Value | ||
attributesToSumPaths []*tftypes.AttributePath | ||
requestConfigRaw map[string]tftypes.Value | ||
expectError bool | ||
} | ||
tests := map[string]testCase{ | ||
"not an Int64": { | ||
val: types.Bool{Value: true}, | ||
expectError: true, | ||
}, | ||
"unknown Int64": { | ||
val: types.Int64{Unknown: true}, | ||
}, | ||
"null Int64": { | ||
val: types.Int64{Null: true}, | ||
}, | ||
"valid integer as Int64 less than sum of attributes": { | ||
val: types.Int64{Value: 10}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, 15), | ||
"two": tftypes.NewValue(tftypes.Number, 15), | ||
}, | ||
expectError: true, | ||
}, | ||
"valid integer as Int64 equal to sum of attributes": { | ||
val: types.Int64{Value: 10}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, 5), | ||
"two": tftypes.NewValue(tftypes.Number, 5), | ||
}, | ||
}, | ||
"valid integer as Int64 greater than sum of attributes": { | ||
val: types.Int64{Value: 10}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, 4), | ||
"two": tftypes.NewValue(tftypes.Number, 4), | ||
}, | ||
}, | ||
"valid integer as Int64 greater than sum of attributes, when one summed attribute is null": { | ||
val: types.Int64{Value: 10}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, nil), | ||
"two": tftypes.NewValue(tftypes.Number, 9), | ||
}, | ||
}, | ||
"valid integer as Int64 does not return error when all attributes are null": { | ||
val: types.Int64{Null: true}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, nil), | ||
"two": tftypes.NewValue(tftypes.Number, nil), | ||
}, | ||
}, | ||
"valid integer as Int64 greater than sum of attributes, when one summed attribute is unknown": { | ||
val: types.Int64{Value: 10}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), | ||
"two": tftypes.NewValue(tftypes.Number, 9), | ||
}, | ||
}, | ||
"valid integer as Int64 does not return error when all attributes are unknown": { | ||
val: types.Int64{Unknown: true}, | ||
attributesToSumPaths: []*tftypes.AttributePath{ | ||
tftypes.NewAttributePath().WithAttributeName("one"), | ||
tftypes.NewAttributePath().WithAttributeName("two"), | ||
}, | ||
requestConfigRaw: map[string]tftypes.Value{ | ||
"one": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), | ||
"two": tftypes.NewValue(tftypes.Number, tftypes.UnknownValue), | ||
}, | ||
}, | ||
} | ||
|
||
for name, test := range tests { | ||
name, test := name, test | ||
t.Run(name, func(t *testing.T) { | ||
request := tfsdk.ValidateAttributeRequest{ | ||
AttributePath: tftypes.NewAttributePath().WithAttributeName("test"), | ||
AttributeConfig: test.val, | ||
Config: tfsdk.Config{ | ||
Raw: tftypes.NewValue(tftypes.Object{}, test.requestConfigRaw), | ||
Schema: tfsdk.Schema{ | ||
Attributes: map[string]tfsdk.Attribute{ | ||
"test": {Type: types.Int64Type}, | ||
"one": {Type: types.Int64Type}, | ||
"two": {Type: types.Int64Type}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
response := tfsdk.ValidateAttributeResponse{} | ||
|
||
AtLeastSumOf(test.attributesToSumPaths).Validate(context.Background(), request, &response) | ||
|
||
if !response.Diagnostics.HasError() && test.expectError { | ||
t.Fatal("expected error, got no error") | ||
} | ||
|
||
if response.Diagnostics.HasError() && !test.expectError { | ||
t.Fatalf("got unexpected error: %s", response.Diagnostics) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package int64validator | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/tfsdk" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag" | ||
) | ||
|
||
var _ tfsdk.AttributeValidator = atMostSumOfValidator{} | ||
|
||
// atMostSumOfValidator validates that an integer Attribute's value is at most the sum of one | ||
// or more integer Attributes. | ||
type atMostSumOfValidator struct { | ||
attributesToSumPaths []*tftypes.AttributePath | ||
} | ||
|
||
// Description describes the validation in plain text formatting. | ||
func (validator atMostSumOfValidator) Description(_ context.Context) string { | ||
var attributePaths []string | ||
for _, path := range validator.attributesToSumPaths { | ||
attributePaths = append(attributePaths, path.String()) | ||
} | ||
|
||
return fmt.Sprintf("value must be at most sum of %s", strings.Join(attributePaths, " + ")) | ||
} | ||
|
||
// MarkdownDescription describes the validation in Markdown formatting. | ||
func (validator atMostSumOfValidator) MarkdownDescription(ctx context.Context) string { | ||
return validator.Description(ctx) | ||
} | ||
|
||
// Validate performs the validation. | ||
func (validator atMostSumOfValidator) Validate(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) { | ||
i, ok := validateInt(ctx, request, response) | ||
|
||
if !ok { | ||
return | ||
} | ||
|
||
var sumOfAttribs int64 | ||
|
||
for _, path := range validator.attributesToSumPaths { | ||
var attribToSum types.Int64 | ||
|
||
response.Diagnostics.Append(request.Config.GetAttribute(ctx, path, &attribToSum)...) | ||
if response.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
sumOfAttribs += attribToSum.Value | ||
} | ||
|
||
if i > sumOfAttribs { | ||
|
||
response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic( | ||
request.AttributePath, | ||
validator.Description(ctx), | ||
fmt.Sprintf("%d", i), | ||
)) | ||
|
||
return | ||
} | ||
} | ||
|
||
// AtMostSumOf returns an AttributeValidator which ensures that any configured | ||
// attribute value: | ||
// | ||
// - Is a number, which can be represented by a 64-bit integer. | ||
// - Is exclusively at most the sum of the given attributes. | ||
// | ||
// Null (unconfigured) and unknown (known after apply) values are skipped. | ||
func AtMostSumOf(attributesToSum []*tftypes.AttributePath) tfsdk.AttributeValidator { | ||
return atMostSumOfValidator{ | ||
attributesToSumPaths: attributesToSum, | ||
} | ||
} |
Oops, something went wrong.