Skip to content

Commit

Permalink
boolvalidator: add Equals validator (#232)
Browse files Browse the repository at this point in the history
* boolvalidator: add Equals validator

This validator can be used in cases where non-null boolean value should be exactly `true` or exactly `false`.

```console
% go test -count=1 ./boolvalidator/...
ok      github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator        0.251s
```

* Update boolvalidator/equals.go

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

* chore: changelog
  • Loading branch information
jar-b authored Sep 20, 2024
1 parent 7979126 commit 974015b
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20240920-164852.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'boolvalidator: Added `Equals` validator'
time: 2024-09-20T16:48:52.562758-04:00
custom:
Issue: "232"
51 changes: 51 additions & 0 deletions boolvalidator/equals.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package boolvalidator

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var _ validator.Bool = equalsValidator{}

type equalsValidator struct {
value types.Bool
}

func (v equalsValidator) Description(ctx context.Context) string {
return fmt.Sprintf("Value must be %q", v.value)
}

func (v equalsValidator) MarkdownDescription(ctx context.Context) string {
return v.Description(ctx)
}

func (v equalsValidator) ValidateBool(ctx context.Context, req validator.BoolRequest, resp *validator.BoolResponse) {
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
return
}

configValue := req.ConfigValue

if !configValue.Equal(v.value) {
resp.Diagnostics.Append(validatordiag.InvalidAttributeValueMatchDiagnostic(
req.Path,
v.Description(ctx),
configValue.String(),
))
}
}

// Equals returns an AttributeValidator which ensures that the configured boolean attribute
// matches the given `value`. Null (unconfigured) and unknown (known after apply) values are skipped.
func Equals(value bool) validator.Bool {
return equalsValidator{
value: types.BoolValue(value),
}
}
69 changes: 69 additions & 0 deletions boolvalidator/equals_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package boolvalidator_test

import (
"context"
"testing"

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

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

type testCase struct {
in types.Bool
validator validator.Bool
expErrors int
}

testCases := map[string]testCase{
"simple-match": {
in: types.BoolValue(true),
validator: boolvalidator.Equals(true),
expErrors: 0,
},
"simple-mismatch": {
in: types.BoolValue(false),
validator: boolvalidator.Equals(true),
expErrors: 1,
},
"skip-validation-on-null": {
in: types.BoolNull(),
validator: boolvalidator.Equals(true),
expErrors: 0,
},
"skip-validation-on-unknown": {
in: types.BoolUnknown(),
validator: boolvalidator.Equals(true),
expErrors: 0,
},
}

for name, test := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()
req := validator.BoolRequest{
ConfigValue: test.in,
}
res := validator.BoolResponse{}
test.validator.ValidateBool(context.TODO(), req, &res)

if test.expErrors > 0 && !res.Diagnostics.HasError() {
t.Fatalf("expected %d error(s), got none", test.expErrors)
}

if test.expErrors > 0 && test.expErrors != res.Diagnostics.ErrorsCount() {
t.Fatalf("expected %d error(s), got %d: %v", test.expErrors, res.Diagnostics.ErrorsCount(), res.Diagnostics)
}

if test.expErrors == 0 && res.Diagnostics.HasError() {
t.Fatalf("expected no error(s), got %d: %v", res.Diagnostics.ErrorsCount(), res.Diagnostics)
}
})
}
}

0 comments on commit 974015b

Please sign in to comment.