config/hcl2shim: ValuesSDKEquivalent float64 comparison of numbers
The SDK uses only the native int and float64 types internally for values that are specified as being "number" in schema, so for SDK purposes only a float64 level of precision is significant. To avoid any weirdness introduced as we shim and un-shim numbers, we'll reduce floating point numbers to float64 precision before comparing them to try to mimic the result the SDK itself would've gotten from comparing its own float64 versions of these values using the Go "==" operator.
This commit is contained in:
parent
46a4628782
commit
995042666a
|
@ -60,6 +60,8 @@ func ValuesSDKEquivalent(a, b cty.Value) bool {
|
|||
return valuesSDKEquivalentMappings(a, b)
|
||||
case aTy.IsObjectType() && bTy.IsObjectType():
|
||||
return valuesSDKEquivalentMappings(a, b)
|
||||
case aTy == cty.Number && bTy == cty.Number:
|
||||
return valuesSDKEquivalentNumbers(a, b)
|
||||
default:
|
||||
// We've now covered all the interesting cases, so anything that falls
|
||||
// down here cannot be equivalent.
|
||||
|
@ -175,3 +177,38 @@ func valuesSDKEquivalentMappings(a, b cty.Value) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// valuesSDKEquivalentNumbers decides equivalence for two number values based
|
||||
// on the fact that the SDK uses int and float64 representations while
|
||||
// cty (and thus Terraform Core) uses big.Float, and so we expect to lose
|
||||
// precision in the round-trip.
|
||||
//
|
||||
// This does _not_ attempt to allow for an epsilon difference that may be
|
||||
// caused by accumulated innacuracy in a float calculation, under the
|
||||
// expectation that providers generally do not actually do compuations on
|
||||
// floats and instead just pass string representations of them on verbatim
|
||||
// to remote APIs. A remote API _itself_ may introduce inaccuracy, but that's
|
||||
// a problem for the provider itself to deal with, based on its knowledge of
|
||||
// the remote system, e.g. using DiffSuppressFunc.
|
||||
func valuesSDKEquivalentNumbers(a, b cty.Value) bool {
|
||||
if a.RawEquals(b) {
|
||||
return true // easy
|
||||
}
|
||||
|
||||
af := a.AsBigFloat()
|
||||
bf := b.AsBigFloat()
|
||||
|
||||
if af.IsInt() != bf.IsInt() {
|
||||
return false
|
||||
}
|
||||
if af.IsInt() && bf.IsInt() {
|
||||
return false // a.RawEquals(b) test above is good enough for integers
|
||||
}
|
||||
|
||||
// The SDK supports only int and float64, so if it's not an integer
|
||||
// we know that only a float64-level of precision can possibly be
|
||||
// significant.
|
||||
af64, _ := af.Float64()
|
||||
bf64, _ := bf.Float64()
|
||||
return af64 == bf64
|
||||
}
|
||||
|
|
|
@ -2,12 +2,19 @@ package hcl2shim
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
func TestValuesSDKEquivalent(t *testing.T) {
|
||||
piBig, _, err := big.ParseFloat("3.14159265358979323846264338327950288419716939937510582097494459", 10, 512, big.ToZero)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pi64, _ := piBig.Float64()
|
||||
|
||||
tests := []struct {
|
||||
A, B cty.Value
|
||||
Want bool
|
||||
|
@ -55,6 +62,21 @@ func TestValuesSDKEquivalent(t *testing.T) {
|
|||
cty.Zero,
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.NumberVal(piBig),
|
||||
cty.Zero,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.NumberFloatVal(pi64),
|
||||
cty.Zero,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.NumberFloatVal(pi64),
|
||||
cty.NumberVal(piBig),
|
||||
true,
|
||||
},
|
||||
|
||||
// Bools
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue