Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/francoispqt/gojay
Browse files Browse the repository at this point in the history
  • Loading branch information
francoispqt committed Apr 28, 2018
2 parents 66f6440 + 50e09b5 commit c5402e6
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 53 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ func main() {

Unsafe API has the same functions than the regular API, it only has `Unmarshal API` for now. It is unsafe because it makes assumptions on the quality of the given JSON.

If you are not sure if you're JSON is valid, don't use the Unsafe API.
If you are not sure if your JSON is valid, don't use the Unsafe API.

Also, the `Unsafe` API does not copy the buffer when using Unmarshal API, which, in case of string decoding, can lead to data corruption if a byte buffer is reused. Using the `Decode` API makes `Unsafe` API safer as the io.Reader relies on `copy` builtin method and `Decoder` will have its own internal buffer :)

Expand Down
24 changes: 12 additions & 12 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// If a JSON value is not appropriate for a given target type, or if a JSON number
// overflows the target type, UnmarshalArray skips that field and completes the unmarshaling as best it can.
func UnmarshalArray(data []byte, v UnmarshalerArray) error {
dec := BorrowDecoder(nil)
dec := borrowDecoder(nil, 0)
defer dec.Release()
dec.data = make([]byte, len(data))
copy(dec.data, data)
Expand All @@ -35,7 +35,7 @@ func UnmarshalArray(data []byte, v UnmarshalerArray) error {
// If a JSON value is not appropriate for a given target type, or if a JSON number
// overflows the target type, UnmarshalObject skips that field and completes the unmarshaling as best it can.
func UnmarshalObject(data []byte, v UnmarshalerObject) error {
dec := BorrowDecoder(nil)
dec := borrowDecoder(nil, 0)
defer dec.Release()
dec.data = make([]byte, len(data))
copy(dec.data, data)
Expand Down Expand Up @@ -73,53 +73,53 @@ func Unmarshal(data []byte, v interface{}) error {
var dec *Decoder
switch vt := v.(type) {
case *string:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeString(vt)
case *int:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt(vt)
case *int32:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt32(vt)
case *uint32:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint32(vt)
case *int64:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeInt64(vt)
case *uint64:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeUint64(vt)
case *float64:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeFloat64(vt)
case *bool:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = data
err = dec.decodeBool(vt)
case UnmarshalerObject:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = make([]byte, len(data))
copy(dec.data, data)
_, err = dec.decodeObject(vt)
case UnmarshalerArray:
dec = BorrowDecoder(nil)
dec = borrowDecoder(nil, 0)
dec.length = len(data)
dec.data = make([]byte, len(data))
copy(dec.data, data)
Expand Down
4 changes: 2 additions & 2 deletions decode_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (dec *Decoder) skipArray() (int, error) {
var arraysOpen = 1
var arraysClosed = 0
// var stringOpen byte = 0
for j := dec.cursor; j < dec.length; j++ {
for j := dec.cursor; j < dec.length || dec.read(); j++ {
switch dec.data[j] {
case ']':
arraysClosed++
Expand All @@ -94,7 +94,7 @@ func (dec *Decoder) skipArray() (int, error) {
// loop backward and count how many anti slash found
// to see if string is effectively escaped
ct := 1
for i := j; i > 0; i-- {
for i := j - 2; i > 0; i-- {
if dec.data[i] != '\\' {
break
}
Expand Down
35 changes: 35 additions & 0 deletions decode_array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,38 @@ func TestDecoderSliceDecoderAPIError(t *testing.T) {
assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
assert.IsType(t, InvalidJSONError(""), err, "err message must be 'Invalid JSON'")
}

func TestSkipArray(t *testing.T) {
testCases := []struct {
json string
expectations func(*testing.T, int, error)
}{
{
json: `"testbasic"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"testbasic"]`), i)
assert.Nil(t, err)
},
},
{
json: `"test \\\\\" escape"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \\\\\" escape"]`), i)
assert.Nil(t, err)
},
},
{
json: `"test \\\\\\"]`,
expectations: func(t *testing.T, i int, err error) {
assert.Equal(t, len(`"test \\\\\\"]`), i)
assert.Nil(t, err)
},
},
}

for _, test := range testCases {
dec := NewDecoder(strings.NewReader(test.json))
i, err := dec.skipArray()
test.expectations(t, i, err)
}
}
2 changes: 1 addition & 1 deletion decode_number.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ func (dec *Decoder) atoi32(start, end int) int32 {
for i := start + 1; i < end; i++ {
intv := int32(digits[dec.data[i]])
if val > maxInt32toMultiply {
dec.err = InvalidTypeError("Overflows int321")
dec.err = InvalidTypeError("Overflows int32")
return 0
}
val = (val << 3) + (val << 1)
Expand Down
67 changes: 51 additions & 16 deletions decode_number_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ func TestDecoderIntBasic(t *testing.T) {
assert.Equal(t, 124, v, "v must be equal to 124")
}
func TestDecoderIntNegative(t *testing.T) {
json := []byte(`-124`)
json := []byte(` -124 `)
var v int
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, -124, v, "v must be equal to -124")
}
func TestDecoderIntNegativeError(t *testing.T) {
json := []byte(` -12x4 `)
var v int
err := Unmarshal(json, &v)
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderIntNull(t *testing.T) {
json := []byte(`null`)
var v int
Expand Down Expand Up @@ -56,6 +63,20 @@ func TestDecoderIntOverfow(t *testing.T) {
assert.NotNil(t, err, "Err must not be nil as int is overflowing")
assert.Equal(t, 0, v, "v must be equal to 0")
}
func TestDecoderIntOverfow2(t *testing.T) {
json := []byte(`92233720368547758089 `)
var v int
err := Unmarshal(json, &v)
assert.NotNil(t, err, "Err must not be nil as int is overflowing")
assert.Equal(t, 0, v, "v must be equal to 0")
}
func TestDecoderIntOverfow3(t *testing.T) {
json := []byte(`92233720368547758089 `)
var v int
err := Unmarshal(json, &v)
assert.NotNil(t, err, "Err must not be nil as int is overflowing")
assert.Equal(t, 0, v, "v must be equal to 0")
}
func TestDecoderIntPoolError(t *testing.T) {
result := int(1)
dec := NewDecoder(nil)
Expand All @@ -68,13 +89,6 @@ func TestDecoderIntPoolError(t *testing.T) {
_ = dec.DecodeInt(&result)
assert.True(t, false, "should not be called as decoder should have panicked")
}
func TestDecoderIntOverfow2(t *testing.T) {
json := []byte(`92233720368547758089`)
var v int
err := Unmarshal(json, &v)
assert.NotNil(t, err, "Err must not be nil as int is overflowing")
assert.Equal(t, 0, v, "v must be equal to 0")
}
func TestDecoderInttDecoderAPI(t *testing.T) {
var v int
dec := NewDecoder(strings.NewReader(`33`))
Expand All @@ -92,12 +106,19 @@ func TestDecoderInt32Basic(t *testing.T) {
assert.Equal(t, int32(124), v, "v must be equal to 124")
}
func TestDecoderInt32Negative(t *testing.T) {
json := []byte(`-124`)
json := []byte(`-124 `)
var v int32
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, int32(-124), v, "v must be equal to -124")
}
func TestDecoderInt32NegativeError(t *testing.T) {
json := []byte(`-12x4 `)
var v int32
err := Unmarshal(json, &v)
assert.NotNil(t, err, "Err must be nil")
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderInt32Null(t *testing.T) {
json := []byte(`null`)
var v int32
Expand Down Expand Up @@ -127,7 +148,7 @@ func TestDecoderInt32Big(t *testing.T) {
assert.Equal(t, int32(2147483647), v, "int32 must be equal to 2147483647")
}
func TestDecoderInt32Overflow(t *testing.T) {
json := []byte(`2147483648`)
json := []byte(` 2147483648`)
var v int32
err := Unmarshal(json, &v)
assert.NotNil(t, err, "err must not be nil as int32 overflows")
Expand Down Expand Up @@ -162,7 +183,7 @@ func TestDecoderInt32tDecoderAPI(t *testing.T) {
}

func TestDecoderUint32Basic(t *testing.T) {
json := []byte(`124`)
json := []byte(`124 `)
var v uint32
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
Expand Down Expand Up @@ -190,7 +211,7 @@ func TestDecoderUint32InvalidJSON(t *testing.T) {
assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
}
func TestDecoderUint32Big(t *testing.T) {
json := []byte(`4294967295`)
json := []byte(`4294967295 `)
var v uint32
err := Unmarshal(json, &v)
assert.Nil(t, err, "err must not be nil as uint32 does not overflow")
Expand Down Expand Up @@ -233,7 +254,7 @@ func TestDecoderUint32tDecoderAPI(t *testing.T) {
}

func TestDecoderInt64Basic(t *testing.T) {
json := []byte(`124`)
json := []byte(`124 `)
var v int64
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
Expand Down Expand Up @@ -309,7 +330,7 @@ func TestDecoderInt64tDecoderAPI(t *testing.T) {
assert.Equal(t, int64(33), v, "v must be equal to 33")
}
func TestDecoderUint64Basic(t *testing.T) {
json := []byte(`124`)
json := []byte(` 124 `)
var v uint64
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
Expand Down Expand Up @@ -378,15 +399,29 @@ func TestDecoderUint64tDecoderAPI(t *testing.T) {
assert.Equal(t, uint64(33), v, "v must be equal to 33")
}
func TestDecoderFloatBasic(t *testing.T) {
json := []byte(`100.11`)
json := []byte(`100.11 `)
var v float64
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, 100.11, v, "v must be equal to 100.11")
}
func TestDecoderFloatBasic2(t *testing.T) {
json := []byte(` 100.11 `)
var v float64
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, 100.11, v, "v must be equal to 100.11")
}
func TestDecoderFloatBasic3(t *testing.T) {
json := []byte(` 100 `)
var v float64
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
assert.Equal(t, float64(100), v, "v must be equal to 100.11")
}

func TestDecoderFloatBig(t *testing.T) {
json := []byte(`89899843.3493493`)
json := []byte(`89899843.3493493 `)
var v float64
err := Unmarshal(json, &v)
assert.Nil(t, err, "Err must be nil")
Expand Down
3 changes: 0 additions & 3 deletions decode_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ func (dec *Decoder) DecodeObject(j UnmarshalerObject) error {
return err
}
func (dec *Decoder) decodeObject(j UnmarshalerObject) (int, error) {
if dec.isPooled == 1 {
panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
}
keys := j.NKeys()
for ; dec.cursor < dec.length || dec.read(); dec.cursor++ {
switch dec.data[dec.cursor] {
Expand Down
9 changes: 7 additions & 2 deletions decode_object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,13 @@ func TestDecodeObjectNull(t *testing.T) {
var jsonComplex = []byte(`{
"test": "{\"test\":\"1\",\"test1\":2}",
"test2\\n": "\\\\\\\\\\\n",
"testArrSkip": ["testString with escaped \" quotes"],
"testArrSkip": ["testString with escaped \\\" quotes"],
"testSkipString": "skip \\ string with \\n escaped char \" ",
"testSkipObject": {
"testSkipSubObj": {
"test": "test"
}
},
"testSkipNumber": 123.23,
"testBool": true,
"testSub": {
Expand Down Expand Up @@ -210,7 +215,7 @@ func TestDecodeObjComplex(t *testing.T) {
result := jsonObjectComplex{}
err := UnmarshalObject(jsonComplex, &result)
assert.NotNil(t, err, "err should not be as invalid type as been encountered nil")
assert.Equal(t, `Cannot unmarshal to struct, wrong char '"' found at pos 460`, err.Error(), "err should not be as invalid type as been encountered nil")
assert.Equal(t, `Cannot unmarshal to struct, wrong char '"' found at pos 531`, err.Error(), "err should not be as invalid type as been encountered nil")
assert.Equal(t, `{"test":"1","test1":2}`, result.Test, "result.Test is not expected value")
assert.Equal(t, `\\\\\\n`, result.Test2, "result.Test2 is not expected value")
assert.Equal(t, 1, result.Test3, "result.test3 is not expected value")
Expand Down
13 changes: 13 additions & 0 deletions decode_stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,19 @@ func TestStreamDecodingDeadline(t *testing.T) {
assert.Equal(t, now.String(), dec.deadline.String(), "dec.now and now should be equal")
}

func TestStreamDecodingDeadlineNotSet(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
_, isSet := dec.Deadline()
assert.Equal(t, false, isSet, "isSet should be false as deadline is not set")
}

// this test is only relevant for coverage
func TestStreamDecodingValue(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
v := dec.Value("")
assert.Nil(t, v, "v should be nil")
}

func TestStreamDecodingErrNotSet(t *testing.T) {
dec := Stream.NewDecoder(&StreamReader{})
assert.Nil(t, dec.Err(), "dec.Err should be nim")
Expand Down
7 changes: 7 additions & 0 deletions encode.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package gojay

import (
"fmt"
"reflect"
)

// MarshalObject returns the JSON encoding of v.
//
// It takes a struct implementing Marshaler to a JSON slice of byte
Expand Down Expand Up @@ -162,6 +167,8 @@ func Marshal(v interface{}) ([]byte, error) {
enc := BorrowEncoder()
defer enc.Release()
return enc.encodeFloat(float64(vt))
default:
err = InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, reflect.TypeOf(vt).String()))
}
return b, err
}
Expand Down
Loading

0 comments on commit c5402e6

Please sign in to comment.