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