Skip to content

Commit

Permalink
Merge pull request #147 from kaleido-io/large-num-test
Browse files Browse the repository at this point in the history
Add support for 256 bit JSON numbers (vs. strings)
  • Loading branch information
peterbroadhurst committed Aug 28, 2024
2 parents c214085 + 3165432 commit 9cc0e2c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
16 changes: 14 additions & 2 deletions pkg/fftypes/jsonany.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 Kaleido, Inc.
// Copyright © 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
Expand All @@ -21,6 +21,7 @@ import (
"crypto/sha256"
"database/sql/driver"
"encoding/json"
"strings"

"github.com/hyperledger/firefly-common/pkg/i18n"
"github.com/hyperledger/firefly-common/pkg/log"
Expand Down Expand Up @@ -76,7 +77,18 @@ func (h *JSONAny) Unmarshal(ctx context.Context, v interface{}) error {
if h == nil {
return i18n.NewError(ctx, i18n.MsgNilOrNullObject)
}
return json.Unmarshal([]byte(*h), v)

if _, ok := v.(*float64); ok {
return i18n.NewError(ctx, i18n.MsgUnmarshalToFloat64NotSupported)
}

d := json.NewDecoder(strings.NewReader(h.String()))
d.UseNumber()
if err := d.Decode(v); err != nil {
return err
}

return nil
}

func (h *JSONAny) Hash() *Bytes32 {
Expand Down
45 changes: 45 additions & 0 deletions pkg/fftypes/jsonany_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,51 @@ func TestUnmarshal(t *testing.T) {
assert.Equal(t, "value1", myObj.Key1)
}

func TestUnmarshalHugeNumber(t *testing.T) {

var myInt64Variable int64
var myFloat64Variable float64
ctx := context.Background()
var h *JSONAny
var myObj struct {
Key1 interface{} `json:"key1"`
Key2 JSONAny `json:"key2"`
Key3 JSONAny `json:"key3"`
}

h = JSONAnyPtr(`{"key1":123456789123456789123456789, "key2":123456789123456789123456789, "key3":1234}`)
err := h.Unmarshal(ctx, &myObj)
assert.NoError(t, err)
assert.Equal(t, json.Number("123456789123456789123456789"), myObj.Key1)

assert.NoError(t, err)
assert.Equal(t, "123456789123456789123456789", myObj.Key2.String())

err = myObj.Key2.Unmarshal(ctx, &myInt64Variable)
assert.Error(t, err)
assert.Regexp(t, "cannot unmarshal number 123456789123456789123456789 into Go value of type int64", err)

err = myObj.Key3.Unmarshal(ctx, &myInt64Variable)
assert.NoError(t, err)
assert.Equal(t, int64(1234), myInt64Variable)

err = myObj.Key2.Unmarshal(ctx, &myFloat64Variable)
assert.Error(t, err)
assert.Regexp(t, "FF00249", err)
}

func TestUnmarshalHugeNumberError(t *testing.T) {

var h *JSONAny
var myObj struct {
Key1 interface{} `json:"key1"`
}

h = JSONAnyPtr(`{"key1":1234567891invalidchars234569}`)
err := h.Unmarshal(context.Background(), &myObj)
assert.Error(t, err)
}

func TestNilHash(t *testing.T) {
assert.Nil(t, (*JSONAny)(nil).Hash())
}
Expand Down
1 change: 1 addition & 0 deletions pkg/i18n/en_base_error_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,5 @@ var (
MsgDBExecFailed = ffe("FF00245", "Database update failed")
MsgDBErrorBuildingStatement = ffe("FF00247", "Error building statement: %s")
MsgDBReadInsertTSFailed = ffe("FF00248", "Failed to read timestamp from database optimized upsert: %s")
MsgUnmarshalToFloat64NotSupported = ffe("FF00249", "Unmarshalling to a float64 is not supported due to possible precision loss. Consider unmarshalling to an interface, json.Number or fftypes.JSONAny instead")
)

0 comments on commit 9cc0e2c

Please sign in to comment.