You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, Number always converts its value to float64. In many cases it works well, however float64 can't represent big integer values (larger than 2^62) without precision loss.
Actually, there is no native type that can represent ALL values of int64, uint64, and float64 without loss. However, there is a library type that can do it: big.Float (see https://pkg.go.dev/math/big).
Here are the steps:
replace underlying value of Number from float64 to big.Float
by default, use precision that is sufficient to represent all values of int64, uint64, and float64 without loss
allow user to set higher precision in Config (this may be useful if user wants to parse Number from String that contains bigger integer or float)
rework canonNumber() to return big.Float instead of float64; it should automatically detect precision and create big.Float from any of these types:
all native float and integer types
type definitions for those native types (e.g. type MyInt int)
big.Float and big.Int
json.Number
rework NewNumber constructor: it should accept interface{} instead of float64 and use canonNumber() to convert it to big.Float
rework all Number operations, so that they will operate on big.Float values (one stored in Number, another returned from canonNumber for operation argument)
rework Number.EqualDelta and Number.NotEqualDelta: they should accept interface{} instead of float64; this will allow user to pass big.Float instead of float64, when necessary
ensure that canonValue() and other canonization functions does not cause precision loss
rework Number creation
Expect.Number() should accept interface{} instead of float64
rework Value.Number() - it should not force float64 type
rework String.AsNumber() - it should correctly parse big floats and integers
find all invocations to newNumber() that have unnecessary casts to float64 and pass integers instead; e.g. newNumber(a.chain, float64(len(a.value))) can be now replaced with newNumber(a.chain, len(a.value)) because Number now supports integers
adjust equality checks:
find all places that do deep equality checks (e.g. in Object, Array) using reflect.DeepEqual
ensure that they will work when original values have different representations for same numbers (e.g. json.Number vs float64 vs big.Float)
mark Number.Raw as deprecated and ask user to use AsFloat instead; in httpexpect v3, when we will be able to break compatibility, we'll undeprecate Raw, but change its return type to big.Float
adjust DefaultFormatter to handle big.Float values:
add unit tests for Number to check how it works with big integers and floats
add unit tests for Value.Number() to check how it works with json.Number and integers that can't be represented without loss as float64
rework tests for String.AsNumber() - rework float_precision test, add tests for big floats and integers that can't be parsed with default precision, but can be parsed when setting higher precision in Config
cover big integers and floats, and different precisions, in e2e tests (e.g. in e2e_basic_test.go)
Currently, Number always converts its value to float64. In many cases it works well, however float64 can't represent big integer values (larger than 2^62) without precision loss.
Actually, there is no native type that can represent ALL values of int64, uint64, and float64 without loss. However, there is a library type that can do it: big.Float (see https://pkg.go.dev/math/big).
Here are the steps:
replace underlying value of Number from float64 to big.Float
by default, use precision that is sufficient to represent all values of int64, uint64, and float64 without loss
allow user to set higher precision in Config (this may be useful if user wants to parse Number from String that contains bigger integer or float)
rework canonNumber() to return big.Float instead of float64; it should automatically detect precision and create big.Float from any of these types:
type MyInt int)rework NewNumber constructor: it should accept interface{} instead of float64 and use canonNumber() to convert it to big.Float
rework all Number operations, so that they will operate on big.Float values (one stored in Number, another returned from canonNumber for operation argument)
rework Number.EqualDelta and Number.NotEqualDelta: they should accept interface{} instead of float64; this will allow user to pass big.Float instead of float64, when necessary
rework JSON decoding:
find places where we decode JSON: canonValue, Response, WebsocketMessage; configure JSON decoder to use json.Number instead of float64 (see https://pkg.go.dev/encoding/json#Decoder.UseNumber)
ensure that canonValue() and other canonization functions does not cause precision loss
rework Number creation
Expect.Number() should accept interface{} instead of float64
rework Value.Number() - it should not force float64 type
rework String.AsNumber() - it should correctly parse big floats and integers
find all invocations to newNumber() that have unnecessary casts to float64 and pass integers instead; e.g.
newNumber(a.chain, float64(len(a.value)))can be now replaced withnewNumber(a.chain, len(a.value))because Number now supports integersadjust equality checks:
find all places that do deep equality checks (e.g. in Object, Array) using reflect.DeepEqual
ensure that they will work when original values have different representations for same numbers (e.g. json.Number vs float64 vs big.Float)
cover these cases with unit tests
add new getters for Number:
add 4 new methods: AsInt (returns int64), AsUint (return uint64), AsFloat (return float64), AsBig (return big.Float)
each method should report failure if underlying value can't be converted to requested types without loss
add IsBig (similar to other Is methods, see Implement Number IsInt, IsUint, IsFloat, IsNan #155)
mark Number.Raw as deprecated and ask user to use AsFloat instead; in httpexpect v3, when we will be able to break compatibility, we'll undeprecate Raw, but change its return type to big.Float
adjust DefaultFormatter to handle big.Float values:
if value is integer, print it as integer
otherwise print it in non-scientific form (see also Add DefaultFormatter.EnableScientific #190)
adjust tests:
add unit tests for Number to check how it works with big integers and floats
add unit tests for Value.Number() to check how it works with json.Number and integers that can't be represented without loss as float64
rework tests for String.AsNumber() - rework float_precision test, add tests for big floats and integers that can't be parsed with default precision, but can be parsed when setting higher precision in Config
cover big integers and floats, and different precisions, in e2e tests (e.g. in e2e_basic_test.go)