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  }