Skip to content

Consider improving error messaging for knownvalue.NumberExact float comparisons #311

@austinvalle

Description

@austinvalle

terraform-plugin-testing version

v1.7.0

Use cases

When using knownvalue.NumberExact, it's possible to get confusing error messages in the situation where the provided *big.Float does not match the value parsed from a json.Number because of the mantissa using something like big.NewFloat.

Example

func TestNumberFunction_recreate(t *testing.T) {
    resource.UnitTest(t, resource.TestCase{
        ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
            "framework": providerserver.NewProtocol6WithError(New()),
        },
        Steps: []resource.TestStep{
            {
                Config: `output "test" {
                    value = 1.23
                }`,
                ConfigStateChecks: []statecheck.StateCheck{
                    statecheck.ExpectKnownOutputValue("test", knownvalue.NumberExact(big.NewFloat(1.23))),
                },
            },
        },
    })
}

Test error

--- FAIL: TestNumberFunction_recreate (0.43s)
    /Users/austin.valle/code/terraform-provider-corner/internal/framework6provider/number_function_test.go:80: Step 1/1 error: Post-apply refresh state check(s) failed:
        error checking value for output at path: test, err: expected value 1.23 for NumberExact check, got: 1.23
FAIL
FAIL	github.com/hashicorp/terraform-provider-corner/internal/framework6provider	0.896s
FAIL

What can make this more confusing is when it accidentally is correct and the test passes 😅 :

func TestNumberFunction_successful(t *testing.T) {
    resource.UnitTest(t, resource.TestCase{
        ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
            "framework": providerserver.NewProtocol6WithError(New()),
        },
        Steps: []resource.TestStep{
            {
                Config: `output "test" {
                    value = 1234.5
                }`,
                ConfigStateChecks: []statecheck.StateCheck{
                    // Success!
                    statecheck.ExpectKnownOutputValue("test", knownvalue.NumberExact(big.NewFloat(1234.5))),
                },
            },
        },
    })
}

Workaround

You can workaround this by creating the *big.Float exactly how the internal state check logic/Terraform creates it. Fixing the initial example in this issue:

func TestNumberFunction_recreate(t *testing.T) {
    matchingFloat, _, _ := big.ParseFloat("1.23", 10, 512, big.ToNearestEven)

    resource.UnitTest(t, resource.TestCase{
        ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
            "framework": providerserver.NewProtocol6WithError(New()),
        },
        Steps: []resource.TestStep{
            {
                Config: `output "test" {
                    value = 1.23
                }`,
                ConfigStateChecks: []statecheck.StateCheck{
                    // Success!
                    statecheck.ExpectKnownOutputValue("test", knownvalue.NumberExact(matchingFloat)),
                },
            },
        },
    })
}

Proposal

Improve the error message to also include the precision/rounding/mantissa information to make it more apparent why two floating point numbers don't match. Perhaps we could also make a suggestion about how best to create the *big.Float value if a comparison doesn't match because of the mantissa.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions