gojay

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

encode_object_test.go (23932B)


      1 package gojay
      2 
      3 import (
      4 	"strings"
      5 	"testing"
      6 	"time"
      7 
      8 	"github.com/stretchr/testify/assert"
      9 )
     10 
     11 type testObjectWithUnknownType struct {
     12 	unknownType struct{}
     13 }
     14 
     15 func (t *testObjectWithUnknownType) IsNil() bool {
     16 	return t == nil
     17 }
     18 
     19 func (t *testObjectWithUnknownType) MarshalJSONObject(enc *Encoder) {
     20 	enc.AddInterfaceKey("unknownType", t.unknownType)
     21 }
     22 
     23 type TestEncoding struct {
     24 	test          string
     25 	test2         string
     26 	testInt       int
     27 	testBool      bool
     28 	testF32       float32
     29 	testF64       float64
     30 	testInterface interface{}
     31 	testArr       TestEncodingArr
     32 	sub           *SubObject
     33 }
     34 
     35 func (t *TestEncoding) IsNil() bool {
     36 	return t == nil
     37 }
     38 
     39 func (t *TestEncoding) MarshalJSONObject(enc *Encoder) {
     40 	enc.AddStringKey("test", t.test)
     41 	enc.AddStringKey("test2", t.test2)
     42 	enc.AddIntKey("testInt", t.testInt)
     43 	enc.AddBoolKey("testBool", t.testBool)
     44 	enc.AddInterfaceKey("testArr", t.testArr)
     45 	enc.AddInterfaceKey("testF64", t.testF64)
     46 	enc.AddInterfaceKey("testF32", t.testF32)
     47 	enc.AddInterfaceKey("testInterface", t.testInterface)
     48 	enc.AddInterfaceKey("sub", t.sub)
     49 }
     50 
     51 type SubObject struct {
     52 	test1    int
     53 	test2    string
     54 	test3    float64
     55 	testBool bool
     56 	sub      *SubObject
     57 }
     58 
     59 func (t *SubObject) IsNil() bool {
     60 	return t == nil
     61 }
     62 
     63 func (t *SubObject) MarshalJSONObject(enc *Encoder) {
     64 	enc.AddIntKey("test1", t.test1)
     65 	enc.AddStringKey("test2", t.test2)
     66 	enc.AddFloatKey("test3", t.test3)
     67 	enc.AddBoolKey("testBool", t.testBool)
     68 	enc.AddObjectKey("sub", t.sub)
     69 }
     70 
     71 type testEncodingObjInterfaces struct {
     72 	interfaceVal interface{}
     73 }
     74 
     75 func (t *testEncodingObjInterfaces) IsNil() bool {
     76 	return t == nil
     77 }
     78 
     79 func (t *testEncodingObjInterfaces) MarshalJSONObject(enc *Encoder) {
     80 	enc.AddInterfaceKey("interfaceVal", t.interfaceVal)
     81 }
     82 
     83 func TestEncoderObjectEncodeAPI(t *testing.T) {
     84 	t.Run("encode-basic", func(t *testing.T) {
     85 		builder := &strings.Builder{}
     86 		enc := NewEncoder(builder)
     87 		err := enc.EncodeObject(&testObject{
     88 			"漢字", nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil,
     89 			1, nil, 1, nil, 1.1, nil, 1.1, nil, true, nil,
     90 			&testObject{}, testSliceInts{}, interface{}("test"),
     91 		})
     92 		assert.Nil(t, err, "Error should be nil")
     93 		assert.Equal(
     94 			t,
     95 			`{"testStr":"漢字","testInt":1,"testInt64":1,"testInt32":1,"testInt16":1,"testInt8":1,"testUint64":1,"testUint32":1,"testUint16":1,"testUint8":1,"testFloat64":1.1,"testFloat32":1.1,"testBool":true}`,
     96 			builder.String(),
     97 			"Result of marshalling is different as the one expected",
     98 		)
     99 	})
    100 }
    101 
    102 func TestEncoderObjectMarshalAPI(t *testing.T) {
    103 	t.Run("marshal-basic", func(t *testing.T) {
    104 		r, err := Marshal(&testObject{
    105 			"漢字", nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1, nil, 1,
    106 			nil, 1, nil, 1, nil, 1.1, nil, 1.1, nil, true, nil,
    107 			&testObject{}, testSliceInts{}, []interface{}{"h", "o", "l", "a"},
    108 		})
    109 		assert.Nil(t, err, "Error should be nil")
    110 		assert.Equal(
    111 			t,
    112 			`{"testStr":"漢字","testInt":1,"testInt64":1,"testInt32":1,"testInt16":1,"testInt8":1,"testUint64":1,"testUint32":1,"testUint16":1,"testUint8":1,"testFloat64":1.1,"testFloat32":1.1,"testBool":true}`,
    113 			string(r),
    114 			"Result of marshalling is different as the one expected",
    115 		)
    116 	})
    117 
    118 	t.Run("marshal-complex", func(t *testing.T) {
    119 		v := &TestEncoding{
    120 			test:          "hello world",
    121 			test2:         "foobar",
    122 			testInt:       1,
    123 			testBool:      true,
    124 			testF32:       120.53,
    125 			testF64:       120.15,
    126 			testInterface: true,
    127 			testArr: TestEncodingArr{
    128 				&TestEncoding{
    129 					test: "1",
    130 				},
    131 			},
    132 			sub: &SubObject{
    133 				test1:    10,
    134 				test2:    "hello world",
    135 				test3:    1.23543,
    136 				testBool: true,
    137 				sub: &SubObject{
    138 					test1:    10,
    139 					testBool: false,
    140 					test2:    "hello world",
    141 				},
    142 			},
    143 		}
    144 		r, err := MarshalJSONObject(v)
    145 		assert.Nil(t, err, "Error should be nil")
    146 		assert.Equal(
    147 			t,
    148 			`{"test":"hello world","test2":"foobar","testInt":1,"testBool":true,"testArr":[{"test":"1","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}],"testF64":120.15,"testF32":120.53,"testInterface":true,"sub":{"test1":10,"test2":"hello world","test3":1.23543,"testBool":true,"sub":{"test1":10,"test2":"hello world","test3":0,"testBool":false,"sub":{}}}}`,
    149 			string(r),
    150 			"Result of marshalling is different as the one expected",
    151 		)
    152 	})
    153 
    154 	t.Run("marshal-interface-string", func(t *testing.T) {
    155 		v := testEncodingObjInterfaces{"string"}
    156 		r, err := Marshal(&v)
    157 		assert.Nil(t, err, "Error should be nil")
    158 		assert.Equal(
    159 			t,
    160 			`{"interfaceVal":"string"}`,
    161 			string(r),
    162 			"Result of marshalling is different as the one expected")
    163 	})
    164 	t.Run("marshal-interface-int", func(t *testing.T) {
    165 		v := testEncodingObjInterfaces{1}
    166 		r, err := Marshal(&v)
    167 		assert.Nil(t, err, "Error should be nil")
    168 		assert.Equal(
    169 			t,
    170 			`{"interfaceVal":1}`,
    171 			string(r),
    172 			"Result of marshalling is different as the one expected")
    173 	})
    174 	t.Run("marshal-interface-int64", func(t *testing.T) {
    175 		v := testEncodingObjInterfaces{int64(1)}
    176 		r, err := Marshal(&v)
    177 		assert.Nil(t, err, "Error should be nil")
    178 		assert.Equal(
    179 			t,
    180 			`{"interfaceVal":1}`,
    181 			string(r),
    182 			"Result of marshalling is different as the one expected")
    183 	})
    184 	t.Run("marshal-interface-int32", func(t *testing.T) {
    185 		v := testEncodingObjInterfaces{int32(1)}
    186 		r, err := Marshal(&v)
    187 		assert.Nil(t, err, "Error should be nil")
    188 		assert.Equal(
    189 			t,
    190 			`{"interfaceVal":1}`,
    191 			string(r),
    192 			"Result of marshalling is different as the one expected")
    193 	})
    194 	t.Run("marshal-interface-int16", func(t *testing.T) {
    195 		v := testEncodingObjInterfaces{int16(1)}
    196 		r, err := Marshal(&v)
    197 		assert.Nil(t, err, "Error should be nil")
    198 		assert.Equal(
    199 			t,
    200 			`{"interfaceVal":1}`,
    201 			string(r),
    202 			"Result of marshalling is different as the one expected")
    203 	})
    204 	t.Run("marshal-interface-int8", func(t *testing.T) {
    205 		v := testEncodingObjInterfaces{int8(1)}
    206 		r, err := Marshal(&v)
    207 		assert.Nil(t, err, "Error should be nil")
    208 		assert.Equal(
    209 			t,
    210 			`{"interfaceVal":1}`,
    211 			string(r),
    212 			"Result of marshalling is different as the one expected")
    213 	})
    214 	t.Run("marshal-interface-uint64", func(t *testing.T) {
    215 		v := testEncodingObjInterfaces{uint64(1)}
    216 		r, err := Marshal(&v)
    217 		assert.Nil(t, err, "Error should be nil")
    218 		assert.Equal(
    219 			t,
    220 			`{"interfaceVal":1}`,
    221 			string(r),
    222 			"Result of marshalling is different as the one expected")
    223 	})
    224 	t.Run("marshal-interface-uint32", func(t *testing.T) {
    225 		v := testEncodingObjInterfaces{uint32(1)}
    226 		r, err := Marshal(&v)
    227 		assert.Nil(t, err, "Error should be nil")
    228 		assert.Equal(
    229 			t,
    230 			`{"interfaceVal":1}`,
    231 			string(r),
    232 			"Result of marshalling is different as the one expected")
    233 	})
    234 	t.Run("marshal-interface-uint16", func(t *testing.T) {
    235 		v := testEncodingObjInterfaces{uint16(1)}
    236 		r, err := Marshal(&v)
    237 		assert.Nil(t, err, "Error should be nil")
    238 		assert.Equal(
    239 			t,
    240 			`{"interfaceVal":1}`,
    241 			string(r),
    242 			"Result of marshalling is different as the one expected")
    243 	})
    244 	t.Run("marshal-interface-uint8", func(t *testing.T) {
    245 		v := testEncodingObjInterfaces{uint8(1)}
    246 		r, err := Marshal(&v)
    247 		assert.Nil(t, err, "Error should be nil")
    248 		assert.Equal(
    249 			t,
    250 			`{"interfaceVal":1}`,
    251 			string(r),
    252 			"Result of marshalling is different as the one expected")
    253 	})
    254 	t.Run("marshal-interface-float64", func(t *testing.T) {
    255 		v := testEncodingObjInterfaces{float64(1.1)}
    256 		r, err := Marshal(&v)
    257 		assert.Nil(t, err, "Error should be nil")
    258 		assert.Equal(
    259 			t,
    260 			`{"interfaceVal":1.1}`,
    261 			string(r),
    262 			"Result of marshalling is different as the one expected")
    263 	})
    264 	t.Run("marshal-interface-float32", func(t *testing.T) {
    265 		v := testEncodingObjInterfaces{float32(1.1)}
    266 		r, err := Marshal(&v)
    267 		assert.Nil(t, err, "Error should be nil")
    268 		assert.Equal(
    269 			t,
    270 			`{"interfaceVal":1.1}`,
    271 			string(r),
    272 			"Result of marshalling is different as the one expected")
    273 	})
    274 	t.Run("marshal-object-func", func(t *testing.T) {
    275 		f := EncodeObjectFunc(func(enc *Encoder) {
    276 			enc.AddStringKeyOmitEmpty("test", "test")
    277 		})
    278 		r, err := Marshal(f)
    279 		assert.Nil(t, err, "Error should be nil")
    280 		assert.Equal(
    281 			t,
    282 			`{"test":"test"}`,
    283 			string(r),
    284 			"Result of marshalling is different as the one expected")
    285 	})
    286 	t.Run("marshal-any-object", func(t *testing.T) {
    287 		test := struct {
    288 			Foo string
    289 			Bar int
    290 		}{
    291 			"test",
    292 			100,
    293 		}
    294 		r, err := MarshalAny(test)
    295 		assert.Nil(t, err, "Error should be nil")
    296 		assert.Equal(
    297 			t,
    298 			`{"Foo":"test","Bar":100}`,
    299 			string(r),
    300 			"Result of marshalling is different as the one expected")
    301 	})
    302 }
    303 
    304 type TestObectOmitEmpty struct {
    305 	nonNiler           int
    306 	testInt            int
    307 	testFloat          float64
    308 	testFloat32        float32
    309 	testString         string
    310 	testBool           bool
    311 	testObectOmitEmpty *TestObectOmitEmpty
    312 	testObect          *TestObectOmitEmpty
    313 }
    314 
    315 func (t *TestObectOmitEmpty) IsNil() bool {
    316 	return t == nil
    317 }
    318 
    319 func (t *TestObectOmitEmpty) MarshalJSONObject(enc *Encoder) {
    320 	enc.AddIntKeyOmitEmpty("testInt", t.testInt)
    321 	enc.AddIntKeyOmitEmpty("testIntNotEmpty", 1)
    322 	enc.AddFloatKeyOmitEmpty("testFloat", t.testFloat)
    323 	enc.AddFloatKeyOmitEmpty("testFloatNotEmpty", 1.1)
    324 	enc.AddFloat32KeyOmitEmpty("testFloat32", t.testFloat32)
    325 	enc.AddFloat32KeyOmitEmpty("testFloat32NotEmpty", 1.1)
    326 	enc.AddStringKeyOmitEmpty("testString", t.testString)
    327 	enc.AddStringKeyOmitEmpty("testStringNotEmpty", "foo")
    328 	enc.AddBoolKeyOmitEmpty("testBool", t.testBool)
    329 	enc.AddBoolKeyOmitEmpty("testBoolNotEmpty", true)
    330 	enc.AddObjectKeyOmitEmpty("testObect", t.testObect)
    331 	enc.AddObjectKeyOmitEmpty("testObectOmitEmpty", t.testObectOmitEmpty)
    332 	enc.AddArrayKeyOmitEmpty("testArrayOmitEmpty", TestEncodingArrStrings{})
    333 	enc.AddArrayKeyOmitEmpty("testArray", TestEncodingArrStrings{"foo"})
    334 }
    335 
    336 type TestObectOmitEmptyInterface struct{}
    337 
    338 func (t *TestObectOmitEmptyInterface) IsNil() bool {
    339 	return t == nil
    340 }
    341 
    342 func (t *TestObectOmitEmptyInterface) MarshalJSONObject(enc *Encoder) {
    343 	enc.AddInterfaceKeyOmitEmpty("testInt", 0)
    344 	enc.AddInterfaceKeyOmitEmpty("testInt64", int64(0))
    345 	enc.AddInterfaceKeyOmitEmpty("testInt32", int32(0))
    346 	enc.AddInterfaceKeyOmitEmpty("testInt16", int16(0))
    347 	enc.AddInterfaceKeyOmitEmpty("testInt8", int8(0))
    348 	enc.AddInterfaceKeyOmitEmpty("testUint8", uint8(0))
    349 	enc.AddInterfaceKeyOmitEmpty("testUint16", uint16(0))
    350 	enc.AddInterfaceKeyOmitEmpty("testUint32", uint32(0))
    351 	enc.AddInterfaceKeyOmitEmpty("testUint64", uint64(0))
    352 	enc.AddInterfaceKeyOmitEmpty("testIntNotEmpty", 1)
    353 	enc.AddInterfaceKeyOmitEmpty("testFloat", 0)
    354 	enc.AddInterfaceKeyOmitEmpty("testFloatNotEmpty", 1.1)
    355 	enc.AddInterfaceKeyOmitEmpty("testFloat32", float32(0))
    356 	enc.AddInterfaceKeyOmitEmpty("testFloat32NotEmpty", float32(1.1))
    357 	enc.AddInterfaceKeyOmitEmpty("testString", "")
    358 	enc.AddInterfaceKeyOmitEmpty("testStringNotEmpty", "foo")
    359 	enc.AddInterfaceKeyOmitEmpty("testBool", false)
    360 	enc.AddInterfaceKeyOmitEmpty("testBoolNotEmpty", true)
    361 	enc.AddInterfaceKeyOmitEmpty("testObectOmitEmpty", nil)
    362 	enc.AddInterfaceKeyOmitEmpty("testObect", &TestEncoding{})
    363 	enc.AddInterfaceKeyOmitEmpty("testArr", &TestEncodingArrStrings{})
    364 }
    365 
    366 func TestEncoderObjectOmitEmpty(t *testing.T) {
    367 	t.Run("encoder-omit-empty-all-types", func(t *testing.T) {
    368 		v := &TestObectOmitEmpty{
    369 			nonNiler:  1,
    370 			testInt:   0,
    371 			testObect: &TestObectOmitEmpty{testInt: 1},
    372 		}
    373 		r, err := MarshalJSONObject(v)
    374 		assert.Nil(t, err, "Error should be nil")
    375 		assert.Equal(
    376 			t,
    377 			`{"testIntNotEmpty":1,"testFloatNotEmpty":1.1,"testFloat32NotEmpty":1.1,"testStringNotEmpty":"foo","testBoolNotEmpty":true,"testObect":{"testInt":1,"testIntNotEmpty":1,"testFloatNotEmpty":1.1,"testFloat32NotEmpty":1.1,"testStringNotEmpty":"foo","testBoolNotEmpty":true,"testArray":["foo"]},"testArray":["foo"]}`,
    378 			string(r),
    379 			"Result of marshalling is different as the one expected",
    380 		)
    381 	})
    382 
    383 	t.Run("encoder-omit-empty-interface", func(t *testing.T) {
    384 		v := &TestObectOmitEmptyInterface{}
    385 		r, err := MarshalJSONObject(v)
    386 		assert.Nil(t, err, "Error should be nil")
    387 		assert.Equal(
    388 			t,
    389 			`{"testIntNotEmpty":1,"testFloatNotEmpty":1.1,"testFloat32NotEmpty":1.1,"testStringNotEmpty":"foo","testBoolNotEmpty":true,"testObect":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}}`,
    390 			string(r),
    391 			"Result of marshalling is different as the one expected",
    392 		)
    393 	})
    394 }
    395 
    396 func TestEncoderObjectEncodeAPIError(t *testing.T) {
    397 	t.Run("interface-key-error", func(t *testing.T) {
    398 		builder := &strings.Builder{}
    399 		enc := NewEncoder(builder)
    400 		err := enc.EncodeObject(&testObjectWithUnknownType{struct{}{}})
    401 		assert.NotNil(t, err, "Error should not be nil")
    402 		assert.Equal(t, "Invalid type struct {} provided to Marshal", err.Error(), "err.Error() should be 'Invalid type struct {} provided to Marshal'")
    403 	})
    404 	t.Run("write-error", func(t *testing.T) {
    405 		w := TestWriterError("")
    406 		enc := NewEncoder(w)
    407 		err := enc.EncodeObject(&testObject{})
    408 		assert.NotNil(t, err, "Error should not be nil")
    409 		assert.Equal(t, "Test Error", err.Error(), "err.Error() should be 'Test Error'")
    410 	})
    411 	t.Run("interface-error", func(t *testing.T) {
    412 		builder := &strings.Builder{}
    413 		enc := NewEncoder(builder)
    414 		enc.AddInterfaceKeyOmitEmpty("test", struct{}{})
    415 		assert.NotNil(t, enc.err, "enc.Err() should not be nil")
    416 	})
    417 	t.Run("pool-error", func(t *testing.T) {
    418 		v := &TestEncoding{}
    419 		enc := BorrowEncoder(nil)
    420 		enc.isPooled = 1
    421 		defer func() {
    422 			err := recover()
    423 			assert.NotNil(t, err, "err shouldnt be nil")
    424 			assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
    425 			assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
    426 		}()
    427 		_ = enc.EncodeObject(v)
    428 		assert.True(t, false, "should not be called as it should have panicked")
    429 	})
    430 }
    431 
    432 func TestEncoderObjectKeyNullEmpty(t *testing.T) {
    433 	var testCases = []struct {
    434 		name         string
    435 		baseJSON     string
    436 		expectedJSON string
    437 	}{
    438 		{
    439 			name:         "basic 1st elem",
    440 			baseJSON:     "{",
    441 			expectedJSON: `{"foo":null,"bar":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
    442 		},
    443 		{
    444 			name:         "basic 2nd elem",
    445 			baseJSON:     `{"test":"test"`,
    446 			expectedJSON: `{"test":"test","foo":null,"bar":{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
    447 		},
    448 	}
    449 	for _, testCase := range testCases {
    450 		t.Run(testCase.name, func(t *testing.T) {
    451 			var b strings.Builder
    452 			var enc = NewEncoder(&b)
    453 			enc.writeString(testCase.baseJSON)
    454 			enc.AddObjectKeyNullEmpty("foo", (*TestEncoding)(nil))
    455 			enc.ObjectKeyNullEmpty("bar", &TestEncoding{})
    456 			enc.Write()
    457 			assert.Equal(t, testCase.expectedJSON, b.String())
    458 		})
    459 	}
    460 }
    461 
    462 func TestEncoderObjectNullEmpty(t *testing.T) {
    463 	var testCases = []struct {
    464 		name         string
    465 		baseJSON     string
    466 		expectedJSON string
    467 	}{
    468 		{
    469 			name:         "basic 1st elem",
    470 			baseJSON:     "[",
    471 			expectedJSON: `[null,{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
    472 		},
    473 		{
    474 			name:         "basic 2nd elem",
    475 			baseJSON:     `["test"`,
    476 			expectedJSON: `["test",null,{"test":"","test2":"","testInt":0,"testBool":false,"testArr":[],"testF64":0,"testF32":0,"sub":{}}`,
    477 		},
    478 	}
    479 	for _, testCase := range testCases {
    480 		t.Run(testCase.name, func(t *testing.T) {
    481 			var b strings.Builder
    482 			var enc = NewEncoder(&b)
    483 			enc.writeString(testCase.baseJSON)
    484 			enc.AddObjectNullEmpty((*TestEncoding)(nil))
    485 			enc.ObjectNullEmpty(&TestEncoding{})
    486 			enc.Write()
    487 			assert.Equal(t, testCase.expectedJSON, b.String())
    488 		})
    489 	}
    490 }
    491 
    492 type ObjectWithKeys struct {
    493 	Str          string
    494 	Int          int
    495 	Int64        int64
    496 	Int32        int32
    497 	Int16        int16
    498 	Int8         int8
    499 	Uint64       uint64
    500 	Uint32       uint32
    501 	Uint16       uint16
    502 	Uint8        uint8
    503 	Float64      float64
    504 	Float32      float32
    505 	Bool         bool
    506 	Obj          *ObjectWithKeys
    507 	Slice        TestEncodingArrStrings
    508 	Time         *time.Time
    509 	EmbeddedJSON *EmbeddedJSON
    510 }
    511 
    512 func (o *ObjectWithKeys) MarshalJSONObject(enc *Encoder) {
    513 	enc.StringKey("string", o.Str)
    514 	enc.StringKeyOmitEmpty("string", o.Str)
    515 	enc.StringKeyNullEmpty("string", o.Str)
    516 	enc.IntKey("int", o.Int)
    517 	enc.IntKeyOmitEmpty("int", o.Int)
    518 	enc.IntKeyNullEmpty("int", o.Int)
    519 	enc.Int64Key("int64", o.Int64)
    520 	enc.Int64KeyOmitEmpty("int64", o.Int64)
    521 	enc.Int64KeyNullEmpty("int64", o.Int64)
    522 	enc.Int32Key("int32", o.Int32)
    523 	enc.Int32KeyOmitEmpty("int32", o.Int32)
    524 	enc.Int32KeyNullEmpty("int32", o.Int32)
    525 	enc.Int16Key("int16", o.Int16)
    526 	enc.Int16KeyOmitEmpty("int16", o.Int16)
    527 	enc.Int16KeyNullEmpty("int16", o.Int16)
    528 	enc.Int8Key("int8", o.Int8)
    529 	enc.Int8KeyOmitEmpty("int8", o.Int8)
    530 	enc.Int8KeyNullEmpty("int8", o.Int8)
    531 	enc.Uint64KeyOmitEmpty("uint64", o.Uint64)
    532 	enc.Uint64KeyNullEmpty("uint64", o.Uint64)
    533 	enc.Uint64Key("uint64", o.Uint64)
    534 	enc.Uint32Key("uint32", o.Uint32)
    535 	enc.Uint32KeyOmitEmpty("uint32", o.Uint32)
    536 	enc.Uint32KeyNullEmpty("uint32", o.Uint32)
    537 	enc.Uint16KeyOmitEmpty("uint16", o.Uint16)
    538 	enc.Uint16KeyNullEmpty("uint16", o.Uint16)
    539 	enc.Uint16Key("uint16", o.Uint16)
    540 	enc.Uint8Key("uint8", o.Uint8)
    541 	enc.Uint8KeyOmitEmpty("uint8", o.Uint8)
    542 	enc.Uint8KeyNullEmpty("uint8", o.Uint8)
    543 	enc.Float64Key("float64", o.Float64)
    544 	enc.Float64KeyOmitEmpty("float64", o.Float64)
    545 	enc.Float64KeyNullEmpty("float64", o.Float64)
    546 	enc.Float32Key("float32", o.Float32)
    547 	enc.Float32KeyOmitEmpty("float32", o.Float32)
    548 	enc.Float32KeyNullEmpty("float32", o.Float32)
    549 	enc.BoolKey("bool", o.Bool)
    550 	enc.BoolKeyOmitEmpty("bool", o.Bool)
    551 	enc.BoolKeyNullEmpty("bool", o.Bool)
    552 	enc.ObjectKeyOmitEmpty("object", o.Obj)
    553 	enc.ObjectKeyNullEmpty("object", o.Obj)
    554 	enc.ObjectKey("object", o.Obj)
    555 	enc.ArrayKey("array", o.Slice)
    556 	enc.ArrayKeyOmitEmpty("array", o.Slice)
    557 	enc.ArrayKeyNullEmpty("array", o.Slice)
    558 	enc.TimeKey("time", o.Time, time.RFC3339)
    559 	enc.AddEmbeddedJSONKey("ejson", o.EmbeddedJSON)
    560 	enc.AddEmbeddedJSONKeyOmitEmpty("ejson", o.EmbeddedJSON)
    561 	enc.NullKey("null")
    562 }
    563 
    564 func (o *ObjectWithKeys) IsNil() bool {
    565 	return o == nil
    566 }
    567 
    568 type NilObject struct{}
    569 
    570 func (n *NilObject) MarshalJSONObject(enc *Encoder) {}
    571 func (n *NilObject) IsNil() bool                    { return true }
    572 
    573 func TestEncodeObjectWithKeys(t *testing.T) {
    574 	t.Run(
    575 		"should not encode any key",
    576 		func(t *testing.T) {
    577 			var b strings.Builder
    578 			var enc = NewEncoder(&b)
    579 			var o = &ObjectWithKeys{}
    580 			var err = enc.EncodeObjectKeys(o, []string{})
    581 			assert.Nil(t, err)
    582 			assert.Equal(t, `{}`, b.String())
    583 		},
    584 	)
    585 	t.Run(
    586 		"should encode some keys",
    587 		func(t *testing.T) {
    588 			var b strings.Builder
    589 			var enc = NewEncoder(&b)
    590 			var o = &ObjectWithKeys{Str: "hello", Int: 420}
    591 			var err = enc.EncodeObjectKeys(o, []string{"string", "int"})
    592 			assert.Nil(t, err)
    593 			assert.Equal(
    594 				t,
    595 				`{"string":"hello","string":"hello","string":"hello","int":420,"int":420,"int":420}`,
    596 				b.String(),
    597 			)
    598 		},
    599 	)
    600 	t.Run("write-error", func(t *testing.T) {
    601 		w := TestWriterError("")
    602 		enc := NewEncoder(w)
    603 		o := &ObjectWithKeys{Str: "hello", Int: 420}
    604 		err := enc.EncodeObjectKeys(o, []string{"string", "int"})
    605 		assert.NotNil(t, err, "Error should not be nil")
    606 		assert.Equal(t, "Test Error", err.Error(), "err.Error() should be 'Test Error'")
    607 	})
    608 	t.Run("pool-error", func(t *testing.T) {
    609 		v := &TestEncoding{}
    610 		enc := BorrowEncoder(nil)
    611 		enc.isPooled = 1
    612 		defer func() {
    613 			err := recover()
    614 			assert.NotNil(t, err, "err shouldnt be nil")
    615 			assert.IsType(t, InvalidUsagePooledEncoderError(""), err, "err should be of type InvalidUsagePooledEncoderError")
    616 			assert.Equal(t, "Invalid usage of pooled encoder", err.(InvalidUsagePooledEncoderError).Error(), "err should be of type InvalidUsagePooledDecoderError")
    617 		}()
    618 		_ = enc.EncodeObjectKeys(v, []string{})
    619 		assert.True(t, false, "should not be called as it should have panicked")
    620 	})
    621 	t.Run("interface-key-error", func(t *testing.T) {
    622 		builder := &strings.Builder{}
    623 		enc := NewEncoder(builder)
    624 		err := enc.EncodeObjectKeys(&testObjectWithUnknownType{struct{}{}}, []string{})
    625 		assert.NotNil(t, err, "Error should not be nil")
    626 		assert.Equal(t, "Invalid type struct {} provided to Marshal", err.Error(), "err.Error() should be 'Invalid type struct {} provided to Marshal'")
    627 	})
    628 	t.Run("encode-object-with-keys", func(t *testing.T) {
    629 		b := &strings.Builder{}
    630 		enc := NewEncoder(b)
    631 		err := enc.EncodeObjectKeys(EncodeObjectFunc(func(enc *Encoder) {
    632 			enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
    633 				enc.StringKey("test", "hello")
    634 				enc.StringKey("test2", "hello")
    635 			}), []string{"test"})
    636 		}), []string{})
    637 		assert.Nil(t, err, "Error should not be nil")
    638 		assert.Equal(t, `{}`, b.String())
    639 	})
    640 	t.Run("encode-object-with-keys", func(t *testing.T) {
    641 		b := &strings.Builder{}
    642 		enc := NewEncoder(b)
    643 		err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
    644 			enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
    645 				enc.keys = nil
    646 				enc.StringKey("test", "hello")
    647 				enc.StringKey("test2", "hello")
    648 			}), []string{"test"})
    649 		}))
    650 		assert.Nil(t, err, "Error should not be nil")
    651 		assert.Equal(t, `{"test":{}}`, b.String())
    652 	})
    653 	t.Run("encode-object-with-keys", func(t *testing.T) {
    654 		b := &strings.Builder{}
    655 		enc := NewEncoder(b)
    656 		err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
    657 			enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
    658 				enc.StringKey("test", "hello")
    659 				enc.StringKey("test2", "hello")
    660 			}), []string{"test"})
    661 		}))
    662 		assert.Nil(t, err, "Error should not be nil")
    663 		assert.Equal(t, `{"test":{"test":"hello"}}`, b.String())
    664 	})
    665 	t.Run("encode-object-with-keys", func(t *testing.T) {
    666 		b := &strings.Builder{}
    667 		enc := NewEncoder(b)
    668 		err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
    669 			enc.writeByte(' ')
    670 			enc.ObjectKeyWithKeys("test", EncodeObjectFunc(func(enc *Encoder) {
    671 				enc.StringKey("test", "hello")
    672 				enc.StringKey("test2", "hello")
    673 			}), []string{"test"})
    674 		}))
    675 		assert.Nil(t, err, "Error should not be nil")
    676 		assert.Equal(t, `{ ,"test":{"test":"hello"}}`, b.String())
    677 	})
    678 	t.Run("encode-object-with-keys", func(t *testing.T) {
    679 		b := &strings.Builder{}
    680 		enc := NewEncoder(b)
    681 		err := enc.EncodeObject(EncodeObjectFunc(func(enc *Encoder) {
    682 			enc.writeByte(' ')
    683 			enc.ObjectKeyWithKeys("test", &NilObject{}, []string{})
    684 		}))
    685 		assert.Nil(t, err, "Error should not be nil")
    686 		assert.Equal(t, `{ ,"test":{}}`, b.String())
    687 	})
    688 	t.Run("encode-object-with-keys", func(t *testing.T) {
    689 		b := &strings.Builder{}
    690 		enc := NewEncoder(b)
    691 		err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
    692 			enc.ObjectWithKeys(EncodeObjectFunc(func(enc *Encoder) {
    693 				enc.StringKey("test", "hello")
    694 				enc.StringKey("test2", "hello")
    695 			}), []string{"test"})
    696 		}))
    697 		assert.Nil(t, err, "Error should not be nil")
    698 		assert.Equal(t, `[{"test":"hello"}]`, b.String())
    699 	})
    700 	t.Run("encode-object-with-keys", func(t *testing.T) {
    701 		b := &strings.Builder{}
    702 		enc := NewEncoder(b)
    703 		err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
    704 			enc.writeByte(' ')
    705 			enc.ObjectWithKeys(EncodeObjectFunc(func(enc *Encoder) {
    706 				enc.StringKey("test", "hello")
    707 				enc.StringKey("test2", "hello")
    708 			}), []string{"test"})
    709 		}))
    710 		assert.Nil(t, err, "Error should not be nil")
    711 		assert.Equal(t, `[ ,{"test":"hello"}]`, b.String())
    712 	})
    713 	t.Run("encode-object-with-keys", func(t *testing.T) {
    714 		b := &strings.Builder{}
    715 		enc := NewEncoder(b)
    716 		err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
    717 			enc.ObjectWithKeys(&NilObject{}, []string{})
    718 		}))
    719 		assert.Nil(t, err, "Error should not be nil")
    720 		assert.Equal(t, `[{}]`, b.String())
    721 	})
    722 	t.Run("encode-object-with-keys", func(t *testing.T) {
    723 		b := &strings.Builder{}
    724 		enc := NewEncoder(b)
    725 		err := enc.EncodeArray(EncodeArrayFunc(func(enc *Encoder) {
    726 			enc.writeByte(' ')
    727 			enc.ObjectWithKeys(&NilObject{}, []string{})
    728 		}))
    729 		assert.Nil(t, err, "Error should not be nil")
    730 		assert.Equal(t, `[ ,{}]`, b.String())
    731 	})
    732 }