Skip to content

Commit

Permalink
all: Add support for Int32 and Float32 Type Validators (#222)
Browse files Browse the repository at this point in the history
* Add `float32validator` package

* Add `int32validator` package

* Add `Int32Validator` and `Float32Validator` support to `AlsoRequiresValidator`, `AtLeastOneOfValidator`, `ConflictsWithValidator`, and `ExactlyOneOfValidator`

* Add `ValueFloat32sAre` and `ValueInt32sAre` validators to `listvalidator`, `mapvalidator`, and `setvalidator` packages

* Update `terraform-plugin-framework` dependency to int32/float32 implementation branch

* Add changelog entries

* Update comments to use integer constants instead of float

Co-authored-by: Austin Valle <austinvalle@gmail.com>

* Update `int64validator` example tests to use integers instead of floats

---------

Co-authored-by: Austin Valle <austinvalle@gmail.com>
  • Loading branch information
SBGoods and austinvalle committed Jul 9, 2024
1 parent ea42e33 commit ba395d2
Show file tree
Hide file tree
Showing 109 changed files with 6,517 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20240626-174347.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: 'listvalidator: Added `ValueInt32sAre` and `ValueFloat32sAre` validators'
time: 2024-06-26T17:43:47.501066-04:00
custom:
Issue: "222"
5 changes: 5 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20240626-174411.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: 'mapvalidator: Added `ValueInt32sAre` and `ValueFloat32sAre` validators'
time: 2024-06-26T17:44:11.352117-04:00
custom:
Issue: "222"
5 changes: 5 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20240626-174423.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: 'setvalidator: Added `ValueInt32sAre` and `ValueFloat32sAre` validators'
time: 2024-06-26T17:44:23.323248-04:00
custom:
Issue: "222"
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20240626-174145.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'int32validator: New package which contains int32 type specific validators'
time: 2024-06-26T17:41:45.007609-04:00
custom:
Issue: "222"
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20240626-174220.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'float32validator: New package which contains float32 type specific validators'
time: 2024-06-26T17:42:20.2122-04:00
custom:
Issue: "222"
57 changes: 57 additions & 0 deletions float32validator/all.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-framework/schema/validator"
)

// All returns a validator which ensures that any configured attribute value
// attribute value validates against all the given validators.
//
// Use of All is only necessary when used in conjunction with Any or AnyWithAllWarnings
// as the Validators field automatically applies a logical AND.
func All(validators ...validator.Float32) validator.Float32 {
return allValidator{
validators: validators,
}
}

var _ validator.Float32 = allValidator{}

// allValidator implements the validator.
type allValidator struct {
validators []validator.Float32
}

// Description describes the validation in plain text formatting.
func (v allValidator) Description(ctx context.Context) string {
var descriptions []string

for _, subValidator := range v.validators {
descriptions = append(descriptions, subValidator.Description(ctx))
}

return fmt.Sprintf("Value must satisfy all of the validations: %s", strings.Join(descriptions, " + "))
}

// MarkdownDescription describes the validation in Markdown formatting.
func (v allValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}

// ValidateFloat32 performs the validation.
func (v allValidator) ValidateFloat32(ctx context.Context, req validator.Float32Request, resp *validator.Float32Response) {
for _, subValidator := range v.validators {
validateResp := &validator.Float32Response{}

subValidator.ValidateFloat32(ctx, req, validateResp)

resp.Diagnostics.Append(validateResp.Diagnostics...)
}
}
34 changes: 34 additions & 0 deletions float32validator/all_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator_test

import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"

"github.com/hashicorp/terraform-plugin-framework-validators/float32validator"
)

func ExampleAll() {
// Used within a Schema method of a DataSource, Provider, or Resource
_ = schema.Schema{
Attributes: map[string]schema.Attribute{
"example_attr": schema.Float32Attribute{
Required: true,
Validators: []validator.Float32{
// Validate this Float32 value must either be:
// - 1.0
// - At least 2.0, but not 3.0
float32validator.Any(
float32validator.OneOf(1.0),
float32validator.All(
float32validator.AtLeast(2.0),
float32validator.NoneOf(3.0),
),
),
},
},
},
}
}
74 changes: 74 additions & 0 deletions float32validator/all_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator_test

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"

"github.com/hashicorp/terraform-plugin-framework-validators/float32validator"
)

