From a6bc85f5455cb2e26ef646762a0fa2630ab0891b Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Mon, 1 Jul 2024 15:17:02 -0400 Subject: [PATCH 1/2] Fix `float32` reflection logic and tests --- internal/reflect/number.go | 24 ++++++++++++++--- internal/reflect/number_test.go | 46 ++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/internal/reflect/number.go b/internal/reflect/number.go index c4983be6..18c39fed 100644 --- a/internal/reflect/number.go +++ b/internal/reflect/number.go @@ -132,9 +132,9 @@ func Number(ctx context.Context, typ attr.Type, val tftypes.Value, target reflec return reflect.ValueOf(uintResult), diags } case reflect.Float32: - floatResult, _ := result.Float32() + float64Result, _ := result.Float64() - bf := big.NewFloat(float64(floatResult)) + bf := big.NewFloat(float64Result) if result.Text('f', -1) != bf.Text('f', -1) { diags.Append(roundingErrorDiag) @@ -142,7 +142,25 @@ func Number(ctx context.Context, typ attr.Type, val tftypes.Value, target reflec return target, diags } - return reflect.ValueOf(floatResult), diags + float32Result, accuracy := result.Float32() + + // Underflow + // Reference: https://pkg.go.dev/math/big#Float.Float32 + if float32Result == 0 && accuracy != big.Exact { + diags.Append(roundingErrorDiag) + + return target, diags + } + + // Overflow + // Reference: https://pkg.go.dev/math/big#Float.Float32 + if math.IsInf(float64(float32Result), 0) { + diags.Append(roundingErrorDiag) + + return target, diags + } + + return reflect.ValueOf(float32Result), diags case reflect.Float64: floatResult, _ := result.Float64() diff --git a/internal/reflect/number_test.go b/internal/reflect/number_test.go index a028a68c..1030060c 100644 --- a/internal/reflect/number_test.go +++ b/internal/reflect/number_test.go @@ -22,13 +22,17 @@ import ( ) var ( - overflowInt, _, _ = big.ParseFloat("9223372036854775808", 10, 53, big.ToPositiveInf) - overflowUint, _, _ = big.ParseFloat("18446744073709551616", 10, 53, big.ToPositiveInf) - overflowFloat, _, _ = big.ParseFloat("1e10000", 10, 53, big.ToPositiveInf) - overflowNegativeFloat, _, _ = big.ParseFloat("-1e10000", 10, 53, big.ToPositiveInf) - underflowInt, _, _ = big.ParseFloat("-9223372036854775809", 10, 53, big.ToNegativeInf) - underflowFloat, _, _ = big.ParseFloat("1e-1000", 10, 0, big.ToNegativeInf) - underflowNegativeFloat, _, _ = big.ParseFloat("-1e-1000", 10, 0, big.ToNegativeInf) + overflowInt, _, _ = big.ParseFloat("9223372036854775808", 10, 53, big.ToPositiveInf) + overflowUint, _, _ = big.ParseFloat("18446744073709551616", 10, 53, big.ToPositiveInf) + overflowFloat32, _, _ = big.ParseFloat("3.40282346638528859811704183484516925440e+39", 10, 24, big.ToPositiveInf) + overflowFloat64, _, _ = big.ParseFloat("1e10000", 10, 53, big.ToPositiveInf) + overflowNegativeFloat32, _, _ = big.ParseFloat("-3.40282346638528859811704183484516925440e+39", 10, 53, big.ToPositiveInf) + overflowNegativeFloat64, _, _ = big.ParseFloat("-1e10000", 10, 53, big.ToPositiveInf) + underflowInt, _, _ = big.ParseFloat("-9223372036854775809", 10, 53, big.ToNegativeInf) + underflowFloat32, _, _ = big.ParseFloat("1.401298464324817070923729583289916131280e-46", 10, 0, big.ToNegativeInf) + underflowFloat64, _, _ = big.ParseFloat("1e-1000", 10, 0, big.ToNegativeInf) + underflowNegativeFloat32, _, _ = big.ParseFloat("-1.401298464324817070923729583289916131280e-46", 10, 0, big.ToNegativeInf) + underflowNegativeFloat64, _, _ = big.ParseFloat("-1e-1000", 10, 0, big.ToNegativeInf) ) func TestNumber_bigFloat(t *testing.T) { @@ -590,13 +594,13 @@ func TestNumber_float32(t *testing.T) { var n float32 - result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 123), reflect.ValueOf(n), refl.Options{}, path.Empty()) + result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 1.23), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diags.HasError() { t.Errorf("Unexpected error: %v", diags) } reflect.ValueOf(&n).Elem().Set(result) - if n != 123 { - t.Errorf("Expected %v, got %v", 123, n) + if n != 1.23 { + t.Errorf("Expected %v, got %v", 1.23, n) } } @@ -608,11 +612,11 @@ func TestNumber_float32OverflowError(t *testing.T) { diag.NewAttributeErrorDiagnostic( path.Empty(), "Value Conversion Error", - "An unexpected error was encountered trying to convert to number. This is always an error in the provider. Please report the following to the provider developer:\n\ncannot store 1.797693135e+308 in float32", + "An unexpected error was encountered trying to convert to number. This is always an error in the provider. Please report the following to the provider developer:\n\ncannot store 3.402823669e+39 in float32", ), } - _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, math.MaxFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty()) + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -627,11 +631,11 @@ func TestNumber_float32UnderflowError(t *testing.T) { diag.NewAttributeErrorDiagnostic( path.Empty(), "Value Conversion Error", - "An unexpected error was encountered trying to convert to number. This is always an error in the provider. Please report the following to the provider developer:\n\ncannot store 4.940656458e-324 in float32", + "An unexpected error was encountered trying to convert to number. This is always an error in the provider. Please report the following to the provider developer:\n\ncannot store 1.401298464e-46 in float32", ), } - _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, math.SmallestNonzeroFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty()) + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -643,13 +647,13 @@ func TestNumber_float64(t *testing.T) { var n float64 - result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 123), reflect.ValueOf(n), refl.Options{}, path.Empty()) + result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 1.23), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diags.HasError() { t.Errorf("Unexpected error: %v", diags) } reflect.ValueOf(&n).Elem().Set(result) - if n != 123 { - t.Errorf("Expected %v, got %v", 123, n) + if n != 1.23 { + t.Errorf("Expected %v, got %v", 1.23, n) } } @@ -665,7 +669,7 @@ func TestNumber_float64OverflowError(t *testing.T) { ), } - _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowFloat), reflect.ValueOf(n), refl.Options{}, path.Empty()) + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -684,7 +688,7 @@ func TestNumber_float64OverflowNegativeError(t *testing.T) { ), } - _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowNegativeFloat), reflect.ValueOf(n), refl.Options{}, path.Empty()) + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowNegativeFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -703,7 +707,7 @@ func TestNumber_float64UnderflowError(t *testing.T) { ), } - _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowFloat), reflect.ValueOf(n), refl.Options{}, path.Empty()) + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) @@ -722,7 +726,7 @@ func TestNumber_float64UnderflowNegativeError(t *testing.T) { ), } - _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowNegativeFloat), reflect.ValueOf(n), refl.Options{}, path.Empty()) + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowNegativeFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty()) if diff := cmp.Diff(diags, expectedDiags); diff != "" { t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) From a7fd8bc89d7354202dc1ff1bd43536082df2c144 Mon Sep 17 00:00:00 2001 From: Selena Goods Date: Mon, 1 Jul 2024 15:22:22 -0400 Subject: [PATCH 2/2] Add float32 negative overflow and underflow tests --- internal/reflect/number_test.go | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/internal/reflect/number_test.go b/internal/reflect/number_test.go index 1030060c..a7b8b49e 100644 --- a/internal/reflect/number_test.go +++ b/internal/reflect/number_test.go @@ -623,6 +623,25 @@ func TestNumber_float32OverflowError(t *testing.T) { } } +func TestNumber_float32OverflowNegativeError(t *testing.T) { + t.Parallel() + + var n float32 + expectedDiags := diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Empty(), + "Value Conversion Error", + "An unexpected error was encountered trying to convert to number. This is always an error in the provider. Please report the following to the provider developer:\n\ncannot store -3.402823466e+39 in float32", + ), + } + + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowNegativeFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty()) + + if diff := cmp.Diff(diags, expectedDiags); diff != "" { + t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) + } +} + func TestNumber_float32UnderflowError(t *testing.T) { t.Parallel() @@ -642,6 +661,25 @@ func TestNumber_float32UnderflowError(t *testing.T) { } } +func TestNumber_float32UnderflowNegativeError(t *testing.T) { + t.Parallel() + + var n float32 + expectedDiags := diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Empty(), + "Value Conversion Error", + "An unexpected error was encountered trying to convert to number. This is always an error in the provider. Please report the following to the provider developer:\n\ncannot store -1.401298464e-46 in float32", + ), + } + + _, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowNegativeFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty()) + + if diff := cmp.Diff(diags, expectedDiags); diff != "" { + t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff) + } +} + func TestNumber_float64(t *testing.T) { t.Parallel()