Skip to content

Commit a772159

Browse files
authored
Introduce int64validator package (#21)
Reference: #2
1 parent b852afe commit a772159

File tree

7 files changed

+423
-0
lines changed

7 files changed

+423
-0
lines changed

.changelog/21.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:feature
2+
Introduced `int64validator` package with `AtLeast()`, `AtMost()`, and `Between()` validation functions
3+
```

int64validator/at_least.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package validate
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag"
8+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
9+
)
10+
11+
var _ tfsdk.AttributeValidator = atLeastValidator{}
12+
13+
// atLeastValidator validates that an integer Attribute's value is at least a certain value.
14+
type atLeastValidator struct {
15+
min int64
16+
}
17+
18+
// Description describes the validation in plain text formatting.
19+
func (validator atLeastValidator) Description(_ context.Context) string {
20+
return fmt.Sprintf("value must be at least %d", validator.min)
21+
}
22+
23+
// MarkdownDescription describes the validation in Markdown formatting.
24+
func (validator atLeastValidator) MarkdownDescription(ctx context.Context) string {
25+
return validator.Description(ctx)
26+
}
27+
28+
// Validate performs the validation.
29+
func (validator atLeastValidator) Validate(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) {
30+
i, ok := validateInt(ctx, request, response)
31+
32+
if !ok {
33+
return
34+
}
35+
36+
if i < validator.min {
37+
response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic(
38+
request.AttributePath,
39+
validator.Description(ctx),
40+
fmt.Sprintf("%d", i),
41+
))
42+
43+
return
44+
}
45+
}
46+
47+
// AtLeast returns an AttributeValidator which ensures that any configured
48+
// attribute value:
49+
//
50+
// - Is a number, which can be represented by a 64-bit integer.
51+
// - Is exclusively greater than the given minimum.
52+
//
53+
// Null (unconfigured) and unknown (known after apply) values are skipped.
54+
func AtLeast(min int64) tfsdk.AttributeValidator {
55+
return atLeastValidator{
56+
min: min,
57+
}
58+
}

int64validator/at_least_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package validate
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 TestAtLeastValidator(t *testing.T) {
14+
t.Parallel()
15+
16+
type testCase struct {
17+
val attr.Value
18+
min int64
19+
expectError bool
20+
}
21+
tests := map[string]testCase{
22+
"not an Int64": {
23+
val: types.Bool{Value: true},
24+
expectError: true,
25+
},
26+
"unknown Int64": {
27+
val: types.Int64{Unknown: true},
28+
min: 1,
29+
},
30+
"null Int64": {
31+
val: types.Int64{Null: true},
32+
min: 1,
33+
},
34+
"valid integer as Int64": {
35+
val: types.Int64{Value: 2},
36+
min: 1,
37+
},
38+
"valid integer as Int64 min": {
39+
val: types.Int64{Value: 1},
40+
min: 1,
41+
},
42+
"too small integer as Int64": {
43+
val: types.Int64{Value: -1},
44+
min: 1,
45+
expectError: true,
46+
},
47+
}
48+
49+
for name, test := range tests {
50+
name, test := name, test
51+
t.Run(name, func(t *testing.T) {
52+
request := tfsdk.ValidateAttributeRequest{
53+
AttributePath: tftypes.NewAttributePath().WithAttributeName("test"),
54+
AttributeConfig: test.val,
55+
}
56+
response := tfsdk.ValidateAttributeResponse{}
57+
AtLeast(test.min).Validate(context.TODO(), request, &response)
58+
59+
if !response.Diagnostics.HasError() && test.expectError {
60+
t.Fatal("expected error, got no error")
61+
}
62+
63+
if response.Diagnostics.HasError() && !test.expectError {
64+
t.Fatalf("got unexpected error: %s", response.Diagnostics)
65+
}
66+
})
67+
}
68+
}

int64validator/at_most.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package validate
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag"
8+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
)
11+
12+
var _ tfsdk.AttributeValidator = atMostValidator{}
13+
14+
// atMostValidator validates that an integer Attribute's value is at most a certain value.
15+
type atMostValidator struct {
16+
max int64
17+
}
18+
19+
// Description describes the validation in plain text formatting.
20+
func (validator atMostValidator) Description(_ context.Context) string {
21+
return fmt.Sprintf("value must be at most %d", validator.max)
22+
}
23+
24+
// MarkdownDescription describes the validation in Markdown formatting.
25+
func (validator atMostValidator) MarkdownDescription(ctx context.Context) string {
26+
return validator.Description(ctx)
27+
}
28+
29+
// Validate performs the validation.
30+
func (validator atMostValidator) Validate(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) {
31+
i, ok := validateInt(ctx, request, response)
32+
33+
if !ok {
34+
return
35+
}
36+
37+
if i > validator.max {
38+
response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic(
39+
request.AttributePath,
40+
validator.Description(ctx),
41+
fmt.Sprintf("%d", i),
42+
))
43+
44+
return
45+
}
46+
}
47+
48+
// AtMost returns an AttributeValidator which ensures that any configured
49+
// attribute value:
50+
//
51+
// - Is a number, which can be represented by a 64-bit integer.
52+
// - Is exclusively less than the given maximum.
53+
//
54+
// Null (unconfigured) and unknown (known after apply) values are skipped.
55+
func AtMost(max int64) tfsdk.AttributeValidator {
56+
return atMostValidator{
57+
max: max,
58+
}
59+
}
60+
61+
// validateInt ensures that the request contains an Int64 value.
62+
func validateInt(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) (int64, bool) {
63+
var n types.Int64
64+
65+
diags := tfsdk.ValueAs(ctx, request.AttributeConfig, &n)
66+
67+
if diags.HasError() {
68+
response.Diagnostics = append(response.Diagnostics, diags...)
69+
70+
return 0, false
71+
}
72+
73+
if n.Unknown || n.Null {
74+
return 0, false
75+
}
76+
77+
return n.Value, true
78+
}

int64validator/at_most_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package validate
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 TestAtMostValidator(t *testing.T) {
14+
t.Parallel()
15+
16+
type testCase struct {
17+
val attr.Value
18+
max int64
19+
expectError bool
20+
}
21+
tests := map[string]testCase{
22+
"not an Int64": {
23+
val: types.Bool{Value: true},
24+
expectError: true,
25+
},
26+
"unknown Int64": {
27+
val: types.Int64{Unknown: true},
28+
max: 2,
29+
},
30+
"null Int64": {
31+
val: types.Int64{Null: true},
32+
max: 2,
33+
},
34+
"valid integer as Int64": {
35+
val: types.Int64{Value: 1},
36+
max: 2,
37+
},
38+
"valid integer as Int64 min": {
39+
val: types.Int64{Value: 2},
40+
max: 2,
41+
},
42+
"too large integer as Int64": {
43+
val: types.Int64{Value: 4},
44+
max: 2,
45+
expectError: true,
46+
},
47+
}
48+
49+
for name, test := range tests {
50+
name, test := name, test
51+
t.Run(name, func(t *testing.T) {
52+
request := tfsdk.ValidateAttributeRequest{
53+
AttributePath: tftypes.NewAttributePath().WithAttributeName("test"),
54+
AttributeConfig: test.val,
55+
}
56+
response := tfsdk.ValidateAttributeResponse{}
57+
AtMost(test.max).Validate(context.TODO(), request, &response)
58+
59+
if !response.Diagnostics.HasError() && test.expectError {
60+
t.Fatal("expected error, got no error")
61+
}
62+
63+
if response.Diagnostics.HasError() && !test.expectError {
64+
t.Fatalf("got unexpected error: %s", response.Diagnostics)
65+
}
66+
})
67+
}
68+
}

int64validator/between.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package validate
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework-validators/validatordiag"
8+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
9+
)
10+
11+
var _ tfsdk.AttributeValidator = betweenValidator{}
12+
13+
// betweenValidator validates that an integer Attribute's value is in a range.
14+
type betweenValidator struct {
15+
min, max int64
16+
}
17+
18+
// Description describes the validation in plain text formatting.
19+
func (validator betweenValidator) Description(_ context.Context) string {
20+
return fmt.Sprintf("value must be between %d and %d", validator.min, validator.max)
21+
}
22+
23+
// MarkdownDescription describes the validation in Markdown formatting.
24+
func (validator betweenValidator) MarkdownDescription(ctx context.Context) string {
25+
return validator.Description(ctx)
26+
}
27+
28+
// Validate performs the validation.
29+
func (validator betweenValidator) Validate(ctx context.Context, request tfsdk.ValidateAttributeRequest, response *tfsdk.ValidateAttributeResponse) {
30+
i, ok := validateInt(ctx, request, response)
31+
32+
if !ok {
33+
return
34+
}
35+
36+
if i < validator.min || i > validator.max {
37+
response.Diagnostics.Append(validatordiag.AttributeValueDiagnostic(
38+
request.AttributePath,
39+
validator.Description(ctx),
40+
fmt.Sprintf("%d", i),
41+
))
42+
43+
return
44+
}
45+
}
46+
47+
// Between returns an AttributeValidator which ensures that any configured
48+
// attribute value:
49+
//
50+
// - Is a number, which can be represented by a 64-bit integer.
51+
// - Is exclusively greater than the given minimum and less than the given maximum.
52+
//
53+
// Null (unconfigured) and unknown (known after apply) values are skipped.
54+
func Between(min, max int64) tfsdk.AttributeValidator {
55+
if min > max {
56+
return nil
57+
}
58+
59+
return betweenValidator{
60+
min: min,
61+
max: max,
62+
}
63+
}

0 commit comments

Comments
 (0)