gojay

high performance JSON encoder/decoder with stream API for Golang
git clone git://git.lair.cx/gojay
Log | Files | Refs | README | LICENSE

encode_array_test.go (10417B)


      1 package gojay
      2 
      3 import (
      4 	"strings"
      5 	"testing"
      6 
      7 	"github.com/stretchr/testify/assert"
      8 )
      9 
     10 type TestEncodingArrStrings []string
     11 
     12 func (t TestEncodingArrStrings) MarshalJSONArray(enc *Encoder) {
     13 	for _, e := range t {
     14 		enc.AddString(e)
     15 	}
     16 }
     17 func (t TestEncodingArrStrings) IsNil() bool {
     18 	return len(t) == 0
     19 }
     20 
     21 type TestEncodingArr []*TestEncoding
     22 
     23 func (t TestEncodingArr) MarshalJSONArray(enc *Encoder) {
     24 	for _, e := range t {
     25 		enc.AddObject(e)
     26 	}
     27 }
     28 func (t TestEncodingArr) IsNil() bool {
     29 	return t == nil
     30 }
     31 
     32 type testEncodingArrInterfaces []interface{}
     33 
     34 func (t testEncodingArrInterfaces) MarshalJSONArray(enc *Encoder) {
     35 	for _, e := range t {
     36 		enc.AddInterface(e)
     37 	}
     38 }
     39 func (t testEncodingArrInterfaces) IsNil() bool {
     40 	return t == nil
     41 }
     42 
     43 func TestEncoderArrayMarshalAPI(t *testing.T) {
     44 	t.Run("array-objects", func(t *testing.T) {
     45 		v := &TestEncodingArr{
     46 			&TestEncoding{
     47 				test:          "hello world",
     48 				test2:         "漢字",
     49 				testInt:       1,
     50 				testBool:      true,
     51 				testInterface: 1,
     52 				sub: &SubObject{
     53 					test1:    10,
     54 					test2:    "hello world",
     55 					test3:    1.23543,
     56 					testBool: true,
     57 					sub: &SubObject{
     58 						test1:    10,
     59 						testBool: false,
     60 						test2:    "hello world",
     61 					},
     62 				},
     63 			},
     64 			&TestEncoding{
     65 				test:     "hello world",
     66 				test2:    "漢字",
     67 				testInt:  1,
     68 				testBool: true,
     69 				sub: &SubObject{
     70 					test1:    10,
     71 					test2:    "hello world",
     72 					test3:    1.23543,
     73 					testBool: true,
     74 					sub: &SubObject{
     75 						test1:    10,
     76 						testBool: false,
     77 						test2:    "hello world",
     78 					},
     79 				},
     80 			},
     81 			nil,
     82 		}
     83 		r, err := Marshal(v)
     84 		assert.Nil(t, err, "Error should be nil")
     85 		assert.Equal(
     86 			t,
     87 			`[{"test":"hello world","test2":"漢字","testInt":1,"testBool":true,`+
     88 				`"testArr":[],"testF64":0,"testF32":0,"testInterface":1,"sub":{"test1":10,"test2":"hello world",`+
     89 				`"test3":1.23543,"testBool":true,"sub":{"test1":10,"test2":"hello world",`+
     90 				`"test3":0,"testBool":false,"sub":{}}}},{"test":"hello world","test2":"漢字","testInt":1,`+
     91 				`"testBool":true,"testArr":[],"testF64":0,"testF32":0,"sub":{"test1":10,"test2":"hello world","test3":1.23543,`+
     92 				`"testBool":true,"sub":{"test1":10,"test2":"hello world","test3":0,"testBool":false,"sub":{}}}},{}]`,
     93 			string(r),
     94 			"Result of marshalling is different as the one expected")
     95 	})
     96 	t.Run("array-interfaces", func(t *testing.T) {
     97 		v := &testEncodingArrInterfaces{
     98 			1,
     99 			int64(1),
    100 			int32(1),
    101 			int16(1),
    102 			int8(1),
    103 			uint64(1),
    104 			uint32(1),
    105 			uint16(1),
    106 			uint8(1),
    107 			float64(1.31),
    108 			float32(1.31),
    109 			&TestEncodingArr{},
    110 			&TestEncodingArrStrings{},
    111 			true,
    112 			false,
    113 			"test",
    114 			&TestEncoding{
    115 				test:     "hello world",
    116 				test2:    "foobar",
    117 				testInt:  1,
    118 				testBool: true,
    119 			},
    120 		}
    121 		r, err := MarshalJSONArray(v)
    122 		assert.Nil(t, err, "Error should be nil")
    123 		assert.Equal(
    124 			t,
    125 			`[1,1,1,1,1,1,1,1,1.31,1.31,[],[],true,false,"test",{"test":"hello world","test2":"foobar","testInt":1,"testBool":true,"testArr":[],"testF64":0,"testF32":0,"sub":{}}]`,
    126 			string(r),
    127 			"Result of marshalling is different as the one expected")
    128 	})
    129 }
    130 
    131 func TestEncoderArrayEncodeAPI(t *testing.T) {
    132 	t.Run("array-interfaces", func(t *testing.T) {
    133 		v := &testEncodingArrInterfaces{
    134 			1,
    135 			int64(1),
    136 			int32(1),
    137 			int16(1),
    138 			int8(1),
    139 			uint64(1),
    140 			uint32(1),
    141 			uint16(1),
    142 			uint8(1),
    143 			float64(1.31),
    144 			// float32(1.31),
    145 			&TestEncodingArr{},
    146 			true,
    147 			"test",
    148 			&TestEncoding{
    149 				test:     "hello world",
    150 				test2:    "foobar",
    151 				testInt:  1,
    152 				testBool: true,
    153 			},
    154 		}
    155 		builder := &strings.Builder{}
    156 		enc := BorrowEncoder(builder)
    157 		defer enc.Release()
    158 		err := enc.EncodeArray(v)
    159 		assert.Nil(t, err, "Error should be nil")
    160 		assert.Equal(
    161 			t,
    162 			`[1,1,1,1,1,1,1,1,1.31,[],true,"test",{"test":"hello world","test2":"foobar","testInt":1,"testBool":true,"testArr":[],"testF64":0,"testF32":0,"sub":{}}]`,
    163 			builder.String(),
    164 			"Result of marshalling is different as the one expected")
    165 	})
    166 
    167 	t.Run("array-interfaces-write-error", func(t *testing.T) {
    168 		v := &testEncodingArrInterfaces{}
    169 		w := TestWriterError("")
    170 		enc := BorrowEncoder(w)
    171 		defer enc.Release()
    172 		err := enc.EncodeArray(v)
    173 		assert.NotNil(t, err, "err should not be nil")
    174 	})
    175 }
    176 
    177 // Array add with omit key tests
    178 
    179 type TestEncodingIntOmitEmpty []int
    180 
    181 func (t TestEncodingIntOmitEmpty) MarshalJSONArray(enc *Encoder) {
    182 	for _, e := range t {
    183 		enc.AddIntOmitEmpty(e)
    184 	}
    185 }
    186 func (t TestEncodingIntOmitEmpty) IsNil() bool {
    187 	return t == nil
    188 }
    189 
    190 type TestEncodingStringOmitEmpty []string
    191 
    192 func (t TestEncodingStringOmitEmpty) MarshalJSONArray(enc *Encoder) {
    193 	for _, e := range t {
    194 		enc.AddStringOmitEmpty(e)
    195 	}
    196 }
    197 func (t TestEncodingStringOmitEmpty) IsNil() bool {
    198 	return t == nil
    199 }
    200 
    201 type TestEncodingFloatOmitEmpty []float64
    202 
    203 func (t TestEncodingFloatOmitEmpty) MarshalJSONArray(enc *Encoder) {
    204 	for _, e := range t {
    205 		enc.AddFloatOmitEmpty(e)
    206 	}
    207 }
    208 func (t TestEncodingFloatOmitEmpty) IsNil() bool {
    209 	return t == nil
    210 }
    211 
    212 type TestEncodingFloat32OmitEmpty []float32
    213 
    214 func (t TestEncodingFloat32OmitEmpty) MarshalJSONArray(enc *Encoder) {
    215 	for _, e := range t {
    216 		enc.AddFloat32OmitEmpty(e)
    217 	}
    218 }
    219 func (t TestEncodingFloat32OmitEmpty) IsNil() bool {
    220 	return t == nil
    221 }
    222 
    223 type TestEncodingBoolOmitEmpty []bool
    224 
    225 func (t TestEncodingBoolOmitEmpty) MarshalJSONArray(enc *Encoder) {
    226 	for _, e := range t {
    227 		enc.AddBoolOmitEmpty(e)
    228 	}
    229 }
    230 func (t TestEncodingBoolOmitEmpty) IsNil() bool {
    231 	return len(t) == 0
    232 }
    233 
    234 type TestEncodingArrOmitEmpty []TestEncodingBoolOmitEmpty
    235 
    236 func (t TestEncodingArrOmitEmpty) MarshalJSONArray(enc *Encoder) {
    237 	for _, e := range t {
    238 		enc.AddArrayOmitEmpty(e)
    239 	}
    240 }
    241 func (t TestEncodingArrOmitEmpty) IsNil() bool {
    242 	return len(t) == 0
    243 }
    244 
    245 type TestObjEmpty struct {
    246 	empty bool
    247 }
    248 
    249 func (t *TestObjEmpty) MarshalJSONObject(enc *Encoder) {
    250 }
    251 
    252 func (t *TestObjEmpty) IsNil() bool {
    253 	return !t.empty
    254 }
    255 
    256 type TestEncodingObjOmitEmpty []*TestObjEmpty
    257 
    258 func (t TestEncodingObjOmitEmpty) MarshalJSONArray(enc *Encoder) {
    259 	for _, e := range t {
    260 		enc.AddObjectOmitEmpty(e)
    261 	}
    262 }
    263 func (t TestEncodingObjOmitEmpty) IsNil() bool {
    264 	return t == nil
    265 }
    266 
    267 func TestEncoderArrayOmitEmpty(t *testing.T) {
    268 	t.Run("omit-int", func(t *testing.T) {
    269 		intArr := TestEncodingIntOmitEmpty{0, 1, 0, 1}
    270 		b, err := Marshal(intArr)
    271 		assert.Nil(t, err, "err must be nil")
    272 		assert.Equal(t, `[1,1]`, string(b), "string(b) must be equal to `[1,1]`")
    273 	})
    274 	t.Run("omit-float", func(t *testing.T) {
    275 		floatArr := TestEncodingFloatOmitEmpty{0, 1, 0, 1}
    276 		b, err := Marshal(floatArr)
    277 		assert.Nil(t, err, "err must be nil")
    278 		assert.Equal(t, `[1,1]`, string(b), "string(b) must be equal to `[1,1]`")
    279 	})
    280 	t.Run("omit-float32", func(t *testing.T) {
    281 		float32Arr := TestEncodingFloat32OmitEmpty{0, 1, 0, 1}
    282 		b, err := Marshal(float32Arr)
    283 		assert.Nil(t, err, "err must be nil")
    284 		assert.Equal(t, `[1,1]`, string(b), "string(b) must be equal to `[1,1]`")
    285 	})
    286 	t.Run("omit-string", func(t *testing.T) {
    287 		stringArr := TestEncodingStringOmitEmpty{"", "hello", "", "world"}
    288 		b, err := Marshal(stringArr)
    289 		assert.Nil(t, err, "err must be nil")
    290 		assert.Equal(t, `["hello","world"]`, string(b), "string(b) must be equal to `[\"hello\",\"world\"]`")
    291 	})
    292 	t.Run("omit-bool", func(t *testing.T) {
    293 		boolArr := TestEncodingBoolOmitEmpty{false, true, false, true}
    294 		b, err := Marshal(boolArr)
    295 		assert.Nil(t, err, "err must be nil")
    296 		assert.Equal(t, `[true,true]`, string(b), "string(b) must be equal to `[true,true]`")
    297 	})
    298 	t.Run("omit-arr", func(t *testing.T) {
    299 		arrArr := TestEncodingArrOmitEmpty{TestEncodingBoolOmitEmpty{true}, nil, TestEncodingBoolOmitEmpty{true}, nil}
    300 		b, err := Marshal(arrArr)
    301 		assert.Nil(t, err, "err must be nil")
    302 		assert.Equal(t, `[[true],[true]]`, string(b), "string(b) must be equal to `[[true],[true]]`")
    303 	})
    304 	t.Run("omit-obj", func(t *testing.T) {
    305 		objArr := TestEncodingObjOmitEmpty{&TestObjEmpty{true}, &TestObjEmpty{false}, &TestObjEmpty{true}, &TestObjEmpty{false}}
    306 		b, err := Marshal(objArr)
    307 		assert.Nil(t, err, "err must be nil")
    308 		assert.Equal(t, `[{},{}]`, string(b), "string(b) must be equal to `[{},{}]`")
    309 	})
    310 }
    311 
    312 func TestEncoderArrErrors(t *testing.T) {
    313 	t.Run("add-interface-error", func(t *testing.T) {
    314 		builder := &strings.Builder{}
    315 		enc := NewEncoder(builder)
    316 		enc.AddInterface(nil)
    317 		assert.Nil(t, enc.err, "enc.Err() should not be nil")
    318 		assert.Equal(t, "", builder.String(), "builder.String() should not be ''")
    319 	})
    320 	t.Run("array-pooled-error", func(t *testing.T) {
    321 		v := &testEncodingArrInterfaces{}
    322 		enc := BorrowEncoder(nil)
    323 		enc.Release()
    324 		defer func() {
    325 			err := recover()
    326 			assert.NotNil(t, err, "err shouldnt be nil")
    327 			assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
    328 			assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
    329 		}()
    330 		_ = enc.EncodeArray(v)
    331 		assert.True(t, false, "should not be called as it should have panicked")
    332 	})
    333 }
    334 
    335 func TestEncoderArrayFunc(t *testing.T) {
    336 	var f EncodeArrayFunc
    337 	assert.True(t, f.IsNil())
    338 }
    339 
    340 func TestEncodeArrayNullEmpty(t *testing.T) {
    341 	var testCases = []struct {
    342 		name, baseJSON, expectedJSON string
    343 	}{
    344 		{
    345 			name:         "basic 1st elem",
    346 			baseJSON:     "[",
    347 			expectedJSON: `[null,["foo"]`,
    348 		},
    349 		{
    350 			name:         "basic 1st elem",
    351 			baseJSON:     `["test"`,
    352 			expectedJSON: `["test",null,["foo"]`,
    353 		},
    354 	}
    355 
    356 	for _, testCase := range testCases {
    357 		t.Run(testCase.name, func(t *testing.T) {
    358 			var b strings.Builder
    359 			var enc = NewEncoder(&b)
    360 			enc.writeString(testCase.baseJSON)
    361 			enc.AddArrayNullEmpty(&TestEncodingArrStrings{})
    362 			enc.ArrayNullEmpty(&TestEncodingArrStrings{"foo"})
    363 		})
    364 	}
    365 }
    366 
    367 func TestEncodeArrayKeyNullEmpty(t *testing.T) {
    368 	var testCases = []struct {
    369 		name, baseJSON, expectedJSON string
    370 	}{
    371 		{
    372 			name:         "basic 1st elem",
    373 			baseJSON:     "{",
    374 			expectedJSON: `{"foo":null,"bar":["foo"]`,
    375 		},
    376 		{
    377 			name:         "basic 1st elem",
    378 			baseJSON:     `{"test":"test"`,
    379 			expectedJSON: `{"test":"test","foo":null,"bar":["foo"]`,
    380 		},
    381 	}
    382 
    383 	for _, testCase := range testCases {
    384 		t.Run(testCase.name, func(t *testing.T) {
    385 			var b strings.Builder
    386 			var enc = NewEncoder(&b)
    387 			enc.writeString(testCase.baseJSON)
    388 			enc.AddArrayKeyNullEmpty("foo", &TestEncodingArrStrings{})
    389 			enc.ArrayKeyNullEmpty("bar", &TestEncodingArrStrings{"foo"})
    390 		})
    391 	}
    392 }