Skip to content

Commit 6ab653a

Browse files
authored
reflect: Use float64 string representation for float32 reflection equivalency (#1015)
* Fix `float32` reflection logic and tests * Add float32 negative overflow and underflow tests
1 parent 758afb7 commit 6ab653a

File tree

2 files changed

+84
-24
lines changed

2 files changed

+84
-24
lines changed

internal/reflect/number.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,35 @@ func Number(ctx context.Context, typ attr.Type, val tftypes.Value, target reflec
132132
return reflect.ValueOf(uintResult), diags
133133
}
134134
case reflect.Float32:
135-
floatResult, _ := result.Float32()
135+
float64Result, _ := result.Float64()
136136

137-
bf := big.NewFloat(float64(floatResult))
137+
bf := big.NewFloat(float64Result)
138138

139139
if result.Text('f', -1) != bf.Text('f', -1) {
140140
diags.Append(roundingErrorDiag)
141141

142142
return target, diags
143143
}
144144

145-
return reflect.ValueOf(floatResult), diags
145+
float32Result, accuracy := result.Float32()
146+
147+
// Underflow
148+
// Reference: https://pkg.go.dev/math/big#Float.Float32
149+
if float32Result == 0 && accuracy != big.Exact {
150+
diags.Append(roundingErrorDiag)
151+
152+
return target, diags
153+
}
154+
155+
// Overflow
156+
// Reference: https://pkg.go.dev/math/big#Float.Float32
157+
if math.IsInf(float64(float32Result), 0) {
158+
diags.Append(roundingErrorDiag)
159+
160+
return target, diags
161+
}
162+
163+
return reflect.ValueOf(float32Result), diags
146164
case reflect.Float64:
147165
floatResult, _ := result.Float64()
148166

internal/reflect/number_test.go

+63-21
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ import (
2222
)
2323

2424
var (
25-
overflowInt, _, _ = big.ParseFloat("9223372036854775808", 10, 53, big.ToPositiveInf)
26-
overflowUint, _, _ = big.ParseFloat("18446744073709551616", 10, 53, big.ToPositiveInf)
27-
overflowFloat, _, _ = big.ParseFloat("1e10000", 10, 53, big.ToPositiveInf)
28-
overflowNegativeFloat, _, _ = big.ParseFloat("-1e10000", 10, 53, big.ToPositiveInf)
29-
underflowInt, _, _ = big.ParseFloat("-9223372036854775809", 10, 53, big.ToNegativeInf)
30-
underflowFloat, _, _ = big.ParseFloat("1e-1000", 10, 0, big.ToNegativeInf)
31-
underflowNegativeFloat, _, _ = big.ParseFloat("-1e-1000", 10, 0, big.ToNegativeInf)
25+
overflowInt, _, _ = big.ParseFloat("9223372036854775808", 10, 53, big.ToPositiveInf)
26+
overflowUint, _, _ = big.ParseFloat("18446744073709551616", 10, 53, big.ToPositiveInf)
27+
overflowFloat32, _, _ = big.ParseFloat("3.40282346638528859811704183484516925440e+39", 10, 24, big.ToPositiveInf)
28+
overflowFloat64, _, _ = big.ParseFloat("1e10000", 10, 53, big.ToPositiveInf)
29+
overflowNegativeFloat32, _, _ = big.ParseFloat("-3.40282346638528859811704183484516925440e+39", 10, 53, big.ToPositiveInf)
30+
overflowNegativeFloat64, _, _ = big.ParseFloat("-1e10000", 10, 53, big.ToPositiveInf)
31+
underflowInt, _, _ = big.ParseFloat("-9223372036854775809", 10, 53, big.ToNegativeInf)
32+
underflowFloat32, _, _ = big.ParseFloat("1.401298464324817070923729583289916131280e-46", 10, 0, big.ToNegativeInf)
33+
underflowFloat64, _, _ = big.ParseFloat("1e-1000", 10, 0, big.ToNegativeInf)
34+
underflowNegativeFloat32, _, _ = big.ParseFloat("-1.401298464324817070923729583289916131280e-46", 10, 0, big.ToNegativeInf)
35+
underflowNegativeFloat64, _, _ = big.ParseFloat("-1e-1000", 10, 0, big.ToNegativeInf)
3236
)
3337

3438
func TestNumber_bigFloat(t *testing.T) {
@@ -590,13 +594,13 @@ func TestNumber_float32(t *testing.T) {
590594

591595
var n float32
592596

593-
result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 123), reflect.ValueOf(n), refl.Options{}, path.Empty())
597+
result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 1.23), reflect.ValueOf(n), refl.Options{}, path.Empty())
594598
if diags.HasError() {
595599
t.Errorf("Unexpected error: %v", diags)
596600
}
597601
reflect.ValueOf(&n).Elem().Set(result)
598-
if n != 123 {
599-
t.Errorf("Expected %v, got %v", 123, n)
602+
if n != 1.23 {
603+
t.Errorf("Expected %v, got %v", 1.23, n)
600604
}
601605
}
602606

