gojay

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

decode_string_test.go (19423B)


      1 package gojay
      2 
      3 import (
      4 	"fmt"
      5 	"strings"
      6 	"sync"
      7 	"testing"
      8 
      9 	"github.com/stretchr/testify/assert"
     10 )
     11 
     12 func TestDecoderString(t *testing.T) {
     13 	testCases := []struct {
     14 		name           string
     15 		json           string
     16 		expectedResult string
     17 		err            bool
     18 		errType        interface{}
     19 	}{
     20 		{
     21 			name:           "basic-string",
     22 			json:           `"string"`,
     23 			expectedResult: "string",
     24 			err:            false,
     25 		},
     26 		{
     27 			name:           "string-solidus",
     28 			json:           `"\/"`,
     29 			expectedResult: "/",
     30 			err:            false,
     31 		},
     32 		{
     33 			name:           "basic-string",
     34 			json:           ``,
     35 			expectedResult: "",
     36 			err:            false,
     37 		},
     38 		{
     39 			name:           "basic-string",
     40 			json:           `""`,
     41 			expectedResult: "",
     42 			err:            false,
     43 		},
     44 		{
     45 			name:           "basic-string2",
     46 			json:           `"hello world!"`,
     47 			expectedResult: "hello world!",
     48 			err:            false,
     49 		},
     50 		{
     51 			name:           "escape-control-char",
     52 			json:           `"\n"`,
     53 			expectedResult: "\n",
     54 			err:            false,
     55 		},
     56 		{
     57 			name:           "escape-control-char",
     58 			json:           `"\\n"`,
     59 			expectedResult: `\n`,
     60 			err:            false,
     61 		},
     62 		{
     63 			name:           "escape-control-char",
     64 			json:           `"\t"`,
     65 			expectedResult: "\t",
     66 			err:            false,
     67 		},
     68 		{
     69 			name:           "escape-control-char",
     70 			json:           `"\\t"`,
     71 			expectedResult: `\t`,
     72 			err:            false,
     73 		},
     74 		{
     75 			name:           "escape-control-char",
     76 			json:           `"\b"`,
     77 			expectedResult: "\b",
     78 			err:            false,
     79 		},
     80 		{
     81 			name:           "escape-control-char",
     82 			json:           `"\\b"`,
     83 			expectedResult: `\b`,
     84 			err:            false,
     85 		},
     86 		{
     87 			name:           "escape-control-char",
     88 			json:           `"\f"`,
     89 			expectedResult: "\f",
     90 			err:            false,
     91 		},
     92 		{
     93 			name:           "escape-control-char",
     94 			json:           `"\\f"`,
     95 			expectedResult: `\f`,
     96 			err:            false,
     97 		},
     98 		{
     99 			name:           "escape-control-char",
    100 			json:           `"\r"`,
    101 			expectedResult: "\r",
    102 			err:            false,
    103 		},
    104 		{
    105 			name:           "escape-control-char",
    106 			json:           `"\`,
    107 			expectedResult: "",
    108 			err:            true,
    109 		},
    110 		{
    111 			name:           "escape-control-char-solidus",
    112 			json:           `"\/"`,
    113 			expectedResult: "/",
    114 			err:            false,
    115 		},
    116 		{
    117 			name:           "escape-control-char-solidus",
    118 			json:           `"/"`,
    119 			expectedResult: "/",
    120 			err:            false,
    121 		},
    122 		{
    123 			name:           "escape-control-char-solidus-escape-char",
    124 			json:           `"\\/"`,
    125 			expectedResult: `\/`,
    126 			err:            false,
    127 		},
    128 		{
    129 			name:           "escape-control-char",
    130 			json:           `"\\r"`,
    131 			expectedResult: `\r`,
    132 			err:            false,
    133 		},
    134 		{
    135 			name:           "utf8",
    136 			json:           `"𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕 𠴕 𠵼 𠵿"`,
    137 			expectedResult: "𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕 𠴕 𠵼 𠵿",
    138 			err:            false,
    139 		},
    140 		{
    141 			name:           "utf8-code-point",
    142 			json:           `"\u06fc"`,
    143 			expectedResult: `ۼ`,
    144 			err:            false,
    145 		},
    146 		{
    147 			name:           "utf8-code-point-escaped",
    148 			json:           `"\\u2070"`,
    149 			expectedResult: `\u2070`,
    150 			err:            false,
    151 		},
    152 		{
    153 			name:           "utf8-code-point-err",
    154 			json:           `"\u2Z70"`,
    155 			expectedResult: ``,
    156 			err:            true,
    157 		},
    158 		{
    159 			name:           "utf16-surrogate",
    160 			json:           `"\uD834\uDD1E"`,
    161 			expectedResult: `𝄞`,
    162 			err:            false,
    163 		},
    164 		{
    165 			name:           "utf16-surrogate",
    166 			json:           `"\uD834\\"`,
    167 			expectedResult: `�\`,
    168 			err:            false,
    169 		},
    170 		{
    171 			name:           "utf16-surrogate",
    172 			json:           `"\uD834\uD834"`,
    173 			expectedResult: "�\x00\x00\x00",
    174 			err:            false,
    175 		},
    176 		{
    177 			name:           "utf16-surrogate",
    178 			json:           `"\uD834"`,
    179 			expectedResult: `�`,
    180 			err:            false,
    181 		},
    182 		{
    183 			name:           "utf16-surrogate-err",
    184 			json:           `"\uD834\`,
    185 			expectedResult: ``,
    186 			err:            true,
    187 		},
    188 		{
    189 			name:           "utf16-surrogate-err2",
    190 			json:           `"\uD834\uDZ1E`,
    191 			expectedResult: ``,
    192 			err:            true,
    193 		},
    194 		{
    195 			name:           "utf16-surrogate-err3",
    196 			json:           `"\uD834`,
    197 			expectedResult: ``,
    198 			err:            true,
    199 		},
    200 		{
    201 			name:           "utf16-surrogate-followed-by-control-char",
    202 			json:           `"\uD834\t"`,
    203 			expectedResult: "�\t",
    204 			err:            false,
    205 		},
    206 		{
    207 			name:           "utf16-surrogate-followed-by-control-char",
    208 			json:           `"\uD834\n"`,
    209 			expectedResult: "�\n",
    210 			err:            false,
    211 		},
    212 		{
    213 			name:           "utf16-surrogate-followed-by-control-char",
    214 			json:           `"\uD834\f"`,
    215 			expectedResult: "�\f",
    216 			err:            false,
    217 		},
    218 		{
    219 			name:           "utf16-surrogate-followed-by-control-char",
    220 			json:           `"\uD834\b"`,
    221 			expectedResult: "�\b",
    222 			err:            false,
    223 		},
    224 		{
    225 			name:           "utf16-surrogate-followed-by-control-char",
    226 			json:           `"\uD834\r"`,
    227 			expectedResult: "�\r",
    228 			err:            false,
    229 		},
    230 		{
    231 			name:           "utf16-surrogate-followed-by-control-char",
    232 			json:           `"\uD834\h"`,
    233 			expectedResult: "",
    234 			err:            true,
    235 		},
    236 		{
    237 			name:           "null",
    238 			json:           `null`,
    239 			expectedResult: "",
    240 		},
    241 		{
    242 			name:           "null-err",
    243 			json:           `nall`,
    244 			expectedResult: "",
    245 			err:            true,
    246 		},
    247 		{
    248 			name:           "escape quote err",
    249 			json:           `"test string \" escaped"`,
    250 			expectedResult: `test string " escaped`,
    251 			err:            false,
    252 		},
    253 		{
    254 			name:           "escape quote err2",
    255 			json:           `"test string \t escaped"`,
    256 			expectedResult: "test string \t escaped",
    257 			err:            false,
    258 		},
    259 		{
    260 			name:           "escape quote err2",
    261 			json:           `"test string \r escaped"`,
    262 			expectedResult: "test string \r escaped",
    263 			err:            false,
    264 		},
    265 		{
    266 			name:           "escape quote err2",
    267 			json:           `"test string \b escaped"`,
    268 			expectedResult: "test string \b escaped",
    269 			err:            false,
    270 		},
    271 		{
    272 			name:           "escape quote err",
    273 			json:           `"test string \n escaped"`,
    274 			expectedResult: "test string \n escaped",
    275 			err:            false,
    276 		},
    277 		{
    278 			name:           "escape quote err",
    279 			json:           `"test string \\\" escaped`,
    280 			expectedResult: ``,
    281 			err:            true,
    282 			errType:        InvalidJSONError(""),
    283 		},
    284 		{
    285 			name:           "escape quote err",
    286 			json:           `"test string \\\l escaped"`,
    287 			expectedResult: ``,
    288 			err:            true,
    289 			errType:        InvalidJSONError(""),
    290 		},
    291 		{
    292 			name:           "invalid-json",
    293 			json:           `invalid`,
    294 			expectedResult: ``,
    295 			err:            true,
    296 			errType:        InvalidJSONError(""),
    297 		},
    298 		{
    299 			name:           "string-complex",
    300 			json:           `  "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char"`,
    301 			expectedResult: "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char",
    302 		},
    303 	}
    304 
    305 	for _, testCase := range testCases {
    306 		t.Run(testCase.name, func(t *testing.T) {
    307 			str := ""
    308 			dec := NewDecoder(strings.NewReader(testCase.json))
    309 			err := dec.Decode(&str)
    310 			if testCase.err {
    311 				assert.NotNil(t, err, "err should not be nil")
    312 				if testCase.errType != nil {
    313 					assert.IsType(t, testCase.errType, err, "err should of the given type")
    314 				}
    315 			} else {
    316 				assert.Nil(t, err, "err should be nil")
    317 			}
    318 			assert.Equal(t, testCase.expectedResult, str, fmt.Sprintf("'%s' should be equal to expectedResult", str))
    319 		})
    320 	}
    321 }
    322 func TestDecoderStringNull(t *testing.T) {
    323 	testCases := []struct {
    324 		name           string
    325 		json           string
    326 		expectedResult string
    327 		err            bool
    328 		errType        interface{}
    329 		resultIsNil    bool
    330 	}{
    331 		{
    332 			name:           "basic-string",
    333 			json:           `"string"`,
    334 			expectedResult: "string",
    335 			err:            false,
    336 		},
    337 		{
    338 			name:           "string-solidus",
    339 			json:           `"\/"`,
    340 			expectedResult: "/",
    341 			err:            false,
    342 		},
    343 		{
    344 			name:           "basic-string",
    345 			json:           ``,
    346 			expectedResult: "",
    347 			err:            false,
    348 			resultIsNil:    true,
    349 		},
    350 		{
    351 			name:           "basic-string",
    352 			json:           `""`,
    353 			expectedResult: "",
    354 			err:            false,
    355 		},
    356 		{
    357 			name:           "basic-string2",
    358 			json:           `"hello world!"`,
    359 			expectedResult: "hello world!",
    360 			err:            false,
    361 		},
    362 		{
    363 			name:           "escape-control-char",
    364 			json:           `"\n"`,
    365 			expectedResult: "\n",
    366 			err:            false,
    367 		},
    368 		{
    369 			name:           "escape-control-char",
    370 			json:           `"\\n"`,
    371 			expectedResult: `\n`,
    372 			err:            false,
    373 		},
    374 		{
    375 			name:           "escape-control-char",
    376 			json:           `"\t"`,
    377 			expectedResult: "\t",
    378 			err:            false,
    379 		},
    380 		{
    381 			name:           "escape-control-char",
    382 			json:           `"\\t"`,
    383 			expectedResult: `\t`,
    384 			err:            false,
    385 		},
    386 		{
    387 			name:           "escape-control-char",
    388 			json:           `"\b"`,
    389 			expectedResult: "\b",
    390 			err:            false,
    391 		},
    392 		{
    393 			name:           "escape-control-char",
    394 			json:           `"\\b"`,
    395 			expectedResult: `\b`,
    396 			err:            false,
    397 		},
    398 		{
    399 			name:           "escape-control-char",
    400 			json:           `"\f"`,
    401 			expectedResult: "\f",
    402 			err:            false,
    403 		},
    404 		{
    405 			name:           "escape-control-char",
    406 			json:           `"\\f"`,
    407 			expectedResult: `\f`,
    408 			err:            false,
    409 		},
    410 		{
    411 			name:           "escape-control-char",
    412 			json:           `"\r"`,
    413 			expectedResult: "\r",
    414 			err:            false,
    415 		},
    416 		{
    417 			name:           "escape-control-char",
    418 			json:           `"\`,
    419 			expectedResult: "",
    420 			err:            true,
    421 		},
    422 		{
    423 			name:           "escape-control-char-solidus",
    424 			json:           `"\/"`,
    425 			expectedResult: "/",
    426 			err:            false,
    427 		},
    428 		{
    429 			name:           "escape-control-char-solidus",
    430 			json:           `"/"`,
    431 			expectedResult: "/",
    432 			err:            false,
    433 		},
    434 		{
    435 			name:           "escape-control-char-solidus-escape-char",
    436 			json:           `"\\/"`,
    437 			expectedResult: `\/`,
    438 			err:            false,
    439 		},
    440 		{
    441 			name:           "escape-control-char",
    442 			json:           `"\\r"`,
    443 			expectedResult: `\r`,
    444 			err:            false,
    445 		},
    446 		{
    447 			name:           "utf8",
    448 			json:           `"𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕 𠴕 𠵼 𠵿"`,
    449 			expectedResult: "𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕 𠴕 𠵼 𠵿",
    450 			err:            false,
    451 		},
    452 		{
    453 			name:           "utf8-code-point",
    454 			json:           `"\u06fc"`,
    455 			expectedResult: `ۼ`,
    456 			err:            false,
    457 		},
    458 		{
    459 			name:           "utf8-code-point-escaped",
    460 			json:           `"\\u2070"`,
    461 			expectedResult: `\u2070`,
    462 			err:            false,
    463 		},
    464 		{
    465 			name:           "utf8-code-point-err",
    466 			json:           `"\u2Z70"`,
    467 			expectedResult: ``,
    468 			err:            true,
    469 		},
    470 		{
    471 			name:           "utf16-surrogate",
    472 			json:           `"\uD834\uDD1E"`,
    473 			expectedResult: `𝄞`,
    474 			err:            false,
    475 		},
    476 		{
    477 			name:           "utf16-surrogate",
    478 			json:           `"\uD834\\"`,
    479 			expectedResult: `�\`,
    480 			err:            false,
    481 		},
    482 		{
    483 			name:           "utf16-surrogate",
    484 			json:           `"\uD834\uD834"`,
    485 			expectedResult: "�\x00\x00\x00",
    486 			err:            false,
    487 		},
    488 		{
    489 			name:           "utf16-surrogate",
    490 			json:           `"\uD834"`,
    491 			expectedResult: `�`,
    492 			err:            false,
    493 		},
    494 		{
    495 			name:           "utf16-surrogate-err",
    496 			json:           `"\uD834\`,
    497 			expectedResult: ``,
    498 			err:            true,
    499 		},
    500 		{
    501 			name:           "utf16-surrogate-err2",
    502 			json:           `"\uD834\uDZ1E`,
    503 			expectedResult: ``,
    504 			err:            true,
    505 		},
    506 		{
    507 			name:           "utf16-surrogate-err3",
    508 			json:           `"\uD834`,
    509 			expectedResult: ``,
    510 			err:            true,
    511 		},
    512 		{
    513 			name:           "utf16-surrogate-followed-by-control-char",
    514 			json:           `"\uD834\t"`,
    515 			expectedResult: "�\t",
    516 			err:            false,
    517 		},
    518 		{
    519 			name:           "utf16-surrogate-followed-by-control-char",
    520 			json:           `"\uD834\n"`,
    521 			expectedResult: "�\n",
    522 			err:            false,
    523 		},
    524 		{
    525 			name:           "utf16-surrogate-followed-by-control-char",
    526 			json:           `"\uD834\f"`,
    527 			expectedResult: "�\f",
    528 			err:            false,
    529 		},
    530 		{
    531 			name:           "utf16-surrogate-followed-by-control-char",
    532 			json:           `"\uD834\b"`,
    533 			expectedResult: "�\b",
    534 			err:            false,
    535 		},
    536 		{
    537 			name:           "utf16-surrogate-followed-by-control-char",
    538 			json:           `"\uD834\r"`,
    539 			expectedResult: "�\r",
    540 			err:            false,
    541 		},
    542 		{
    543 			name:           "utf16-surrogate-followed-by-control-char",
    544 			json:           `"\uD834\h"`,
    545 			expectedResult: "",
    546 			err:            true,
    547 		},
    548 		{
    549 			name:           "null",
    550 			json:           `null`,
    551 			expectedResult: "",
    552 			resultIsNil:    true,
    553 		},
    554 		{
    555 			name:           "null-err",
    556 			json:           `nall`,
    557 			expectedResult: "",
    558 			err:            true,
    559 		},
    560 		{
    561 			name:           "escape quote err",
    562 			json:           `"test string \" escaped"`,
    563 			expectedResult: `test string " escaped`,
    564 			err:            false,
    565 		},
    566 		{
    567 			name:           "escape quote err2",
    568 			json:           `"test string \t escaped"`,
    569 			expectedResult: "test string \t escaped",
    570 			err:            false,
    571 		},
    572 		{
    573 			name:           "escape quote err2",
    574 			json:           `"test string \r escaped"`,
    575 			expectedResult: "test string \r escaped",
    576 			err:            false,
    577 		},
    578 		{
    579 			name:           "escape quote err2",
    580 			json:           `"test string \b escaped"`,
    581 			expectedResult: "test string \b escaped",
    582 			err:            false,
    583 		},
    584 		{
    585 			name:           "escape quote err",
    586 			json:           `"test string \n escaped"`,
    587 			expectedResult: "test string \n escaped",
    588 			err:            false,
    589 		},
    590 		{
    591 			name:           "escape quote err",
    592 			json:           `"test string \\\" escaped`,
    593 			expectedResult: ``,
    594 			err:            true,
    595 			errType:        InvalidJSONError(""),
    596 		},
    597 		{
    598 			name:           "escape quote err",
    599 			json:           `"test string \\\l escaped"`,
    600 			expectedResult: ``,
    601 			err:            true,
    602 			errType:        InvalidJSONError(""),
    603 		},
    604 		{
    605 			name:           "invalid-json",
    606 			json:           `invalid`,
    607 			expectedResult: ``,
    608 			err:            true,
    609 			errType:        InvalidJSONError(""),
    610 		},
    611 		{
    612 			name:           "string-complex",
    613 			json:           `  "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char"`,
    614 			expectedResult: "string with spaces and \"escape\"d \"quotes\" and escaped line returns \n and escaped \\\\ escaped char",
    615 		},
    616 	}
    617 
    618 	for _, testCase := range testCases {
    619 		t.Run(testCase.name, func(t *testing.T) {
    620 			str := (*string)(nil)
    621 			err := Unmarshal([]byte(testCase.json), &str)
    622 			if testCase.err {
    623 				assert.NotNil(t, err, "err should not be nil")
    624 				if testCase.errType != nil {
    625 					assert.IsType(t, testCase.errType, err, "err should of the given type")
    626 				}
    627 				return
    628 			}
    629 			assert.Nil(t, err, "Err must be nil")
    630 			if testCase.resultIsNil {
    631 				assert.Nil(t, str)
    632 			} else {
    633 				assert.Equal(t, testCase.expectedResult, *str, fmt.Sprintf("v must be equal to %s", testCase.expectedResult))
    634 			}
    635 		})
    636 	}
    637 	t.Run("decoder-api-invalid-json2", func(t *testing.T) {
    638 		var v = new(string)
    639 		var dec = NewDecoder(strings.NewReader(`a`))
    640 		err := dec.StringNull(&v)
    641 		assert.NotNil(t, err, "Err must not be nil")
    642 		assert.IsType(t, InvalidJSONError(""), err, "err should be of type InvalidJSONError")
    643 	})
    644 }
    645 func TestDecoderStringInvalidType(t *testing.T) {
    646 	json := []byte(`1`)
    647 	var v string
    648 	err := Unmarshal(json, &v)
    649 	assert.NotNil(t, err, "Err must not be nil as JSON is invalid")
    650 	assert.IsType(t, InvalidUnmarshalError(""), err, "err message must be 'Invalid JSON'")
    651 }
    652 
    653 func TestDecoderStringDecoderAPI(t *testing.T) {
    654 	var v string
    655 	dec := NewDecoder(strings.NewReader(`"hello world!"`))
    656 	defer dec.Release()
    657 	err := dec.DecodeString(&v)
    658 	assert.Nil(t, err, "Err must be nil")
    659 	assert.Equal(t, "hello world!", v, "v must be equal to 'hello world!'")
    660 }
    661 
    662 func TestDecoderStringPoolError(t *testing.T) {
    663 	// reset the pool to make sure it's not full
    664 	decPool = sync.Pool{
    665 		New: func() interface{} {
    666 			return NewDecoder(nil)
    667 		},
    668 	}
    669 	result := ""
    670 	dec := NewDecoder(nil)
    671 	dec.Release()
    672 	defer func() {
    673 		err := recover()
    674 		assert.NotNil(t, err, "err shouldnt be nil")
    675 		assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError")
    676 	}()
    677 	_ = dec.DecodeString(&result)
    678 	assert.True(t, false, "should not be called as decoder should have panicked")
    679 }
    680 
    681 func TestDecoderSkipEscapedStringError(t *testing.T) {
    682 	dec := NewDecoder(strings.NewReader(``))
    683 	defer dec.Release()
    684 	err := dec.skipEscapedString()
    685 	assert.NotNil(t, err, "Err must be nil")
    686 	assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
    687 }
    688 
    689 func TestDecoderSkipEscapedStringError2(t *testing.T) {
    690 	dec := NewDecoder(strings.NewReader(`\"`))
    691 	defer dec.Release()
    692 	err := dec.skipEscapedString()
    693 	assert.NotNil(t, err, "Err must be nil")
    694 	assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
    695 }
    696 
    697 func TestDecoderSkipEscapedStringError3(t *testing.T) {
    698 	dec := NewDecoder(strings.NewReader(`invalid`))
    699 	defer dec.Release()
    700 	err := dec.skipEscapedString()
    701 	assert.NotNil(t, err, "Err must be nil")
    702 	assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
    703 }
    704 
    705 func TestDecoderSkipEscapedStringError4(t *testing.T) {
    706 	dec := NewDecoder(strings.NewReader(`\u12`))
    707 	defer dec.Release()
    708 	err := dec.skipEscapedString()
    709 	assert.NotNil(t, err, "Err must be nil")
    710 	assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
    711 }
    712 
    713 func TestDecoderSkipStringError(t *testing.T) {
    714 	dec := NewDecoder(strings.NewReader(`invalid`))
    715 	defer dec.Release()
    716 	err := dec.skipString()
    717 	assert.NotNil(t, err, "Err must be nil")
    718 	assert.IsType(t, InvalidJSONError(""), err, "err must be of type InvalidJSONError")
    719 }
    720 
    721 func TestSkipString(t *testing.T) {
    722 	testCases := []struct {
    723 		name           string
    724 		json           string
    725 		expectedResult string
    726 		err            bool
    727 		errType        interface{}
    728 	}{
    729 		{
    730 			name:           "escape quote err",
    731 			json:           `test string \\" escaped"`,
    732 			expectedResult: ``,
    733 			err:            true,
    734 			errType:        InvalidJSONError(""),
    735 		},
    736 		{
    737 			name:           "escape quote err",
    738 			json:           `test string \\\l escaped"`,
    739 			expectedResult: ``,
    740 			err:            true,
    741 			errType:        InvalidJSONError(""),
    742 		},
    743 		{
    744 			name:           "string-solidus",
    745 			json:           `Asia\/Bangkok","enable":true}"`,
    746 			expectedResult: "",
    747 			err:            false,
    748 		},
    749 		{
    750 			name:           "string-unicode",
    751 			json:           `[2]\u66fe\u5b97\u5357"`,
    752 			expectedResult: "",
    753 			err:            false,
    754 		},
    755 	}
    756 
    757 	for _, testCase := range testCases {
    758 		dec := NewDecoder(strings.NewReader(testCase.json))
    759 		err := dec.skipString()
    760 		if testCase.err {
    761 			assert.NotNil(t, err, "err should not be nil")
    762 			if testCase.errType != nil {
    763 				assert.IsType(t, testCase.errType, err, "err should be of expected type")
    764 			}
    765 			return
    766 		}
    767 		assert.Nil(t, err, "err should be nil")
    768 	}
    769 }