diff --git a/.changes/unreleased/ENHANCEMENTS-20240626-163240.yaml b/.changes/unreleased/ENHANCEMENTS-20240626-163240.yaml new file mode 100644 index 000000000..7f31ac2ea --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20240626-163240.yaml @@ -0,0 +1,5 @@ +kind: ENHANCEMENTS +body: 'knownvalue: Add `Int32Exact` check for int32 value testing.' +time: 2024-06-26T16:32:40.387821-04:00 +custom: + Issue: "356" diff --git a/.changes/unreleased/ENHANCEMENTS-20240626-163311.yaml b/.changes/unreleased/ENHANCEMENTS-20240626-163311.yaml new file mode 100644 index 000000000..b6c29f5ba --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20240626-163311.yaml @@ -0,0 +1,5 @@ +kind: ENHANCEMENTS +body: 'knownvalue: Add `Float32Exact` check for float32 value testing.' +time: 2024-06-26T16:33:11.495969-04:00 +custom: + Issue: "356" diff --git a/knownvalue/float32.go b/knownvalue/float32.go new file mode 100644 index 000000000..ee02fdcb1 --- /dev/null +++ b/knownvalue/float32.go @@ -0,0 +1,51 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "encoding/json" + "fmt" + "strconv" +) + +var _ Check = float32Exact{} + +type float32Exact struct { + value float32 +} + +// CheckValue determines whether the passed value is of type float32, and +// contains a matching float32 value. +func (v float32Exact) CheckValue(other any) error { + jsonNum, ok := other.(json.Number) + + if !ok { + return fmt.Errorf("expected json.Number value for Float32Exact check, got: %T", other) + } + + otherVal, err := strconv.ParseFloat(string(jsonNum), 32) + + if err != nil { + return fmt.Errorf("expected json.Number to be parseable as float32 value for Float32Exact check: %s", err) + } + + if float32(otherVal) != v.value { + return fmt.Errorf("expected value %s for Float32Exact check, got: %s", v.String(), strconv.FormatFloat(otherVal, 'f', -1, 32)) + } + + return nil +} + +// String returns the string representation of the float32 value. +func (v float32Exact) String() string { + return strconv.FormatFloat(float64(v.value), 'f', -1, 32) +} + +// Float32Exact returns a Check for asserting equality between the +// supplied float32 and the value passed to the CheckValue method. +func Float32Exact(value float32) float32Exact { + return float32Exact{ + value: value, + } +} diff --git a/knownvalue/float32_test.go b/knownvalue/float32_test.go new file mode 100644 index 000000000..4b2ef14c4 --- /dev/null +++ b/knownvalue/float32_test.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestFloat32Value_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.Check + other any + expectedError error + }{ + "zero-nil": { + self: knownvalue.Float32Exact(0), + expectedError: fmt.Errorf("expected json.Number value for Float32Exact check, got: "), + }, + "zero-other": { + self: knownvalue.Float32Exact(0), + other: json.Number("0.0"), // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.Float32Exact(1.234), + expectedError: fmt.Errorf("expected json.Number value for Float32Exact check, got: "), + }, + "wrong-type": { + self: knownvalue.Float32Exact(1.234), + other: json.Number("str"), + expectedError: fmt.Errorf("expected json.Number to be parseable as float32 value for Float32Exact check: strconv.ParseFloat: parsing \"str\": invalid syntax"), + }, + "not-equal": { + self: knownvalue.Float32Exact(1.234), + other: json.Number("4.321"), + expectedError: fmt.Errorf("expected value 1.234 for Float32Exact check, got: 4.321"), + }, + "equal": { + self: knownvalue.Float32Exact(1.234), + other: json.Number("1.234"), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestFloat32Value_String(t *testing.T) { + t.Parallel() + + got := knownvalue.Float32Exact(1.234567890123e+03).String() + + if diff := cmp.Diff(got, "1234.5679"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/knownvalue/int32.go b/knownvalue/int32.go new file mode 100644 index 000000000..49dd30bb3 --- /dev/null +++ b/knownvalue/int32.go @@ -0,0 +1,51 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue + +import ( + "encoding/json" + "fmt" + "strconv" +) + +var _ Check = int32Exact{} + +type int32Exact struct { + value int32 +} + +// CheckValue determines whether the passed value is of type int32, and +// contains a matching int32 value. +func (v int32Exact) CheckValue(other any) error { + jsonNum, ok := other.(json.Number) + + if !ok { + return fmt.Errorf("expected json.Number value for Int32Exact check, got: %T", other) + } + + otherVal, err := strconv.ParseInt(string(jsonNum), 10, 32) + + if err != nil { + return fmt.Errorf("expected json.Number to be parseable as int32 value for Int32Exact check: %s", err) + } + + if int32(otherVal) != v.value { + return fmt.Errorf("expected value %d for Int32Exact check, got: %d", v.value, otherVal) + } + + return nil +} + +// String returns the string representation of the int32 value. +func (v int32Exact) String() string { + return strconv.FormatInt(int64(v.value), 10) +} + +// Int32Exact returns a Check for asserting equality between the +// supplied int32 and the value passed to the CheckValue method. +func Int32Exact(value int32) int32Exact { + return int32Exact{ + value: value, + } +} diff --git a/knownvalue/int32_test.go b/knownvalue/int32_test.go new file mode 100644 index 000000000..b153dee29 --- /dev/null +++ b/knownvalue/int32_test.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package knownvalue_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" +) + +func TestInt32Value_CheckValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + self knownvalue.Check + other any + expectedError error + }{ + "zero-nil": { + self: knownvalue.Int32Exact(0), + expectedError: fmt.Errorf("expected json.Number value for Int32Exact check, got: "), + }, + "zero-other": { + self: knownvalue.Int32Exact(0), + other: json.Number("0"), // checking against the underlying value field zero-value + }, + "nil": { + self: knownvalue.Int32Exact(1234), + expectedError: fmt.Errorf("expected json.Number value for Int32Exact check, got: "), + }, + "wrong-type": { + self: knownvalue.Int32Exact(1234), + other: json.Number("str"), + expectedError: fmt.Errorf("expected json.Number to be parseable as int32 value for Int32Exact check: strconv.ParseInt: parsing \"str\": invalid syntax"), + }, + "not-equal": { + self: knownvalue.Int32Exact(1234), + other: json.Number("4321"), + expectedError: fmt.Errorf("expected value 1234 for Int32Exact check, got: 4321"), + }, + "equal": { + self: knownvalue.Int32Exact(1234), + other: json.Number("1234"), + }, + } + + for name, testCase := range testCases { + name, testCase := name, testCase + + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := testCase.self.CheckValue(testCase.other) + + if diff := cmp.Diff(got, testCase.expectedError, equateErrorMessage); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } + }) + } +} + +func TestInt32Value_String(t *testing.T) { + t.Parallel() + + got := knownvalue.Int32Exact(123456789).String() + + if diff := cmp.Diff(got, "123456789"); diff != "" { + t.Errorf("unexpected difference: %s", diff) + } +} diff --git a/website/data/plugin-testing-nav-data.json b/website/data/plugin-testing-nav-data.json index bac221d3f..6fbce82b3 100644 --- a/website/data/plugin-testing-nav-data.json +++ b/website/data/plugin-testing-nav-data.json @@ -86,10 +86,18 @@ "title": "Custom", "path": "acceptance-tests/known-value-checks/custom" }, + { + "title": "Float32", + "path": "acceptance-tests/known-value-checks/float32" + }, { "title": "Float64", "path": "acceptance-tests/known-value-checks/float64" }, + { + "title": "Int32", + "path": "acceptance-tests/known-value-checks/int32" + }, { "title": "Int64", "path": "acceptance-tests/known-value-checks/int64" diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx index b577eb8cc..ef92d4e80 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/custom.mdx @@ -63,7 +63,9 @@ The `other` parameter passed to the `CheckValue` method is one of the following Refer to the following built-in known value checks for implementations that handle the different types that can be passed to the `CheckValue` method in the `other` parameter: * [Bool](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Bool) +* [Float32Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float32Exact) * [Float64Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float64Exact) +* [Int32Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int32Exact) * [Int64Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int64Exact) * [ListExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#ListExact) * [MapExact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#MapExact) diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/float32.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float32.mdx new file mode 100644 index 000000000..26f5a77fc --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/float32.mdx @@ -0,0 +1,42 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Float32 Value Checks for use with Plan Checks. +--- + +# Float32 Known Value Checks + +The known value checks that are available for float32 values are: + +* [Float32Exact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float32#float32exact-check) + +## `Float32Exact` Check + +The [Float32Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float32Exact) check tests that a resource attribute, or output value has an exactly matching float32 value. + +Example usage of [Float32Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Float32Exact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Float32(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + // Provider definition omitted. + Steps: []resource.TestStep{ + { + // Example resource containing a computed float32 attribute named "computed_attribute" + Config: `resource "test_resource" "one" {}`, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("computed_attribute"), + knownvalue.Float32Exact(1.23), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx index 62db10d5b..a942ce660 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/index.mdx @@ -39,7 +39,9 @@ The following table shows the correspondence between [knownvalue.Check](https:// | Known Value Check Type | Framework Attribute Type | SDKv2 Attribute Type | |------------------------------------------------------------------------------------------------------|---------------------------|----------------------| | [Bool Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/bool) | `schema.BoolAttribute` | `schema.TypeBool` | +| [Float32 Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/float32) | `schema.Float32Attribute` | `schema.TypeFloat` | | [Float64 Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64) | `schema.Float64Attribute` | `schema.TypeFloat` | +| [Int32 Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/int32) | `schema.Int32Attribute` | `schema.TypeInt` | | [Int64 Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/int64) | `schema.Int64Attribute` | `schema.TypeInt` | | [List Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/list) | `schema.ListAttribute` | `schema.TypeList` | | [Map Known Value Checks](/terraform/plugin/testing/acceptance-tests/known-value-checks/map) | `schema.MapAttribute` | `schema.TypeMap` | diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int32.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int32.mdx new file mode 100644 index 000000000..69f1bd7ab --- /dev/null +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int32.mdx @@ -0,0 +1,42 @@ +--- +page_title: 'Plugin Development - Acceptance Testing: Known Values' +description: >- + Int32 Value Checks for use with Plan Checks. +--- + +# Int32 Known Value Checks + +The known value checks that are available for int32 values are: + +* [Int32Exact](/terraform/plugin/testing/acceptance-tests/known-value-checks/int32#int32exact-check) + +## `Int32Exact` Check + +The [Int32Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int32Exact) check tests that a resource attribute, or output value has an exactly matching int32 value. + +Example usage of [Int32Exact](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-testing/knownvalue#Int32Exact) in an [ExpectKnownValue](/terraform/plugin/testing/acceptance-tests/plan-checks/resource) plan check. + +```go +func TestExpectKnownValue_CheckPlan_Int32(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + // Provider definition omitted. + Steps: []resource.TestStep{ + { + // Example resource containing a computed int32 attribute named "computed_attribute" + Config: `resource "test_resource" "one" {}`, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue( + "test_resource.one", + tfjsonpath.New("computed_attribute"), + knownvalue.Int32Exact(123), + ), + }, + }, + }, + }, + }) +} +``` diff --git a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx index af647e701..55cc46192 100644 --- a/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx +++ b/website/docs/plugin/testing/acceptance-tests/known-value-checks/int64.mdx @@ -8,7 +8,7 @@ description: >- The known value checks that are available for int64 values are: -* [Int64Exact](/terraform/plugin/testing/acceptance-tests/known-value-checks/float64#int64exact-check) +* [Int64Exact](/terraform/plugin/testing/acceptance-tests/known-value-checks/int64#int64exact-check) ## `Int64Exact` Check diff --git a/website/docs/plugin/testing/acceptance-tests/tfjson-paths.mdx b/website/docs/plugin/testing/acceptance-tests/tfjson-paths.mdx index e169026d2..a40e90f52 100644 --- a/website/docs/plugin/testing/acceptance-tests/tfjson-paths.mdx +++ b/website/docs/plugin/testing/acceptance-tests/tfjson-paths.mdx @@ -64,7 +64,9 @@ The following table shows the different [`tfjsonpath.Path` type](https://pkg.go. | Framework Attribute Type | SDKv2 Attribute Type | Child Path Method | |---------------------------|----------------------|-------------------| | `schema.BoolAttribute` | `schema.TypeBool` | N/A | +| `schema.Float32Attribute` | `schema.TypeFloat` | N/A | | `schema.Float64Attribute` | `schema.TypeFloat` | N/A | +| `schema.Int32Attribute` | `schema.TypeInt` | N/A | | `schema.Int64Attribute` | `schema.TypeInt` | N/A | | `schema.ListAttribute` | `schema.TypeList` | `AtSliceIndex()` | | `schema.MapAttribute` | `schema.TypeMap` | `AtMapKey()` |