@@ -608,11 +612,30 @@ func TestNumber_float32OverflowError(t *testing.T) {
608612
diag.NewAttributeErrorDiagnostic(
609613
path.Empty(),
610614
"Value Conversion Error",
611-
"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",
615+
"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",
616+
),
617+
}
618+
619+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty())
620+
621+
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
622+
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
623+
}
624+
}
625+
626+
func TestNumber_float32OverflowNegativeError(t *testing.T) {
627+
t.Parallel()
628+
629+
var n float32
630+
expectedDiags := diag.Diagnostics{
631+
diag.NewAttributeErrorDiagnostic(
632+
path.Empty(),
633+
"Value Conversion Error",
634+
"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",
612635
),
613636
}
614637

615-
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, math.MaxFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty())
638+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowNegativeFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty())
616639

617640
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
618641
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
@@ -627,11 +650,30 @@ func TestNumber_float32UnderflowError(t *testing.T) {
627650
diag.NewAttributeErrorDiagnostic(
628651
path.Empty(),
629652
"Value Conversion Error",
630-
"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",
653+
"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",
631654
),
632655
}
633656

634-
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, math.SmallestNonzeroFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty())
657+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty())
658+
659+
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
660+
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
661+
}
662+
}
663+
664+
func TestNumber_float32UnderflowNegativeError(t *testing.T) {
665+
t.Parallel()
666+
667+
var n float32
668+
expectedDiags := diag.Diagnostics{
669+
diag.NewAttributeErrorDiagnostic(
670+
path.Empty(),
671+
"Value Conversion Error",
672+
"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",
673+
),
674+
}
675+
676+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowNegativeFloat32), reflect.ValueOf(n), refl.Options{}, path.Empty())
635677

636678
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
637679
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
@@ -643,13 +685,13 @@ func TestNumber_float64(t *testing.T) {
643685

644686
var n float64
645687

646-
result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 123), reflect.ValueOf(n), refl.Options{}, path.Empty())
688+
result, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, 1.23), reflect.ValueOf(n), refl.Options{}, path.Empty())
647689
if diags.HasError() {
648690
t.Errorf("Unexpected error: %v", diags)
649691
}
650692
reflect.ValueOf(&n).Elem().Set(result)
651-
if n != 123 {
652-
t.Errorf("Expected %v, got %v", 123, n)
693+
if n != 1.23 {
694+
t.Errorf("Expected %v, got %v", 1.23, n)
653695
}
654696
}
655697

@@ -665,7 +707,7 @@ func TestNumber_float64OverflowError(t *testing.T) {
665707
),
666708
}
667709

668-
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowFloat), reflect.ValueOf(n), refl.Options{}, path.Empty())
710+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty())
669711

670712
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
671713
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
@@ -684,7 +726,7 @@ func TestNumber_float64OverflowNegativeError(t *testing.T) {
684726
),
685727
}
686728

687-
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowNegativeFloat), reflect.ValueOf(n), refl.Options{}, path.Empty())
729+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, overflowNegativeFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty())
688730

689731
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
690732
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
@@ -703,7 +745,7 @@ func TestNumber_float64UnderflowError(t *testing.T) {
703745
),
704746
}
705747

706-
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowFloat), reflect.ValueOf(n), refl.Options{}, path.Empty())
748+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty())
707749

708750
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
709751
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)
@@ -722,7 +764,7 @@ func TestNumber_float64UnderflowNegativeError(t *testing.T) {
722764
),
723765
}
724766

725-
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowNegativeFloat), reflect.ValueOf(n), refl.Options{}, path.Empty())
767+
_, diags := refl.Number(context.Background(), types.NumberType, tftypes.NewValue(tftypes.Number, underflowNegativeFloat64), reflect.ValueOf(n), refl.Options{}, path.Empty())
726768

727769
if diff := cmp.Diff(diags, expectedDiags); diff != "" {
728770
t.Errorf("unexpected diagnostics (+wanted, -got): %s", diff)

0 commit comments

Comments
 (0)