1
0
mirror of https://github.com/json-iterator/go.git synced 2025-06-15 22:50:24 +02:00

18 Commits

Author SHA1 Message Date
71ac16282d Merge pull request #635 from molon/fix-tests
encoding/json: Compatibility optimization
2022-09-16 07:37:16 +08:00
720cd423d0 encoding/json: use standard ES6 formatting for numbers during marshal
92b3e3651d
2022-09-15 22:10:44 +08:00
9b00d50ac0 Revert "std: float64/32 clean up e-09 to e-9"
This reverts commit 10b9ac0971.
2022-09-15 22:09:27 +08:00
ffc487c633 encoding/json: allow non-string type keys for (un-)marshal
ffbd31e9f7
2022-09-15 22:07:27 +08:00
10b9ac0971 std: float64/32 clean up e-09 to e-9 2022-09-15 21:13:32 +08:00
bf8b920736 Merge pull request #628 from HassanBaker/upgrade-stretchr
bumped stretchr to v1.8.0 to get rid of yaml v2 vuln
2022-08-05 15:01:11 +08:00
a7b8414362 bumped stretchr to v1.8.0 to get rid of yaml v2 vuln
Signed-off-by: Hassan Baker <me@hassanbaker.dev>
2022-08-04 17:25:33 +01:00
024077e996 fix go 1.18 compatibility 2021-09-11 10:17:26 +08:00
08b5e5796b notice incompatibility 2021-09-10 23:54:13 +08:00
c6661824eb Merge pull request #562 from runzhi/master
fix: invalid unicode while binary to string
2021-07-22 09:00:26 +08:00
3c55efb1a1 fix: invalid unicode while binary to string 2021-07-19 13:58:16 +08:00
e6b9536d36 Merge pull request #513 from AllenX2018/fix-issue-510
fix issue 510
2020-11-18 09:31:58 +08:00
a3465d79a9 fix issue 510 2020-11-17 17:37:55 +08:00
9b79a3e192 fix issue 508 (#512) 2020-11-14 09:45:31 +08:00
1779031cda fix issue 508 2020-11-13 15:58:42 +08:00
6821bec9fa jsoniter: Fix errors during reading integers from chunked io.Reader (#477)
This commit fixes bug in Iterator.assertInteger method if the next
conditions are met:
- Iterator reads data from `io.Reader`,
- expected value is `0` (zero)
- `Iterator.tail == Iterator.head + 1`
- `Iterator.tail < len(Iterator.buf)`
- value in the buffer after `Iterator.tail` is presented from the previous read and has '.' character.

Typical error which user cal see is:
- assertInteger: can not decode float as int, error found in #X byte of ...

Regression test added for checking the correct behaviour.

Fixes #476
2020-08-06 09:14:08 +08:00
9461257643 fixed null in number json tag string (#480) 2020-08-03 10:12:41 +08:00
5bce16d299 fix issue #469 2020-07-21 17:07:23 +08:00
16 changed files with 197 additions and 32 deletions

View File

@ -8,8 +8,6 @@
A high-performance 100% compatible drop-in replacement of "encoding/json" A high-performance 100% compatible drop-in replacement of "encoding/json"
You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
# Benchmark # Benchmark
![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) ![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png)

View File

@ -180,9 +180,9 @@ func readHex(iter *jsoniter.Iterator, b1, b2 byte) byte {
} }
ret *= 16 ret *= 16
if b2 >= '0' && b2 <= '9' { if b2 >= '0' && b2 <= '9' {
ret = b2 - '0' ret += b2 - '0'
} else if b2 >= 'a' && b2 <= 'f' { } else if b2 >= 'a' && b2 <= 'f' {
ret = b2 - 'a' + 10 ret += b2 - 'a' + 10
} else { } else {
iter.ReportError("read hex", "expects 0~9 or a~f, but found "+string([]byte{b2})) iter.ReportError("read hex", "expects 0~9 or a~f, but found "+string([]byte{b2}))
return 0 return 0

View File

@ -22,11 +22,11 @@ func TestBinaryAsStringCodec(t *testing.T) {
}) })
t.Run("non safe set", func(t *testing.T) { t.Run("non safe set", func(t *testing.T) {
should := require.New(t) should := require.New(t)
output, err := jsoniter.Marshal([]byte{1, 2, 3, 15}) output, err := jsoniter.Marshal([]byte{1, 2, 3, 23})
should.NoError(err) should.NoError(err)
should.Equal(`"\\x01\\x02\\x03\\x0f"`, string(output)) should.Equal(`"\\x01\\x02\\x03\\x17"`, string(output))
var val []byte var val []byte
should.NoError(jsoniter.Unmarshal(output, &val)) should.NoError(jsoniter.Unmarshal(output, &val))
should.Equal([]byte{1, 2, 3, 15}, val) should.Equal([]byte{1, 2, 3, 23}, val)
}) })
} }

