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  }