github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/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 "runtime" 22 "runtime/debug" 23 "strings" 24 "sync" 25 "testing" 26 "time" 27 28 "github.com/davecgh/go-spew/spew" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestMain(m *testing.M) { 34 go func() { 35 if !debugAsyncGC { 36 return 37 } 38 println("Begin GC looping...") 39 for { 40 runtime.GC() 41 debug.FreeOSMemory() 42 } 43 println("stop GC looping!") 44 }() 45 time.Sleep(time.Millisecond) 46 m.Run() 47 } 48 49 func TestGC(t *testing.T) { 50 if debugSyncGC { 51 return 52 } 53 var w interface{} 54 out, err := decode(TwitterJson, &w, true) 55 if err != nil { 56 t.Fatal(err) 57 } 58 if out != len(TwitterJson) { 59 t.Fatal(out) 60 } 61 wg := &sync.WaitGroup{} 62 N := 10000 63 for i := 0; i < N; i++ { 64 wg.Add(1) 65 go func(wg *sync.WaitGroup) { 66 defer wg.Done() 67 var w interface{} 68 out, err := decode(TwitterJson, &w, true) 69 if err != nil { 70 t.Error(err) 71 return 72 } 73 if out != len(TwitterJson) { 74 t.Error(out) 75 return 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 err == nil { 127 t.Fatal("invalid error") 128 } 129 }) 130 t.Run("short array", func(t *testing.T) { 131 var obj, obj2 = &[]int{}, &[]int{} 132 var data = `[""]` 133 d := NewDecoder(data) 134 err := d.Decode(obj) 135 err2 := json.Unmarshal([]byte(data), obj2) 136 // println(err2.Error()) 137 assert.Equal(t, err2 == nil, err == nil) 138 // assert.Equal(t, len(data), d.i) 139 assert.Equal(t, obj2, obj) 140 }) 141 142 t.Run("int ", func(t *testing.T) { 143 var obj int = 123 144 var obj2 int = 123 145 var data = `[""]` 146 d := NewDecoder(data) 147 err := d.Decode(&obj) 148 err2 := json.Unmarshal([]byte(data), &obj2) 149 println(err.Error(), obj, obj2) 150 assert.Equal(t, err2 == nil, err == nil) 151 // assert.Equal(t, len(data), d.i) 152 assert.Equal(t, obj2, obj) 153 }) 154 155 t.Run("array", func(t *testing.T) { 156 var obj, obj2 = &[]int{}, &[]int{} 157 var data = `["",true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]` 158 d := NewDecoder(data) 159 err := d.Decode(obj) 160 err2 := json.Unmarshal([]byte(data), obj2) 161 // println(err2.Error()) 162 assert.Equal(t, err2 == nil, err == nil) 163 // assert.Equal(t, len(data), d.i) 164 assert.Equal(t, obj2, obj) 165 }) 166 167 t.Run("map", func(t *testing.T) { 168 var obj, obj2 = &map[int]int{}, &map[int]int{} 169 var data = `{"true" : { },"1":1,"2" : true,"3":3}` 170 d := NewDecoder(data) 171 err := d.Decode(obj) 172 err2 := json.Unmarshal([]byte(data), obj2) 173 assert.Equal(t, err2 == nil, err == nil) 174 // assert.Equal(t, len(data), d.i) 175 assert.Equal(t, obj2, obj) 176 }) 177 t.Run("map error", func(t *testing.T) { 178 var obj, obj2 = &map[int]int{}, &map[int]int{} 179 var data = `{"true" : { ],"1":1,"2" : true,"3":3}` 180 d := NewDecoder(data) 181 err := d.Decode(obj) 182 err2 := json.Unmarshal([]byte(data), obj2) 183 println(err.Error()) 184 println(err2.Error()) 185 assert.Equal(t, err2 == nil, err == nil) 186 // assert.Equal(t, len(data), d.i) 187 // assert.Equal(t, obj2, obj) 188 }) 189 } 190 191 func TestDecodeCorrupt(t *testing.T) { 192 var ds = []string{ 193 `{,}`, 194 `{,"a"}`, 195 `{"a":}`, 196 `{"a":1,}`, 197 `{"a":1,"b"}`, 198 `{"a":1,"b":}`, 199 `{,"a":1 "b":2}`, 200 `{"a",:1 "b":2}`, 201 `{"a":,1 "b":2}`, 202 `{"a":1 "b",:2}`, 203 `{"a":1 "b":,2}`, 204 `{"a":1 "b":2,}`, 205 `{"a":1 "b":2}`, 206 `[,]`, 207 `[,1]`, 208 `[1,]`, 209 `[,1,2]`, 210 `[1,2,]`, 211 } 212 for _, d := range ds { 213 var o interface{} 214 _, err := decode(d, &o, false) 215 if err == nil { 216 t.Fatalf("%#v", d) 217 } 218 if !strings.Contains(err.Error(), "invalid char") { 219 t.Fatal(err.Error()) 220 } 221 } 222 } 223 224 func TestDecodeOption(t *testing.T) { 225 var s string 226 var d *Decoder 227 var out interface{} 228 var out2 struct{} 229 var err error 230 231 s = "123" 232 d = NewDecoder(s) 233 d.SetOptions(OptionUseNumber) 234 err = d.Decode(&out) 235 assert.NoError(t, err) 236 assert.Equal(t, out.(json.Number), json.Number("123")) 237 238 d = NewDecoder(s) 239 err = d.Decode(&out) 240 assert.NoError(t, err) 241 assert.Equal(t, out.(float64), float64(123)) 242 243 s = `{"un": 123}` 244 d = NewDecoder(s) 245 d.SetOptions(OptionDisableUnknown) 246 err = d.Decode(&out2) 247 assert.Error(t, err) 248 249 d = NewDecoder(s) 250 err = d.Decode(&out2) 251 assert.NoError(t, err) 252 } 253 254 func decode(s string, v interface{}, copy bool) (int, error) { 255 d := NewDecoder(s) 256 if copy { 257 d.CopyString() 258 } 259 err := d.Decode(v) 260 if err != nil { 261 return 0, err 262 } 263 return len(s), err 264 } 265 266 func TestDecoder_Basic(t *testing.T) { 267 var v int 268 pos, err := decode("12345", &v, false) 269 assert.NoError(t, err) 270 assert.Equal(t, 5, pos) 271 assert.Equal(t, 12345, v) 272 } 273 274 func TestDecoder_Generic(t *testing.T) { 275 var v interface{} 276 pos, err := decode(TwitterJson, &v, false) 277 assert.NoError(t, err) 278 assert.Equal(t, len(TwitterJson), pos) 279 } 280 281 func TestDecoder_Binding(t *testing.T) { 282 var v TwitterStruct 283 pos, err := decode(TwitterJson, &v, false) 284 assert.NoError(t, err) 285 assert.Equal(t, len(TwitterJson), pos) 286 assert.Equal(t, _BindingValue, v, 0) 287 spew.Dump(v) 288 } 289 290 func TestDecoder_MapWithIndirectElement(t *testing.T) { 291 var v map[string]struct{ A [129]byte } 292 _, err := decode(`{"":{"A":[1,2,3,4,5]}}`, &v, false) 293 require.NoError(t, err) 294 assert.Equal(t, [129]byte{1, 2, 3, 4, 5}, v[""].A) 295 } 296 297 func BenchmarkDecoder_Generic_Sonic(b *testing.B) { 298 var w interface{} 299 _, _ = decode(TwitterJson, &w, true) 300 b.SetBytes(int64(len(TwitterJson))) 301 b.ResetTimer() 302 for i := 0; i < b.N; i++ { 303 var v interface{} 304 _, _ = decode(TwitterJson, &v, true) 305 } 306 } 307 308 func BenchmarkDecoder_Generic_Sonic_Fast(b *testing.B) { 309 var w interface{} 310 _, _ = decode(TwitterJson, &w, false) 311 b.SetBytes(int64(len(TwitterJson))) 312 b.ResetTimer() 313 for i := 0; i < b.N; i++ { 314 var v interface{} 315 _, _ = decode(TwitterJson, &v, false) 316 } 317 } 318 319 func BenchmarkDecoder_Generic_StdLib(b *testing.B) { 320 var w interface{} 321 m := []byte(TwitterJson) 322 _ = json.Unmarshal(m, &w) 323 b.SetBytes(int64(len(TwitterJson))) 324 b.ResetTimer() 325 for i := 0; i < b.N; i++ { 326 var v interface{} 327 _ = json.Unmarshal(m, &v) 328 } 329 } 330 331 func BenchmarkDecoder_Binding_Sonic(b *testing.B) { 332 var w TwitterStruct 333 _, _ = decode(TwitterJson, &w, true) 334 b.SetBytes(int64(len(TwitterJson))) 335 b.ResetTimer() 336 for i := 0; i < b.N; i++ { 337 var v TwitterStruct 338 _, _ = decode(TwitterJson, &v, true) 339 } 340 } 341 342 func BenchmarkDecoder_Binding_Sonic_Fast(b *testing.B) { 343 var w TwitterStruct 344 _, _ = decode(TwitterJson, &w, false) 345 b.SetBytes(int64(len(TwitterJson))) 346 b.ResetTimer() 347 for i := 0; i < b.N; i++ { 348 var v TwitterStruct 349 _, _ = decode(TwitterJson, &v, false) 350 } 351 } 352 353 func BenchmarkDecoder_Binding_StdLib(b *testing.B) { 354 var w TwitterStruct 355 m := []byte(TwitterJson) 356 _ = json.Unmarshal(m, &w) 357 b.SetBytes(int64(len(TwitterJson))) 358 b.ResetTimer() 359 for i := 0; i < b.N; i++ { 360 var v TwitterStruct 361 _ = json.Unmarshal(m, &v) 362 } 363 } 364 365 func BenchmarkDecoder_Parallel_Generic_Sonic(b *testing.B) { 366 var w interface{} 367 _, _ = decode(TwitterJson, &w, true) 368 b.SetBytes(int64(len(TwitterJson))) 369 b.ResetTimer() 370 b.RunParallel(func(pb *testing.PB) { 371 for pb.Next() { 372 var v interface{} 373 _, _ = decode(TwitterJson, &v, true) 374 } 375 }) 376 } 377 378 func BenchmarkDecoder_Parallel_Generic_Sonic_Fast(b *testing.B) { 379 var w interface{} 380 _, _ = decode(TwitterJson, &w, false) 381 b.SetBytes(int64(len(TwitterJson))) 382 b.ResetTimer() 383 b.RunParallel(func(pb *testing.PB) { 384 for pb.Next() { 385 var v interface{} 386 _, _ = decode(TwitterJson, &v, false) 387 } 388 }) 389 } 390 391 func BenchmarkDecoder_Parallel_Generic_StdLib(b *testing.B) { 392 var w interface{} 393 m := []byte(TwitterJson) 394 _ = json.Unmarshal(m, &w) 395 b.SetBytes(int64(len(TwitterJson))) 396 b.ResetTimer() 397 b.RunParallel(func(pb *testing.PB) { 398 for pb.Next() { 399 var v interface{} 400 _ = json.Unmarshal(m, &v) 401 } 402 }) 403 } 404 405 func BenchmarkDecoder_Parallel_Binding_Sonic(b *testing.B) { 406 var w TwitterStruct 407 _, _ = decode(TwitterJson, &w, true) 408 b.SetBytes(int64(len(TwitterJson))) 409 b.ResetTimer() 410 b.RunParallel(func(pb *testing.PB) { 411 for pb.Next() { 412 var v TwitterStruct 413 _, _ = decode(TwitterJson, &v, true) 414 } 415 }) 416 } 417 418 func BenchmarkDecoder_Parallel_Binding_Sonic_Fast(b *testing.B) { 419 var w TwitterStruct 420 _, _ = decode(TwitterJson, &w, false) 421 b.SetBytes(int64(len(TwitterJson))) 422 b.ResetTimer() 423 b.RunParallel(func(pb *testing.PB) { 424 for pb.Next() { 425 var v TwitterStruct 426 _, _ = decode(TwitterJson, &v, false) 427 } 428 }) 429 } 430 431 func BenchmarkDecoder_Parallel_Binding_StdLib(b *testing.B) { 432 var w TwitterStruct 433 m := []byte(TwitterJson) 434 _ = json.Unmarshal(m, &w) 435 b.SetBytes(int64(len(TwitterJson))) 436 b.ResetTimer() 437 b.RunParallel(func(pb *testing.PB) { 438 for pb.Next() { 439 var v TwitterStruct 440 _ = json.Unmarshal(m, &v) 441 } 442 }) 443 }