4
go.mod
View File

@ -6,6 +6,6 @@ require (
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/google/gofuzz v1.0.0 github.com/google/gofuzz v1.0.0
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 github.com/modern-go/reflect2 v1.0.2
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.8.0
) )

15
go.sum
View File

@ -5,10 +5,17 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -288,6 +288,9 @@ non_decimal_loop:
return iter.readFloat64SlowPath() return iter.readFloat64SlowPath()
} }
value = (value << 3) + (value << 1) + uint64(ind) value = (value << 3) + (value << 1) + uint64(ind)
if value > maxFloat64 {
return iter.readFloat64SlowPath()
}
} }
} }
return iter.readFloat64SlowPath() return iter.readFloat64SlowPath()

View File

@ -9,6 +9,7 @@ var intDigits []int8
const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1
const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
const maxFloat64 = 1<<53 - 1
func init() { func init() {
intDigits = make([]int8, 256) intDigits = make([]int8, 256)
@ -339,7 +340,7 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
} }
func (iter *Iterator) assertInteger() { func (iter *Iterator) assertInteger() {
if iter.head < len(iter.buf) && iter.buf[iter.head] == '.' { if iter.head < iter.tail && iter.buf[iter.head] == '.' {
iter.ReportError("assertInteger", "can not decode float as int") iter.ReportError("assertInteger", "can not decode float as int")
} }
} }

View File