func TestAllValidatorValidateFloat32(t *testing.T) {
t.Parallel()

type testCase struct {
val types.Float32
validators []validator.Float32
expected diag.Diagnostics
}
tests := map[string]testCase{
"invalid": {
val: types.Float32Value(1.2),
validators: []validator.Float32{
float32validator.AtLeast(3),
float32validator.AtLeast(5),
},
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(
path.Root("test"),
"Invalid Attribute Value",
"Attribute test value must be at least 3.000000, got: 1.200000",
),
diag.NewAttributeErrorDiagnostic(
path.Root("test"),
"Invalid Attribute Value",
"Attribute test value must be at least 5.000000, got: 1.200000",
),
},
},
"valid": {
val: types.Float32Value(1.2),
validators: []validator.Float32{
float32validator.AtLeast(0),
float32validator.AtLeast(1),
},
expected: nil,
},
}

for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
t.Parallel()
request := validator.Float32Request{
Path: path.Root("test"),
PathExpression: path.MatchRoot("test"),
ConfigValue: test.val,
}
response := validator.Float32Response{}
float32validator.All(test.validators...).ValidateFloat32(context.Background(), request, &response)

if diff := cmp.Diff(response.Diagnostics, test.expected); diff != "" {
t.Errorf("unexpected diagnostics difference: %s", diff)
}
})
}
}
27 changes: 27 additions & 0 deletions float32validator/also_requires.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator

import (
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"

"github.com/hashicorp/terraform-plugin-framework-validators/internal/schemavalidator"
)

// AlsoRequires checks that a set of path.Expression has a non-null value,
// if the current attribute also has a non-null value.
//
// This implements the validation logic declaratively within the schema.
// Refer to [datasourcevalidator.RequiredTogether],
// [providervalidator.RequiredTogether], or [resourcevalidator.RequiredTogether]
// for declaring this type of validation outside the schema definition.
//
// Relative path.Expression will be resolved using the attribute being
// validated.
func AlsoRequires(expressions ...path.Expression) validator.Float32 {
return schemavalidator.AlsoRequiresValidator{
PathExpressions: expressions,
}
}
32 changes: 32 additions & 0 deletions float32validator/also_requires_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator_test

import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"

"github.com/hashicorp/terraform-plugin-framework-validators/float32validator"
)

func ExampleAlsoRequires() {
// Used within a Schema method of a DataSource, Provider, or Resource
_ = schema.Schema{
Attributes: map[string]schema.Attribute{
"example_attr": schema.Float32Attribute{
Optional: true,
Validators: []validator.Float32{
// Validate this attribute must be configured with other_attr.
float32validator.AlsoRequires(path.Expressions{
path.MatchRoot("other_attr"),
}...),
},
},
"other_attr": schema.StringAttribute{
Optional: true,
},
},
}
}
65 changes: 65 additions & 0 deletions float32validator/any.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-framework/schema/validator"
)

// Any returns a validator which ensures that any configured attribute value
// passes at least one of the given validators.
//
// To prevent practitioner confusion should non-passing validators have
// conflicting logic, only warnings from the passing validator are returned.
// Use AnyWithAllWarnings() to return warnings from non-passing validators
// as well.
func Any(validators ...validator.Float32) validator.Float32 {
return anyValidator{
validators: validators,
}
}

var _ validator.Float32 = anyValidator{}

// anyValidator implements the validator.
type anyValidator struct {
validators []validator.Float32
}

// Description describes the validation in plain text formatting.
func (v anyValidator) Description(ctx context.Context) string {
var descriptions []string

for _, subValidator := range v.validators {
descriptions = append(descriptions, subValidator.Description(ctx))
}

return fmt.Sprintf("Value must satisfy at least one of the validations: %s", strings.Join(descriptions, " + "))
}

// MarkdownDescription describes the validation in Markdown formatting.
func (v anyValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}

// ValidateFloat32 performs the validation.
func (v anyValidator) ValidateFloat32(ctx context.Context, req validator.Float32Request, resp *validator.Float32Response) {
for _, subValidator := range v.validators {
validateResp := &validator.Float32Response{}

subValidator.ValidateFloat32(ctx, req, validateResp)

if !validateResp.Diagnostics.HasError() {
resp.Diagnostics = validateResp.Diagnostics

return
}

resp.Diagnostics.Append(validateResp.Diagnostics...)
}
}
31 changes: 31 additions & 0 deletions float32validator/any_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package float32validator_test

import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"

"github.com/hashicorp/terraform-plugin-framework-validators/float32validator"
)

func ExampleAny() {
// Used within a Schema method of a DataSource, Provider, or Resource
_ = schema.Schema{
Attributes: map[string]schema.Attribute{
"example_attr": schema.Float32Attribute{
Required: true,
Validators: []validator.Float32{
// Validate this Float32 value must either be:
// - 1.0
// - At least 2.0
float32validator.Any(
float32validator.OneOf(1.0),
float32validator.AtLeast(2.0),
),
},
},
},
}
}
Loading

0 comments on commit ba395d2

Please sign in to comment.