gojay

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

decode_interface_test.go (13196B)


      1 package gojay
      2 
      3 import (
      4 	"encoding/json"
      5 	"strings"
      6 	"testing"
      7 
      8 	"github.com/stretchr/testify/assert"
      9 )
     10 
     11 func TestDecodeInterfaceBasic(t *testing.T) {
     12 	testCases := []struct {
     13 		name            string
     14 		json            string
     15 		expectedResult  interface{}
     16 		err             bool
     17 		errType         interface{}
     18 		skipCheckResult bool
     19 	}{
     20 		{
     21 			name:           "array",
     22 			json:           `[1,2,3]`,
     23 			expectedResult: []interface{}([]interface{}{float64(1), float64(2), float64(3)}),
     24 			err:            false,
     25 		},
     26 		{
     27 			name:           "object",
     28 			json:           `{"testStr": "hello world!"}`,
     29 			expectedResult: map[string]interface{}(map[string]interface{}{"testStr": "hello world!"}),
     30 			err:            false,
     31 		},
     32 		{
     33 			name:           "string",
     34 			json:           `"hola amigos!"`,
     35 			expectedResult: interface{}("hola amigos!"),
     36 			err:            false,
     37 		},
     38 		{
     39 			name:           "bool-true",
     40 			json:           `true`,
     41 			expectedResult: interface{}(true),
     42 			err:            false,
     43 		},
     44 		{
     45 			name:           "bool-false",
     46 			json:           `false`,
     47 			expectedResult: interface{}(false),
     48 			err:            false,
     49 		},
     50 		{
     51 			name:           "null",
     52 			json:           `null`,
     53 			expectedResult: interface{}(nil),
     54 			err:            false,
     55 		},
     56 		{
     57 			name:           "number",
     58 			json:           `1234`,
     59 			expectedResult: interface{}(float64(1234)),
     60 			err:            false,
     61 		},
     62 		{
     63 			name:            "array-error",
     64 			json:            `["h""o","l","a"]`,
     65 			err:             true,
     66 			errType:         &json.SyntaxError{},
     67 			skipCheckResult: true,
     68 		},
     69 		{
     70 			name:            "object-error",
     71 			json:            `{"testStr" "hello world!"}`,
     72 			err:             true,
     73 			errType:         &json.SyntaxError{},
     74 			skipCheckResult: true,
     75 		},
     76 		{
     77 			name:            "string-error",
     78 			json:            `"hola amigos!`,
     79 			err:             true,
     80 			errType:         InvalidJSONError(""),
     81 			skipCheckResult: true,
     82 		},
     83 		{
     84 			name:            "bool-true-error",
     85 			json:            `truee`,
     86 			err:             true,
     87 			errType:         InvalidJSONError(""),
     88 			skipCheckResult: true,
     89 		},
     90 		{
     91 			name:            "bool-false-error",
     92 			json:            `fase`,
     93 			expectedResult:  interface{}(false),
     94 			err:             true,
     95 			errType:         InvalidJSONError(""),
     96 			skipCheckResult: true,
     97 		},
     98 		{
     99 			name:            "null-error",
    100 			json:            `nulllll`,
    101 			err:             true,
    102 			errType:         InvalidJSONError(""),
    103 			skipCheckResult: true,
    104 		},
    105 		{
    106 			name:            "number-error",
    107 			json:            `1234"`,
    108 			err:             true,
    109 			errType:         InvalidJSONError(""),
    110 			skipCheckResult: true,
    111 		},
    112 		{
    113 			name:            "unknown-error",
    114 			json:            `?`,
    115 			err:             true,
    116 			errType:         InvalidJSONError(""),
    117 			skipCheckResult: true,
    118 		},
    119 		{
    120 			name:            "empty-json-error",
    121 			json:            ``,
    122 			err:             true,
    123 			errType:         InvalidJSONError(""),
    124 			skipCheckResult: true,
    125 		},
    126 	}
    127 
    128 	for _, testCase := range testCases {
    129 		t.Run("DecodeInterface()"+testCase.name, func(t *testing.T) {
    130 			var i interface{}
    131 			dec := BorrowDecoder(strings.NewReader(testCase.json))
    132 			defer dec.Release()
    133 			err := dec.DecodeInterface(&i)
    134 			if testCase.err {
    135 				t.Log(err)
    136 				assert.NotNil(t, err, "err should not be nil")
    137 				if testCase.errType != nil {
    138 					assert.IsType(t, testCase.errType, err, "err should be of the given type")
    139 				}
    140 				return
    141 			}
    142 			assert.Nil(t, err, "err should be nil")
    143 			if !testCase.skipCheckResult {
    144 				assert.Equal(t, testCase.expectedResult, i, "value at given index should be the same as expected results")
    145 			}
    146 		})
    147 	}
    148 
    149 	for _, testCase := range testCases {
    150 		t.Run("Decode()"+testCase.name, func(t *testing.T) {
    151 			var i interface{}
    152 			dec := BorrowDecoder(strings.NewReader(testCase.json))
    153 			defer dec.Release()
    154 			err := dec.Decode(&i)
    155 			if testCase.err {
    156 				t.Log(err)
    157 				assert.NotNil(t, err, "err should not be nil")
    158 				if testCase.errType != nil {
    159 					assert.IsType(t, testCase.errType, err, "err should be of the given type")
    160 				}
    161 				return
    162 			}
    163 			assert.Nil(t, err, "err should be nil")
    164 			if !testCase.skipCheckResult {
    165 				assert.Equal(t, testCase.expectedResult, i, "value at given index should be the same as expected results")
    166 			}
    167 		})
    168 	}
    169 }
    170 
    171 func TestDecodeInterfaceAsInterface(t *testing.T) {
    172 	testCases := []struct {
    173 		name            string
    174 		json            string
    175 		expectedResult  interface{}
    176 		err             bool
    177 		errType         interface{}
    178 		skipCheckResult bool
    179 	}{
    180 		{
    181 			name: "basic-array",
    182 			json: `{
    183         "testStr": "hola",
    184         "testInterface": ["h","o","l","a"]
    185       }`,
    186 			expectedResult: map[string]interface{}(
    187 				map[string]interface{}{
    188 					"testStr":       "hola",
    189 					"testInterface": []interface{}{"h", "o", "l", "a"},
    190 				}),
    191 			err: false,
    192 		},
    193 		{
    194 			name: "basic-string",
    195 			json: `{
    196         "testInterface": "漢字"
    197       }`,
    198 			expectedResult: map[string]interface{}(
    199 				map[string]interface{}{
    200 					"testInterface": "漢字",
    201 				}),
    202 			err: false,
    203 		},
    204 		{
    205 			name: "basic-error",
    206 			json: `{
    207         "testInterface": ["a""d","i","o","s"]
    208       }`,
    209 			err:             true,
    210 			errType:         &json.SyntaxError{},
    211 			skipCheckResult: true,
    212 		},
    213 		{
    214 			name: "basic-interface",
    215 			json: `{
    216         "testInterface": {
    217           "string": "prost"
    218         }
    219       }`,
    220 			expectedResult: map[string]interface{}(
    221 				map[string]interface{}{
    222 					"testInterface": map[string]interface{}{"string": "prost"},
    223 				}),
    224 			err: false,
    225 		},
    226 		{
    227 			name: "complex-interface",
    228 			json: `{
    229         "testInterface": {
    230           "number": 1988,
    231           "string": "prost",
    232           "array": ["h","o","l","a"],
    233           "object": {
    234             "k": "v",
    235             "a": [1,2,3]
    236           },
    237           "array-of-objects": [
    238             {"k": "v"},
    239             {"a": "b"}
    240           ]
    241         }
    242       }`,
    243 			expectedResult: map[string]interface{}(
    244 				map[string]interface{}{
    245 					"testInterface": map[string]interface{}{
    246 						"array-of-objects": []interface{}{
    247 							map[string]interface{}{"k": "v"},
    248 							map[string]interface{}{"a": "b"},
    249 						},
    250 						"number": float64(1988),
    251 						"string": "prost",
    252 						"array":  []interface{}{"h", "o", "l", "a"},
    253 						"object": map[string]interface{}{
    254 							"k": "v",
    255 							"a": []interface{}{float64(1), float64(2), float64(3)},
    256 						},
    257 					},
    258 				}),
    259 			err: false,
    260 		},
    261 	}
    262 
    263 	for _, testCase := range testCases {
    264 		t.Run("Decode()"+testCase.name, func(t *testing.T) {
    265 			var s interface{}
    266 			dec := BorrowDecoder(strings.NewReader(testCase.json))
    267 			defer dec.Release()
    268 			err := dec.Decode(&s)
    269 			if testCase.err {
    270 				t.Log(err)
    271 				assert.NotNil(t, err, "err should not be nil")
    272 				if testCase.errType != nil {
    273 					assert.IsType(t, testCase.errType, err, "err should be of the given type")
    274 				}
    275 				return
    276 			}
    277 			assert.Nil(t, err, "err should be nil")
    278 			if !testCase.skipCheckResult {
    279 				assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
    280 			}
    281 		})
    282 	}
    283 
    284 	for _, testCase := range testCases {
    285 		t.Run("DecodeInterface()"+testCase.name, func(t *testing.T) {
    286 			var s interface{}
    287 			dec := BorrowDecoder(strings.NewReader(testCase.json))
    288 			defer dec.Release()
    289 			err := dec.DecodeInterface(&s)
    290 			if testCase.err {
    291 				t.Log(err)
    292 				assert.NotNil(t, err, "err should not be nil")
    293 				if testCase.errType != nil {
    294 					assert.IsType(t, testCase.errType, err, "err should be of the given type")
    295 				}
    296 				return
    297 			}
    298 			assert.Nil(t, err, "err should be nil")
    299 			if !testCase.skipCheckResult {
    300 				assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
    301 			}
    302 		})
    303 	}
    304 }
    305 
    306 func TestDecodeAsTestObject(t *testing.T) {
    307 	testCases := []struct {
    308 		name            string
    309 		json            string
    310 		expectedResult  testObject
    311 		err             bool
    312 		errType         interface{}
    313 		skipCheckResult bool
    314 	}{
    315 		{
    316 			name: "basic-array",
    317 			json: `{
    318         "testStr": "hola",
    319         "testInterface": ["h","o","l","a"]
    320       }`,
    321 			expectedResult: testObject{
    322 				testStr:       "hola",
    323 				testInterface: []interface{}([]interface{}{"h", "o", "l", "a"}),
    324 			},
    325 			err: false,
    326 		},
    327 		{
    328 			name: "basic-string",
    329 			json: `{
    330         "testInterface": "漢字"
    331       }`,
    332 			expectedResult: testObject{
    333 				testInterface: interface{}("漢字"),
    334 			},
    335 			err: false,
    336 		},
    337 		{
    338 			name: "basic-error",
    339 			json: `{
    340         "testInterface": ["a""d","i","o","s"]
    341       }`,
    342 			err:             true,
    343 			errType:         &json.SyntaxError{},
    344 			skipCheckResult: true,
    345 		},
    346 		{
    347 			name: "mull-interface",
    348 			json: `{
    349         "testInterface": null,
    350         "testStr": "adios"
    351       }`,
    352 			expectedResult: testObject{
    353 				testInterface: interface{}(nil),
    354 				testStr:       "adios",
    355 			},
    356 			err: false,
    357 		},
    358 		{
    359 			name: "basic-interface",
    360 			json: `{
    361         "testInterface": {
    362           "string": "prost"
    363         },
    364       }`,
    365 			expectedResult: testObject{
    366 				testInterface: map[string]interface{}{"string": "prost"},
    367 			},
    368 			err: false,
    369 		},
    370 		{
    371 			name: "complex-interface",
    372 			json: `{
    373         "testInterface": {
    374           "number": 1988,
    375           "string": "prost",
    376           "array": ["h","o","l","a"],
    377           "object": {
    378             "k": "v",
    379             "a": [1,2,3]
    380           },
    381           "array-of-objects": [
    382             {"k": "v"},
    383             {"a": "b"}
    384           ]
    385         },
    386       }`,
    387 			expectedResult: testObject{
    388 				testInterface: map[string]interface{}{
    389 					"array-of-objects": []interface{}{
    390 						map[string]interface{}{"k": "v"},
    391 						map[string]interface{}{"a": "b"},
    392 					},
    393 					"number": float64(1988),
    394 					"string": "prost",
    395 					"array":  []interface{}{"h", "o", "l", "a"},
    396 					"object": map[string]interface{}{
    397 						"k": "v",
    398 						"a": []interface{}{float64(1), float64(2), float64(3)},
    399 					},
    400 				},
    401 			},
    402 			err: false,
    403 		},
    404 	}
    405 	for _, testCase := range testCases {
    406 		t.Run(testCase.name, func(t *testing.T) {
    407 			s := testObject{}
    408 			dec := BorrowDecoder(strings.NewReader(testCase.json))
    409 			defer dec.Release()
    410 			err := dec.Decode(&s)
    411 			if testCase.err {
    412 				t.Log(err)
    413 				assert.NotNil(t, err, "err should not be nil")
    414 				if testCase.errType != nil {
    415 					assert.IsType(t, testCase.errType, err, "err should be of the given type")
    416 				}
    417 				return
    418 			}
    419 			assert.Nil(t, err, "err should be nil")
    420 			if !testCase.skipCheckResult {
    421 				assert.Equal(t, testCase.expectedResult, s, "value at given index should be the same as expected results")
    422 			}
    423 		})
    424 	}
    425 }
    426 
    427 func TestUnmarshalInterface(t *testing.T) {
    428 	json := []byte(`{
    429     "testInterface": {
    430       "number": 1988,
    431       "null": null,
    432       "string": "prost",
    433       "array": ["h","o","l","a"],
    434       "object": {
    435         "k": "v",
    436         "a": [1,2,3]
    437       },
    438       "array-of-objects": [
    439         {"k": "v"},
    440         {"a": "b"}
    441       ]
    442     }
    443 	}`)
    444 	v := &testObject{}
    445 	err := Unmarshal(json, v)
    446 	assert.Nil(t, err, "Err must be nil")
    447 	expectedInterface := map[string]interface{}{
    448 		"array-of-objects": []interface{}{
    449 			map[string]interface{}{"k": "v"},
    450 			map[string]interface{}{"a": "b"},
    451 		},
    452 		"number": float64(1988),
    453 		"string": "prost",
    454 		"null":   interface{}(nil),
    455 		"array":  []interface{}{"h", "o", "l", "a"},
    456 		"object": map[string]interface{}{
    457 			"k": "v",
    458 			"a": []interface{}{float64(1), float64(2), float64(3)},
    459 		},
    460 	}
    461 	assert.Equal(t, expectedInterface, v.testInterface, "v.testInterface must be equal to the expected one")
    462 }
    463 
    464 func TestUnmarshalInterfaceError(t *testing.T) {
    465 	testCases := []struct {
    466 		name string
    467 		json []byte
    468 	}{
    469 		{
    470 			name: "basic",
    471 			json: []byte(`{"testInterface": {"number": 1bc4}}`),
    472 		},
    473 		{
    474 			name: "syntax",
    475 			json: []byte(`{
    476         "testInterface": {
    477           "array?": [1,"a", ?]
    478         }
    479       }`),
    480 		},
    481 		{
    482 			name: "complex",
    483 			json: []byte(`{
    484         "testInterface": {
    485           "number": 1988,
    486           "string": "prost",
    487           "array": ["h""o","l","a"],
    488           "object": {
    489             "k": "v",
    490             "a": [1,2,3]
    491           },
    492           "array-of-objects": [
    493             {"k": "v"},
    494             {"a": "b"}
    495           ]
    496         }
    497       }`),
    498 		},
    499 	}
    500 	for _, testCase := range testCases {
    501 		t.Run(testCase.name, func(t *testing.T) {
    502 			v := &testObject{}
    503 			err := Unmarshal(testCase.json, v)
    504 			assert.NotNil(t, err, "Err must be not nil")
    505 			t.Log(err)
    506 			assert.IsType(t, &json.SyntaxError{}, err, "err should be a json.SyntaxError{}")
    507 		})
    508 	}
    509 }
    510 
    511 func TestDecodeInterfacePoolError(t *testing.T) {
    512 	result := interface{}(1)
    513 	dec := NewDecoder(nil)
    514 	dec.Release()
    515 	defer func() {
    516 		err := recover()
    517 		assert.NotNil(t, err, "err shouldnt be nil")
    518 		assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
    519 	}()
    520 	_ = dec.DecodeInterface(&result)
    521 	assert.True(t, false, "should not be called as decoder should have panicked")
    522 }
    523 
    524 func TestDecodeNull(t *testing.T) {
    525 	var i interface{}
    526 	dec := BorrowDecoder(strings.NewReader("null"))
    527 	defer dec.Release()
    528 	err := dec.DecodeInterface(&i)
    529 	assert.Nil(t, err, "err should be nil")
    530 	assert.Equal(t, interface{}(nil), i, "value at given index should be the same as expected results")
    531 }