@ -5,7 +5,9 @@ package misc_tests
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"io"
"io/ioutil" "io/ioutil"
"math/rand"
"strconv" "strconv"
"testing" "testing"
@ -70,6 +72,95 @@ func Test_float_as_int(t *testing.T) {
should.NotNil(jsoniter.Unmarshal([]byte(`1.1`), &i)) should.NotNil(jsoniter.Unmarshal([]byte(`1.1`), &i))
} }
// chunkedData is io.Reader which returns random amount of data in range [1, chunkedData.chunkSize].
// It simulates chunked data on from HTTP server, which is commonly used by net/http package.
type chunkedData struct {
chunkSize int
data []byte
head int
}
// Read is implementation of the io.Reader which returns random amount of data in range [1, chunkedData.chunkSize].
func (c *chunkedData) Read(p []byte) (n int, err error) {
to := c.head + int(rand.Int31n(int32(c.chunkSize))+1)
// copy does not copy more data then p can consume
n = copy(p, c.data[c.head:to])
c.head = c.head + n
if c.head >= len(c.data) {
err = io.EOF
}
return n, err
}
// TestIterator_ReadInt_chunkedInput validates the behaviour of Iterator.ReadInt() method in where:
// - it reads data from io.Reader,
// - expected value is 0 (zero)
// - Iterator.tail == Iterator.head
// - Iterator.tail < len(Iterator.buf)
// - value in buffer after Iterator.tail is presented from previous read and has '.' character.
func TestIterator_ReadInt_chunkedInput(t *testing.T) {
should := require.New(t)
data := &chunkedData{
data: jsonFloatIntArray(t, 10),
}
// because this test is rely on randomness of chunkedData, we are doing multiple iterations to
// be sure, that we can hit a required case.
for data.chunkSize = 3; data.chunkSize <= len(data.data); data.chunkSize++ {
data.head = 0
iter := jsoniter.Parse(jsoniter.ConfigDefault, data, data.chunkSize)
i := 0
for iter.ReadArray() {
// every even item is float, let's just skip it.
if i%2 == 0 {
iter.Skip()
i++
continue
}
should.Zero(iter.ReadInt())
should.NoError(iter.Error)
i++
}
}
}
// jsonFloatIntArray generates JSON array where every
// - even item is float 0.1
// - odd item is integer 0
//
// [0.1, 0, 0.1, 0]
func jsonFloatIntArray(t *testing.T, numberOfItems int) []byte {
t.Helper()
numbers := make([]jsoniter.Any, numberOfItems)
for i := range numbers {
switch i % 2 {
case 0:
numbers[i] = jsoniter.WrapFloat64(0.1)
default:
numbers[i] = jsoniter.WrapInt64(0)
}
}
fixture, err := jsoniter.ConfigFastest.Marshal(numbers)
if err != nil {
panic(err)
}
b := &bytes.Buffer{}
require.NoError(
t,
json.Compact(b, fixture),
"json should be compactable",
)
return b.Bytes()
}
func Benchmark_jsoniter_encode_int(b *testing.B) { func Benchmark_jsoniter_encode_int(b *testing.B) {
stream := jsoniter.NewStream(jsoniter.ConfigDefault, ioutil.Discard, 64) stream := jsoniter.NewStream(jsoniter.ConfigDefault, ioutil.Discard, 64)
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {

View File

@ -42,6 +42,25 @@ func Test_marshal_invalid_json_raw_message(t *testing.T) {
should.Nil(aouterr) should.Nil(aouterr)
} }
func Test_marshal_nil_json_raw_message(t *testing.T) {
type A struct {
Nil1 jsoniter.RawMessage `json:"raw1"`
Nil2 json.RawMessage `json:"raw2"`
}
a := A{}
should := require.New(t)
aout, aouterr := jsoniter.Marshal(&a)
should.Equal(`{"raw1":null,"raw2":null}`, string(aout))
should.Nil(aouterr)
a.Nil1 = []byte(`Any`)
a.Nil2 = []byte(`Any`)
should.Nil(jsoniter.Unmarshal(aout, &a))
should.Nil(a.Nil1)
should.Nil(a.Nil2)
}
func Test_raw_message_memory_not_copied_issue(t *testing.T) { func Test_raw_message_memory_not_copied_issue(t *testing.T) {
jsonStream := `{"name":"xxxxx","bundle_id":"com.zonst.majiang","app_platform":"ios","app_category":"100103", "budget_day":1000,"bidding_min":1,"bidding_max":2,"bidding_type":"CPM", "freq":{"open":true,"type":"day","num":100},"speed":1, "targeting":{"vendor":{"open":true,"list":["zonst"]}, "geo_code":{"open":true,"list":["156110100"]},"app_category":{"open":true,"list":["100101"]}, "day_parting":{"open":true,"list":["100409","100410"]},"device_type":{"open":true,"list":["ipad"]}, "os_version":{"open":true,"list":[10]},"carrier":{"open":true,"list":["mobile"]}, "network":{"open":true,"list":["4G"]}},"url":{"tracking_imp_url":"http://www.baidu.com", "tracking_clk_url":"http://www.baidu.com","jump_url":"http://www.baidu.com","deep_link_url":"http://www.baidu.com"}}` jsonStream := `{"name":"xxxxx","bundle_id":"com.zonst.majiang","app_platform":"ios","app_category":"100103", "budget_day":1000,"bidding_min":1,"bidding_max":2,"bidding_type":"CPM", "freq":{"open":true,"type":"day","num":100},"speed":1, "targeting":{"vendor":{"open":true,"list":["zonst"]}, "geo_code":{"open":true,"list":["156110100"]},"app_category":{"open":true,"list":["100101"]}, "day_parting":{"open":true,"list":["100409","100410"]},"device_type":{"open":true,"list":["ipad"]}, "os_version":{"open":true,"list":[10]},"carrier":{"open":true,"list":["mobile"]}, "network":{"open":true,"list":["4G"]}},"url":{"tracking_imp_url":"http://www.baidu.com", "tracking_clk_url":"http://www.baidu.com","jump_url":"http://www.baidu.com","deep_link_url":"http://www.baidu.com"}}`
type IteratorObject struct { type IteratorObject struct {

View File

@ -65,7 +65,7 @@ func (iter *Iterator) ReadVal(obj interface{}) {
decoder := iter.cfg.getDecoderFromCache(cacheKey) decoder := iter.cfg.getDecoderFromCache(cacheKey)
if decoder == nil { if decoder == nil {
typ := reflect2.TypeOf(obj) typ := reflect2.TypeOf(obj)
if typ.Kind() != reflect.Ptr { if typ == nil || typ.Kind() != reflect.Ptr {
iter.ReportError("ReadVal", "can only unmarshal into pointer") iter.ReportError("ReadVal", "can only unmarshal into pointer")
return return
} }

View File

@ -33,11 +33,19 @@ type jsonRawMessageCodec struct {
} }
func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
*((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes()) if iter.ReadNil() {
*((*json.RawMessage)(ptr)) = nil
} else {
*((*json.RawMessage)(ptr)) = iter.SkipAndReturnBytes()
}
} }
func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
if *((*json.RawMessage)(ptr)) == nil {
stream.WriteNil()
} else {
stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
}
} }
func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
@ -48,11 +56,19 @@ type jsoniterRawMessageCodec struct {
} }
func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
*((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes()) if iter.ReadNil() {
*((*RawMessage)(ptr)) = nil
} else {
*((*RawMessage)(ptr)) = iter.SkipAndReturnBytes()
}
} }
func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
if *((*RawMessage)(ptr)) == nil {
stream.WriteNil()
} else {
stream.WriteRaw(string(*((*RawMessage)(ptr)))) stream.WriteRaw(string(*((*RawMessage)(ptr))))
}
} }
func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {

View File

@ -2,11 +2,12 @@ package jsoniter
import ( import (
"fmt" "fmt"
"github.com/modern-go/reflect2"
"io" "io"
"reflect" "reflect"
"sort" "sort"
"unsafe" "unsafe"
"github.com/modern-go/reflect2"
) )
func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder {
@ -106,6 +107,7 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
} }
} }
if typ.Kind() != reflect.String {
if typ == textMarshalerType { if typ == textMarshalerType {
return &directTextMarshalerEncoder{ return &directTextMarshalerEncoder{
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
@ -117,6 +119,7 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
} }
} }
}
switch typ.Kind() { switch typ.Kind() {
case reflect.String: case reflect.String:

View File

@ -1075,6 +1075,11 @@ type stringModeNumberDecoder struct {
} }
func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.WhatIsNext() == NilValue {
decoder.elemDecoder.Decode(ptr, iter)
return
}
c := iter.nextToken() c := iter.nextToken()
if c != '"' { if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))

