From 32129a09f89045e877b34254f394e1b71b14e4d6 Mon Sep 17 00:00:00 2001 From: pmahindrakar-oss Date: Fri, 30 Jul 2021 09:25:48 +0530 Subject: [PATCH] Handling large integers (#202) * Handling large integers Signed-off-by: Prafulla Mahindrakar --- clients/go/coreutils/literals.go | 9 ++++++++- clients/go/coreutils/literals_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/clients/go/coreutils/literals.go b/clients/go/coreutils/literals.go index 2a6b10bb0..707feaaaa 100644 --- a/clients/go/coreutils/literals.go +++ b/clients/go/coreutils/literals.go @@ -4,6 +4,7 @@ package coreutils import ( "encoding/json" "fmt" + "math" "reflect" "strconv" "strings" @@ -492,7 +493,13 @@ func MakeLiteralForType(t *core.LiteralType, v interface{}) (*core.Literal, erro if v == nil { strValue = "" } - + // Note this is to support large integers which by default when passed from an unmarshalled json will be + // converted to float64 and printed as exponential format by Sprintf. + // eg : 8888888 get converted to 8.888888e+06 and which causes strconv.ParseInt to fail + // Inorder to avoid this we explicitly add this check. + if f, ok := v.(float64); ok && math.Trunc(f) == f { + strValue = fmt.Sprintf("%.0f", math.Trunc(f)) + } if newT.Simple == core.SimpleType_STRUCT { if _, isValueStringType := v.(string); !isValueStringType { byteValue, err := json.Marshal(v) diff --git a/clients/go/coreutils/literals_test.go b/clients/go/coreutils/literals_test.go index 38e03f1de..fc0d29d12 100644 --- a/clients/go/coreutils/literals_test.go +++ b/clients/go/coreutils/literals_test.go @@ -6,6 +6,7 @@ package coreutils import ( "fmt" "reflect" + "strconv" "testing" "time" @@ -16,6 +17,7 @@ import ( "github.com/golang/protobuf/ptypes" structpb "github.com/golang/protobuf/ptypes/struct" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -391,6 +393,30 @@ func TestMakeLiteralForType(t *testing.T) { assert.Equal(t, expectedVal, actualVal) }) + t.Run("IntegerComingInAsFloatOverFlow", func(t *testing.T) { + var literalType = &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_INTEGER}} + _, err := MakeLiteralForType(literalType, 8.888888e+19) + assert.NotNil(t, err) + numError := &strconv.NumError{ + Func: "ParseInt", + Num: "88888880000000000000", + Err: fmt.Errorf("value out of range"), + } + parseIntError := errors.WithMessage(numError, "failed to parse integer value") + assert.Equal(t, errors.WithStack(parseIntError).Error(), err.Error()) + }) + + t.Run("IntegerComingInAsFloat", func(t *testing.T) { + var literalType = &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_INTEGER}} + val, err := MakeLiteralForType(literalType, 8.888888e+18) + assert.NoError(t, err) + literalVal := &core.Literal{Value: &core.Literal_Scalar{Scalar: &core.Scalar{ + Value: &core.Scalar_Primitive{Primitive: &core.Primitive{Value: &core.Primitive_Integer{Integer: 8.888888e+18}}}}}} + expectedVal, _ := ExtractFromLiteral(literalVal) + actualVal, _ := ExtractFromLiteral(val) + assert.Equal(t, expectedVal, actualVal) + }) + t.Run("SimpleFloat", func(t *testing.T) { var literalType = &core.LiteralType{Type: &core.LiteralType_Simple{Simple: core.SimpleType_FLOAT}} val, err := MakeLiteralForType(literalType, 1)