github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/internal/encoder/assembler_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 encoder
    18  
    19  import (
    20  	"encoding/hex"
    21  	"encoding/json"
    22  	"math"
    23  	"reflect"
    24  	"runtime"
    25  	"strings"
    26  	"testing"
    27  	"unsafe"
    28  
    29  	"github.com/davecgh/go-spew/spew"
    30  	"github.com/goshafaq/sonic/internal/rt"
    31  	"github.com/goshafaq/sonic/option"
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  func TestEncoderMemoryCorruption(t *testing.T) {
    36  	println("TestEncoderMemoryCorruption")
    37  	runtime.GC()
    38  	var m = map[string]interface{}{
    39  		"1": map[string]interface{}{
    40  			`"` + strings.Repeat("a", int(option.DefaultEncoderBufferSize)-38) + `"`: "b",
    41  			"1": map[string]int32{
    42  				"b": 1658219785,
    43  			},
    44  		},
    45  	}
    46  	out, err := Encode(m, SortMapKeys)
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	println(len(out))
    51  	if err := json.Unmarshal(out, &m); err != nil {
    52  		t.Fatal(err)
    53  	}
    54  }
    55  
    56  func TestAssembler_CompileAndLoad(t *testing.T) {
    57  	p, err := newCompiler().compile(reflect.TypeOf((*bool)(nil)), true)
    58  	assert.Nil(t, err)
    59  	a := newAssembler(p)
    60  	f := a.Load()
    61  	s := newStack()
    62  	b := []byte(nil)
    63  
    64  	/* true */
    65  	v := true
    66  	u := &v
    67  	e := f(&b, unsafe.Pointer(&u), s, 0)
    68  	assert.Nil(t, e)
    69  	println(cap(b))
    70  	println(hex.Dump(b))
    71  
    72  	/* false */
    73  	v = false
    74  	u = &v
    75  	b = b[:0]
    76  	e = f(&b, unsafe.Pointer(&u), s, 0)
    77  	assert.Nil(t, e)
    78  	println(cap(b))
    79  	println(hex.Dump(b))
    80  
    81  	/* nil */
    82  	u = nil
    83  	b = b[:0]
    84  	e = f(&b, unsafe.Pointer(&u), s, 0)
    85  	assert.Nil(t, e)
    86  	println(cap(b))
    87  	println(hex.Dump(b))
    88  }
    89  
    90  type testOps struct {
    91  	key string
    92  	ins _Program
    93  	exp string
    94  	err error
    95  	val interface{}
    96  }
    97  
    98  func testOpCode(t *testing.T, v interface{}, ex string, err error, ins _Program) {
    99  	p := ins
   100  	m := []byte(nil)
   101  	s := new(_Stack)
   102  	a := newAssembler(p)
   103  	f := a.Load()
   104  	e := f(&m, rt.UnpackEface(v).Value, s, 0)
   105  	if err != nil {
   106  		assert.EqualError(t, e, err.Error())
   107  	} else {
   108  		assert.Nil(t, e)
   109  		assert.Equal(t, ex, string(m))
   110  	}
   111  }
   112  
   113  type IfaceValue int
   114  
   115  func (IfaceValue) Error() string {
   116  	return "not really implemented"
   117  }
   118  
   119  type JsonMarshalerValue int
   120  
   121  func (JsonMarshalerValue) MarshalJSON() ([]byte, error) {
   122  	return []byte("123456789"), nil
   123  }
   124  
   125  type RecursiveValue struct {
   126  	A int                       `json:"a"`
   127  	P *RecursiveValue           `json:"p,omitempty"`
   128  	Q []RecursiveValue          `json:"q"`
   129  	R map[string]RecursiveValue `json:"r"`
   130  	Z int                       `json:"z"`
   131  }
   132  
   133  func mustCompile(t interface{}) _Program {
   134  	p, err := newCompiler().compile(reflect.TypeOf(t), !rt.UnpackEface(t).Type.Indirect())
   135  	if err != nil {
   136  		panic(err)
   137  	}
   138  	return p
   139  }
   140  
   141  func TestAssembler_OpCode(t *testing.T) {
   142  	var iface error = IfaceValue(12345)
   143  	var eface interface{} = 12345
   144  	var jval = new(JsonMarshalerValue)
   145  	var jifv json.Marshaler = JsonMarshalerValue(0)
   146  	var jifp json.Marshaler = jval
   147  	var rec = &RecursiveValue{
   148  		A: 123,
   149  		Z: 456,
   150  		P: &RecursiveValue{
   151  			A: 789,
   152  			Z: 666,
   153  			P: &RecursiveValue{
   154  				A: 777,
   155  				Z: 888,
   156  				Q: []RecursiveValue{{
   157  					A: 999,
   158  					Z: 222,
   159  					R: map[string]RecursiveValue{
   160  						"xxx": {
   161  							A: 333,
   162  						},
   163  					},
   164  				}},
   165  			},
   166  		},
   167  	}
   168  	tests := []testOps{
   169  		{
   170  			key: "_OP_null",
   171  			ins: []_Instr{newInsOp(_OP_null)},
   172  			exp: "null",
   173  			val: nil,
   174  		}, {
   175  			key: "_OP_bool/true",
   176  			ins: []_Instr{newInsOp(_OP_bool)},
   177  			exp: "true",
   178  			val: true,
   179  		}, {
   180  			key: "_OP_bool/false",
   181  			ins: []_Instr{newInsOp(_OP_bool)},
   182  			exp: "false",
   183  			val: false,
   184  		}, {
   185  			key: "_OP_i8",
   186  			ins: []_Instr{newInsOp(_OP_i8)},
   187  			exp: "-128",
   188  			val: int8(-128),
   189  		}, {
   190  			key: "_OP_i16",
   191  			ins: []_Instr{newInsOp(_OP_i16)},
   192  			exp: "-32768",
   193  			val: int16(-32768),
   194  		}, {
   195  			key: "_OP_i32",
   196  			ins: []_Instr{newInsOp(_OP_i32)},
   197  			exp: "-2147483648",
   198  			val: int32(-2147483648),
   199  		}, {
   200  			key: "_OP_i64",
   201  			ins: []_Instr{newInsOp(_OP_i64)},
   202  			exp: "-9223372036854775808",
   203  			val: int64(math.MinInt64),
   204  		}, {
   205  			key: "_OP_u8",
   206  			ins: []_Instr{newInsOp(_OP_u8)},
   207  			exp: "255",
   208  			val: uint8(255),
   209  		}, {
   210  			key: "_OP_u16",
   211  			ins: []_Instr{newInsOp(_OP_u16)},
   212  			exp: "65535",
   213  			val: uint16(65535),
   214  		}, {
   215  			key: "_OP_u32",
   216  			ins: []_Instr{newInsOp(_OP_u32)},
   217  			exp: "4294967295",
   218  			val: uint32(4294967295),
   219  		}, {
   220  			key: "_OP_u64",
   221  			ins: []_Instr{newInsOp(_OP_u64)},
   222  			exp: "18446744073709551615",
   223  			val: uint64(18446744073709551615),
   224  		}, {
   225  			key: "_OP_f32",
   226  			ins: []_Instr{newInsOp(_OP_f32)},
   227  			exp: "-12.5",
   228  			val: float32(-12.5),
   229  		}, {
   230  			key: "_OP_f32/nan",
   231  			ins: []_Instr{newInsOp(_OP_f32)},
   232  			err: _ERR_nan_or_infinite,
   233  			val: float32(math.NaN()),
   234  		}, {
   235  			key: "_OP_f32/+inf",
   236  			ins: []_Instr{newInsOp(_OP_f32)},
   237  			err: _ERR_nan_or_infinite,
   238  			val: float32(math.Inf(1)),
   239  		}, {
   240  			key: "_OP_f32/-inf",
   241  			ins: []_Instr{newInsOp(_OP_f32)},
   242  			err: _ERR_nan_or_infinite,
   243  			val: float32(math.Inf(-1)),
   244  		}, {
   245  			key: "_OP_f64",
   246  			ins: []_Instr{newInsOp(_OP_f64)},
   247  			exp: "-2.2250738585072014e-308",
   248  			val: -2.2250738585072014e-308,
   249  		}, {
   250  			key: "_OP_f64/nan",
   251  			ins: []_Instr{newInsOp(_OP_f64)},
   252  			err: _ERR_nan_or_infinite,
   253  			val: math.NaN(),
   254  		}, {
   255  			key: "_OP_f64/+inf",
   256  			ins: []_Instr{newInsOp(_OP_f64)},
   257  			err: _ERR_nan_or_infinite,
   258  			val: math.Inf(1),
   259  		}, {
   260  			key: "_OP_f64/-inf",
   261  			ins: []_Instr{newInsOp(_OP_f64)},
   262  			err: _ERR_nan_or_infinite,
   263  			val: math.Inf(-1),
   264  		}, {
   265  			key: "_OP_str",
   266  			ins: []_Instr{newInsOp(_OP_str)},
   267  			exp: `"Cartoonist, Illustrator, and T-Shirt connoisseur"`,
   268  			val: "Cartoonist, Illustrator, and T-Shirt connoisseur",
   269  		}, {
   270  			key: "_OP_str/empty",
   271  			ins: []_Instr{newInsOp(_OP_str)},
   272  			exp: `""`,
   273  			val: "",
   274  		}, {
   275  			key: "_OP_bin",
   276  			ins: []_Instr{newInsOp(_OP_bin)},
   277  			exp: `"AQIDBAU="`,
   278  			val: []byte{1, 2, 3, 4, 5},
   279  		}, {
   280  			key: "_OP_bin/empty",
   281  			ins: []_Instr{newInsOp(_OP_bin)},
   282  			exp: `""`,
   283  			val: []byte{},
   284  		}, {
   285  			key: "_OP_quote",
   286  			ins: []_Instr{newInsOp(_OP_quote)},
   287  			exp: `"\"test\""`,
   288  			val: "test",
   289  		}, {
   290  			key: "_OP_quote/escape",
   291  			ins: []_Instr{newInsOp(_OP_quote)},
   292  			exp: `"\"hello\\n\\t\\rworld\""`,
   293  			val: "hello\n\t\rworld",
   294  		}, {
   295  			key: "_OP_number",
   296  			ins: []_Instr{newInsOp(_OP_number)},
   297  			exp: "1.2345",
   298  			val: "1.2345",
   299  		}, {
   300  			key: "_OP_number/invalid",
   301  			ins: []_Instr{newInsOp(_OP_number)},
   302  			err: error_number("not a number"),
   303  			val: "not a number",
   304  		}, {
   305  			key: "_OP_eface",
   306  			ins: []_Instr{newInsOp(_OP_eface)},
   307  			exp: `12345`,
   308  			val: &eface,
   309  		}, {
   310  			key: "_OP_iface",
   311  			ins: []_Instr{newInsOp(_OP_iface)},
   312  			exp: `12345`,
   313  			val: &iface,
   314  		}, {
   315  			key: "_OP_byte",
   316  			ins: []_Instr{newInsVi(_OP_byte, 'x')},
   317  			exp: "x",
   318  			val: nil,
   319  		}, {
   320  			key: "_OP_text",
   321  			ins: []_Instr{newInsVs(_OP_text, "hello, world !!")},
   322  			exp: "hello, world !!",
   323  			val: nil,
   324  		}, {
   325  			key: "_OP_map_[iter,next,value]",
   326  			ins: mustCompile(map[string]map[int64]int{}),
   327  			exp: `{"asdf":{"-9223372036854775808":1234}}`,
   328  			val: &map[string]map[int64]int{"asdf": {math.MinInt64: 1234}},
   329  		}, {
   330  			key: "_OP_slice_[len,next]",
   331  			ins: mustCompile([][]int{}),
   332  			exp: `[[1,2,3],[4,5,6]]`,
   333  			val: &[][]int{{1, 2, 3}, {4, 5, 6}},
   334  		}, {
   335  			key: "_OP_marshal[_text]",
   336  			ins: []_Instr{newInsVt(_OP_marshal, reflect.TypeOf(JsonMarshalerValue(0)))},
   337  			exp: "123456789",
   338  			val: new(JsonMarshalerValue),
   339  		}, {
   340  			key: "_OP_marshal[_text]/ptr",
   341  			ins: []_Instr{newInsVt(_OP_marshal, reflect.TypeOf(new(JsonMarshalerValue)))},
   342  			exp: "123456789",
   343  			val: &jval,
   344  		}, {
   345  			key: "_OP_marshal[_text]/iface_v",
   346  			ins: []_Instr{newInsVt(_OP_marshal, jsonMarshalerType)},
   347  			exp: "123456789",
   348  			val: &jifv,
   349  		}, {
   350  			key: "_OP_marshal[_text]/iface_p",
   351  			ins: []_Instr{newInsVt(_OP_marshal, jsonMarshalerType)},
   352  			exp: "123456789",
   353  			val: &jifp,
   354  		},
   355  		{
   356  			key: "_OP_recurse",
   357  			ins: mustCompile(rec),
   358  			exp: `{"a":123,"p":{"a":789,"p":{"a":777,"q":[{"a":999,"q":null,"r":{"` +
   359  				`xxx":{"a":333,"q":null,"r":null,"z":0}},"z":222}],"r":null,"z":8` +
   360  				`88},"q":null,"r":null,"z":666},"q":null,"r":null,"z":456}`,
   361  			val: &rec,
   362  		}}
   363  	for _, tv := range tests {
   364  		t.Run(tv.key, func(t *testing.T) {
   365  			testOpCode(t, tv.val, tv.exp, tv.err, tv.ins)
   366  		})
   367  	}
   368  }
   369  
   370  func TestAssembler_StringMoreSpace(t *testing.T) {
   371  	p := _Program{newInsOp(_OP_str)}
   372  	m := make([]byte, 0, 8)
   373  	s := new(_Stack)
   374  	a := newAssembler(p)
   375  	f := a.Load()
   376  	v := "\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u0010"
   377  	e := f(&m, unsafe.Pointer(&v), s, 0)
   378  	assert.Nil(t, e)
   379  	spew.Dump(m)
   380  }
   381  
   382  func TestAssembler_TwitterJSON_Generic(t *testing.T) {
   383  	p := mustCompile(&_GenericValue)
   384  	m := []byte(nil)
   385  	s := new(_Stack)
   386  	a := newAssembler(p)
   387  	f := a.Load()
   388  	v := &_GenericValue
   389  	e := f(&m, unsafe.Pointer(&v), s, 0)
   390  	assert.Nil(t, e)
   391  	println(string(m))
   392  }
   393  
   394  func TestAssembler_TwitterJSON_Structure(t *testing.T) {
   395  	p := mustCompile(_BindingValue)
   396  	m := []byte(nil)
   397  	s := new(_Stack)
   398  	a := newAssembler(p)
   399  	f := a.Load()
   400  	e := f(&m, unsafe.Pointer(&_BindingValue), s, 0)
   401  	assert.Nil(t, e)
   402  	println(string(m))
   403  	runtime.KeepAlive(s)
   404  }
   405  
   406  func TestScratchedString(t *testing.T) {
   407  	fatal := *(*string)(unsafe.Pointer(&rt.GoString{nil, 1}))
   408  	defer func() {
   409  		if v := recover(); v == nil {
   410  			t.Fatal()
   411  		} else if s, ok := v.(string); !ok {
   412  			t.Fatal(v)
   413  		} else {
   414  			if !strings.Contains(s, "has nil pointer while its length is not zero") {
   415  				t.Fatal(s)
   416  			}
   417  		}
   418  	}()
   419  	_, _ = Encode(fatal, 0)
   420  	t.Fatal()
   421  }
   422  
   423  func TestScratchedNumber(t *testing.T) {
   424  	fatal := *(*json.Number)(unsafe.Pointer(&rt.GoString{nil, 1}))
   425  	defer func() {
   426  		if v := recover(); v == nil {
   427  			t.Fatal()
   428  		} else if s, ok := v.(string); !ok {
   429  			t.Fatal(v)
   430  		} else {
   431  			if !strings.Contains(s, "has nil pointer while its length is not zero") {
   432  				t.Fatal(s)
   433  			}
   434  		}
   435  	}()
   436  	_, _ = Encode(fatal, 0)
   437  	t.Fatal()
   438  }