View File

@ -27,6 +27,14 @@ func (stream *Stream) WriteFloat32(val float32) {
} }
} }
stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32) stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32)
if fmt == 'e' {
// clean up e-09 to e-9
n := len(stream.buf)
if n >= 4 && stream.buf[n-4] == 'e' && stream.buf[n-3] == '-' && stream.buf[n-2] == '0' {
stream.buf[n-2] = stream.buf[n-1]
stream.buf = stream.buf[:n-1]
}
}
} }
// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster // WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster
@ -76,6 +84,14 @@ func (stream *Stream) WriteFloat64(val float64) {
} }
} }
stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64) stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64)
if fmt == 'e' {
// clean up e-09 to e-9
n := len(stream.buf)
if n >= 4 && stream.buf[n-4] == 'e' && stream.buf[n-3] == '-' && stream.buf[n-2] == '0' {
stream.buf[n-2] = stream.buf[n-1]
stream.buf = stream.buf[:n-1]
}
}
} }
// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster // WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster

View File

@ -4,10 +4,11 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"strconv" "strconv"
"testing" "testing"
jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
) )
func Test_read_float(t *testing.T) { func Test_read_float(t *testing.T) {
@ -88,7 +89,7 @@ func Test_write_float32(t *testing.T) {
stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0) stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0)
stream.WriteFloat32(float32(0.0000001)) stream.WriteFloat32(float32(0.0000001))
should.Equal("1e-07", string(stream.Buffer())) should.Equal("1e-7", string(stream.Buffer()))
} }
func Test_write_float64(t *testing.T) { func Test_write_float64(t *testing.T) {
@ -125,5 +126,5 @@ func Test_write_float64(t *testing.T) {
stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0) stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0)
stream.WriteFloat64(float64(0.0000001)) stream.WriteFloat64(float64(0.0000001))
should.Equal("1e-07", string(stream.Buffer())) should.Equal("1e-7", string(stream.Buffer()))
} }

View File

@ -26,6 +26,11 @@ func init() {
Field int `json:"field"` Field int `json:"field"`
})(nil), })(nil),
input: `{"field": null}`, input: `{"field": null}`,
}, unmarshalCase{
ptr: (*struct {
Field int `json:"field,string"`
})(nil),
input: `{"field": null}`,
}, unmarshalCase{ }, unmarshalCase{
ptr: (*struct { ptr: (*struct {
ID int `json:"id"` ID int `json:"id"`