github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/internal/decoder/decoder_test.go (about) 1 /* 2 * Copyright 2021 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package decoder 18 19 import ( 20 "encoding/json" 21 "reflect" 22 "runtime" 23 "runtime/debug" 24 "strings" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/davecgh/go-spew/spew" 30 "github.com/goshafaq/sonic/internal/rt" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 ) 34 35 func TestMain(m *testing.M) { 36 go func() { 37 if !debugAsyncGC { 38 return 39 } 40 println("Begin GC looping...") 41 for { 42 runtime.GC() 43 debug.FreeOSMemory() 44 } 45 println("stop GC looping!") 46 }() 47 time.Sleep(time.Millisecond) 48 m.Run() 49 } 50 51 func TestGC(t *testing.T) { 52 if debugSyncGC { 53 return 54 } 55 var w interface{} 56 out, err := decode(TwitterJson, &w, true) 57 if err != nil { 58 t.Fatal(err) 59 } 60 if out != len(TwitterJson) { 61 t.Fatal(out) 62 } 63 wg := &sync.WaitGroup{} 64 N := 10000 65 for i := 0; i < N; i++ { 66 wg.Add(1) 67 go func(wg *sync.WaitGroup) { 68 defer wg.Done() 69 var w interface{} 70 out, err := decode(TwitterJson, &w, true) 71 if err != nil { 72 t.Fatal(err) 73 } 74 if out != len(TwitterJson) { 75 t.Fatal(out) 76 } 77 runtime.GC() 78 }(wg) 79 } 80 wg.Wait() 81 } 82 83 var _BindingValue TwitterStruct 84 85 func init() { 86 _ = json.Unmarshal([]byte(TwitterJson), &_BindingValue) 87 } 88 89 func TestSkipMismatchTypeError(t *testing.T) { 90 t.Run("struct", func(t *testing.T) { 91 println("TestSkipError") 92 type skiptype struct { 93 A int `json:"a"` 94 B string `json:"b"` 95 96 Pass *int `json:"pass"` 97 98 C struct { 99 Pass4 interface{} `json:"pass4"` 100 101 D struct { 102 E float32 `json:"e"` 103 } `json:"d"` 104 105 Pass2 int `json:"pass2"` 106 } `json:"c"` 107 108 E bool `json:"e"` 109 F []int `json:"f"` 110 G map[string]int `json:"g"` 111 H bool `json:"h,string"` 112 113 Pass3 int `json:"pass2"` 114 115 I json.Number `json:"i"` 116 } 117 var obj, obj2 = &skiptype{Pass: new(int)}, &skiptype{Pass: new(int)} 118 var data = `{"a":"","b":1,"c":{"d":true,"pass2":1,"pass4":true},"e":{},"f":"","g":[],"pass":null,"h":"1.0","i":true,"pass3":1}` 119 d := NewDecoder(data) 120 err := d.Decode(obj) 121 err2 := json.Unmarshal([]byte(data), obj2) 122 println(err2.Error()) 123 assert.Equal(t, err2 == nil, err == nil) 124 // assert.Equal(t, len(data), d.i) 125 assert.Equal(t, obj2, obj) 126 if te, ok := err.(*MismatchTypeError); ok { 127 assert.Equal(t, reflect.TypeOf(obj.I), te.Type) 128 assert.Equal(t, strings.Index(data, `"i":t`)+4, te.Pos) 129 println(err.Error()) 130 } else { 131 t.Fatal("invalid error") 132 } 133 }) 134 t.Run("short array", func(t *testing.T) { 135 var obj, obj2 = &[]int{}, &[]int{} 136 var data = `[""]` 137 d := NewDecoder(data) 138 err := d.Decode(obj) 139 err2 := json.Unmarshal([]byte(data), obj2) 140 // println(err2.Error()) 141 assert.Equal(t, err2 == nil, err == nil) 142 // assert.Equal(t, len(data), d.i) 143 assert.Equal(t, obj2, obj) 144 }) 145 146 t.Run("int ", func(t *testing.T) { 147 var obj int = 123 148 var obj2 int = 123 149 var data = `[""]` 150 d := NewDecoder(data) 151 err := d.Decode(&obj) 152 err2 := json.Unmarshal([]byte(data), &obj2) 153 println(err.Error(), obj, obj2) 154 assert.Equal(t, err2 == nil, err == nil) 155 // assert.Equal(t, len(data), d.i) 156 assert.Equal(t, obj2, obj) 157 }) 158 159 t.Run("array", func(t *testing.T) { 160 var obj, obj2 = &[]int{}, &[]int{} 161 var data = `["",true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]` 162 d := NewDecoder(data) 163 err := d.Decode(obj) 164 err2 := json.Unmarshal([]byte(data), obj2) 165 // println(err2.Error()) 166 assert.Equal(t, err2 == nil, err == nil) 167 // assert.Equal(t, len(data), d.i) 168 assert.Equal(t, obj2, obj) 169 }) 170 171 t.Run("map", func(t *testing.T) { 172 var obj, obj2 = &map[int]int{}, &map[int]int{} 173 var data = `{"true" : { },"1":1,"2" : true,"3":3}` 174 d := NewDecoder(data) 175 err := d.Decode(obj) 176 err2 := json.Unmarshal([]byte(data), obj2) 177 assert.Equal(t, err2 == nil, err == nil) 178 // assert.Equal(t, len(data), d.i) 179 assert.Equal(t, obj2, obj) 180 }) 181 t.Run("map error", func(t *testing.T) { 182 var obj, obj2 = &map[int]int{}, &map[int]int{} 183 var data = `{"true" : { ],"1":1,"2" : true,"3":3}` 184 d := NewDecoder(data) 185 err := d.Decode(obj) 186 err2 := json.Unmarshal([]byte(data), obj2) 187 println(err.Error()) 188 println(err2.Error()) 189 assert.Equal(t, err2 == nil, err == nil) 190 // assert.Equal(t, len(data), d.i) 191 // assert.Equal(t, obj2, obj) 192 }) 193 } 194 195 func TestDecodeCorrupt(t *testing.T) { 196 var ds = []string{ 197 `{,}`, 198 `{,"a"}`, 199 `{"a":}`, 200 `{"a":1,}`, 201 `{"a":1,"b"}`, 202 `{"a":1,"b":}`, 203 `{,"a":1 "b":2}`, 204 `{"a",:1 "b":2}`, 205 `{"a":,1 "b":2}`, 206 `{"a":1 "b",:2}`, 207 `{"a":1 "b":,2}`, 208 `{"a":1 "b":2,}`, 209 `{"a":1 "b":2}`, 210 `[,]`, 211 `[,1]`, 212 `[1,]`, 213 `[,1,2]`, 214 `[1,2,]`, 215 } 216 for _, d := range ds { 217 var o interface{} 218 _, err := decode(d, &o, false) 219 if err == nil { 220 t.Fatalf("%#v", d) 221 } 222 if !strings.Contains(err.Error(), "invalid char") { 223 t.Fatal(err.Error()) 224 } 225 } 226 } 227 228 func decode(s string, v interface{}, copy bool) (int, error) { 229 d := NewDecoder(s) 230 if copy { 231 d.CopyString() 232 } 233 err := d.Decode(v) 234 if err != nil { 235 return 0, err 236 } 237 return d.i, err 238 } 239 240 func TestCopyString(t *testing.T) { 241 var data []byte 242 var dc *Decoder 243 var err error 244 data = []byte(`{"A":"0","B":"1"}`) 245 dc = NewDecoder(rt.Mem2Str(data)) 246 dc.UseNumber() 247 dc.CopyString() 248 var obj struct { 249 A string 250 B string 251 } 252 err = dc.Decode(&obj) 253 if err != nil { 254 t.Fatal(err) 255 } 256 data[6] = '1' 257 if obj.A != "0" { 258 t.Fatal(obj) 259 } 260 data[14] = '0' 261 if obj.B != "1" { 262 t.Fatal(obj) 263 } 264 265 data = []byte(`{"A":"0","B":"1"}`) 266 dc = NewDecoder(rt.Mem2Str(data)) 267 dc.UseNumber() 268 err = dc.Decode(&obj) 269 if err != nil { 270 t.Fatal(err) 271 } 272 data[6] = '1' 273 if obj.A != "1" { 274 t.Fatal(obj) 275 } 276 data[14] = '0' 277 if obj.B != "0" { 278 t.Fatal(obj) 279 } 280 281 data = []byte(`{"A":"0","B":"1"}`) 282 dc = NewDecoder(rt.Mem2Str(data)) 283 dc.UseNumber() 284 dc.CopyString() 285 m := map[string]interface{}{} 286 err = dc.Decode(&m) 287 if err != nil { 288 t.Fatal(err) 289 } 290 data[2] = 'C' 291 data[6] = '1' 292 if m["A"] != "0" { 293 t.Fatal(m) 294 } 295 data[10] = 'D' 296 data[14] = '0' 297 if m["B"] != "1" { 298 t.Fatal(m) 299 } 300 301 data = []byte(`{"A":"0","B":"1"}`) 302 dc = NewDecoder(rt.Mem2Str(data)) 303 dc.UseNumber() 304 m = map[string]interface{}{} 305 err = dc.Decode(&m) 306 if err != nil { 307 t.Fatal(err) 308 } 309 data[6] = '1' 310 if m["A"] != "1" { 311 t.Fatal(m) 312 } 313 data[14] = '0' 314 if m["B"] != "0" { 315 t.Fatal(m) 316 } 317 318 data = []byte(`{"A":"0","B":"1"}`) 319 dc = NewDecoder(rt.Mem2Str(data)) 320 dc.UseNumber() 321 dc.CopyString() 322 var x interface{} 323 err = dc.Decode(&x) 324 if err != nil { 325 t.Fatal(err) 326 } 327 data[2] = 'C' 328 data[6] = '1' 329 m = x.(map[string]interface{}) 330 if m["A"] != "0" { 331 t.Fatal(m) 332 } 333 data[10] = 'D' 334 data[14] = '0' 335 if m["B"] != "1" { 336 t.Fatal(m) 337 } 338 339 data = []byte(`{"A":"0","B":"1"}`) 340 dc = NewDecoder(rt.Mem2Str(data)) 341 dc.UseNumber() 342 var y interface{} 343 err = dc.Decode(&y) 344 if err != nil { 345 t.Fatal(err) 346 } 347 m = y.(map[string]interface{}) 348 data[6] = '1' 349 if m["A"] != "1" { 350 t.Fatal(m) 351 } 352 data[14] = '0' 353 if m["B"] != "0" { 354 t.Fatal(m) 355 } 356 } 357 358 func TestDecoder_Basic(t *testing.T) { 359 var v int 360 pos, err := decode("12345", &v, false) 361 assert.NoError(t, err) 362 assert.Equal(t, 5, pos) 363 assert.Equal(t, 12345, v) 364 } 365 366 func TestDecoder_Generic(t *testing.T) { 367 var v interface{} 368 pos, err := decode(TwitterJson, &v, false) 369 assert.NoError(t, err) 370 assert.Equal(t, len(TwitterJson), pos) 371 } 372 373 func TestDecoder_Binding(t *testing.T) { 374 var v TwitterStruct 375 pos, err := decode(TwitterJson, &v, false) 376 assert.NoError(t, err) 377 assert.Equal(t, len(TwitterJson), pos) 378 assert.Equal(t, _BindingValue, v, 0) 379 spew.Dump(v) 380 } 381 382 func TestDecoder_SetOption(t *testing.T) { 383 var v interface{} 384 d := NewDecoder("123") 385 d.SetOptions(OptionUseInt64) 386 err := d.Decode(&v) 387 assert.NoError(t, err) 388 assert.Equal(t, v, int64(123)) 389 } 390 391 func TestDecoder_MapWithIndirectElement(t *testing.T) { 392 var v map[string]struct{ A [129]byte } 393 _, err := decode(`{"":{"A":[1,2,3,4,5]}}`, &v, false) 394 if x, ok := err.(SyntaxError); ok { 395 println(x.Description()) 396 } 397 require.NoError(t, err) 398 assert.Equal(t, [129]byte{1, 2, 3, 4, 5}, v[""].A) 399 } 400 401 func BenchmarkDecoder_Generic_Sonic(b *testing.B) { 402 var w interface{} 403 _, _ = decode(TwitterJson, &w, true) 404 b.SetBytes(int64(len(TwitterJson))) 405 b.ResetTimer() 406 for i := 0; i < b.N; i++ { 407 var v interface{} 408 _, _ = decode(TwitterJson, &v, true) 409 } 410 } 411 412 func BenchmarkDecoder_Generic_Sonic_Fast(b *testing.B) { 413 var w interface{} 414 _, _ = decode(TwitterJson, &w, false) 415 b.SetBytes(int64(len(TwitterJson))) 416 b.ResetTimer() 417 for i := 0; i < b.N; i++ { 418 var v interface{} 419 _, _ = decode(TwitterJson, &v, false) 420 } 421 } 422 423 func BenchmarkDecoder_Generic_StdLib(b *testing.B) { 424 var w interface{} 425 m := []byte(TwitterJson) 426 _ = json.Unmarshal(m, &w) 427 b.SetBytes(int64(len(TwitterJson))) 428 b.ResetTimer() 429 for i := 0; i < b.N; i++ { 430 var v interface{} 431 _ = json.Unmarshal(m, &v) 432 } 433 } 434 435 func BenchmarkDecoder_Binding_Sonic(b *testing.B) { 436 var w TwitterStruct 437 _, _ = decode(TwitterJson, &w, true) 438 b.SetBytes(int64(len(TwitterJson))) 439 b.ResetTimer() 440 for i := 0; i < b.N; i++ { 441 var v TwitterStruct 442 _, _ = decode(TwitterJson, &v, true) 443 } 444 } 445 446 func BenchmarkDecoder_Binding_Sonic_Fast(b *testing.B) { 447 var w TwitterStruct 448 _, _ = decode(TwitterJson, &w, false) 449 b.SetBytes(int64(len(TwitterJson))) 450 b.ResetTimer() 451 for i := 0; i < b.N; i++ { 452 var v TwitterStruct 453 _, _ = decode(TwitterJson, &v, false) 454 } 455 } 456 457 func BenchmarkDecoder_Binding_StdLib(b *testing.B) { 458 var w TwitterStruct 459 m := []byte(TwitterJson) 460 _ = json.Unmarshal(m, &w) 461 b.SetBytes(int64(len(TwitterJson))) 462 b.ResetTimer() 463 for i := 0; i < b.N; i++ { 464 var v TwitterStruct 465 _ = json.Unmarshal(m, &v) 466 } 467 } 468 469 func BenchmarkDecoder_Parallel_Generic_Sonic(b *testing.B) { 470 var w interface{} 471 _, _ = decode(TwitterJson, &w, true) 472 b.SetBytes(int64(len(TwitterJson))) 473 b.ResetTimer() 474 b.RunParallel(func(pb *testing.PB) { 475 for pb.Next() { 476 var v interface{} 477 _, _ = decode(TwitterJson, &v, true) 478 } 479 }) 480 } 481 482 func BenchmarkDecoder_Parallel_Generic_Sonic_Fast(b *testing.B) { 483 var w interface{} 484 _, _ = decode(TwitterJson, &w, false) 485 b.SetBytes(int64(len(TwitterJson))) 486 b.ResetTimer() 487 b.RunParallel(func(pb *testing.PB) { 488 for pb.Next() { 489 var v interface{} 490 _, _ = decode(TwitterJson, &v, false) 491 } 492 }) 493 } 494 495 func BenchmarkDecoder_Parallel_Generic_StdLib(b *testing.B) { 496 var w interface{} 497 m := []byte(TwitterJson) 498 _ = json.Unmarshal(m, &w) 499 b.SetBytes(int64(len(TwitterJson))) 500 b.ResetTimer() 501 b.RunParallel(func(pb *testing.PB) { 502 for pb.Next() { 503 var v interface{} 504 _ = json.Unmarshal(m, &v) 505 } 506 }) 507 } 508 509 func BenchmarkDecoder_Parallel_Binding_Sonic(b *testing.B) { 510 var w TwitterStruct 511 _, _ = decode(TwitterJson, &w, true) 512 b.SetBytes(int64(len(TwitterJson))) 513 b.ResetTimer() 514 b.RunParallel(func(pb *testing.PB) { 515 for pb.Next() { 516 var v TwitterStruct 517 _, _ = decode(TwitterJson, &v, true) 518 } 519 }) 520 } 521 522 func BenchmarkDecoder_Parallel_Binding_Sonic_Fast(b *testing.B) { 523 var w TwitterStruct 524 _, _ = decode(TwitterJson, &w, false) 525 b.SetBytes(int64(len(TwitterJson))) 526 b.ResetTimer() 527 b.RunParallel(func(pb *testing.PB) { 528 for pb.Next() { 529 var v TwitterStruct 530 _, _ = decode(TwitterJson, &v, false) 531 } 532 }) 533 } 534 535 func BenchmarkDecoder_Parallel_Binding_StdLib(b *testing.B) { 536 var w TwitterStruct 537 m := []byte(TwitterJson) 538 _ = json.Unmarshal(m, &w) 539 b.SetBytes(int64(len(TwitterJson))) 540 b.ResetTimer() 541 b.RunParallel(func(pb *testing.PB) { 542 for pb.Next() { 543 var v TwitterStruct 544 _ = json.Unmarshal(m, &v) 545 } 546 }) 547 } 548 549 func BenchmarkSkip_Sonic(b *testing.B) { 550 var data = rt.Str2Mem(TwitterJson) 551 if ret, _ := Skip(data); ret < 0 { 552 b.Fatal() 553 } 554 b.SetBytes(int64(len(TwitterJson))) 555 b.ResetTimer() 556 for i := 0; i < b.N; i++ { 557 _, _ = Skip(data) 558 } 559 }