github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/ast/parser_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 ast
    18  
    19  import (
    20      `encoding/json`
    21      `os`
    22      `runtime`
    23      `runtime/debug`
    24      `sync`
    25      `testing`
    26      `time`
    27  
    28      `github.com/stretchr/testify/assert`
    29      `github.com/stretchr/testify/require`
    30  )
    31  
    32  var (
    33      debugSyncGC  = os.Getenv("SONIC_SYNC_GC")  != ""
    34      debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
    35  )
    36  
    37  func TestMain(m *testing.M) {
    38      go func ()  {
    39          if !debugAsyncGC {
    40              return
    41          }
    42          println("Begin GC looping...")
    43          for {
    44              runtime.GC()
    45              debug.FreeOSMemory()
    46          }
    47          println("stop GC looping!")
    48      }()
    49      time.Sleep(time.Millisecond)
    50      m.Run()
    51  }
    52  
    53  func TestGC_Parse(t *testing.T) {
    54      if debugSyncGC {
    55          return
    56      }
    57      _, _, err := Loads(_TwitterJson)
    58      if err != nil {
    59          t.Fatal(err)
    60      }
    61      wg := &sync.WaitGroup{}
    62      N := 1000
    63      for i:=0; i<N; i++ {
    64          wg.Add(1)
    65          go func (wg *sync.WaitGroup)  {
    66              defer wg.Done()
    67              _, _, err := Loads(_TwitterJson)
    68              if err != nil {
    69                  t.Error(err)
    70                  return
    71              }
    72              runtime.GC()
    73          }(wg)
    74      }
    75      wg.Wait()
    76  }
    77  
    78  func runDecoderTest(t *testing.T, src string, expect interface{}) {
    79      vv, err := NewParser(src).Parse()
    80      if err != 0 { panic(err) }
    81      x, _ := vv.Interface()
    82      assert.Equal(t, expect, x)
    83  }
    84  
    85  func runDecoderTestUseNumber(t *testing.T, src string, expect interface{}) {
    86      vv, err := NewParser(src).Parse()
    87      if err != 0 { panic(err) }
    88      vvv, _ := vv.InterfaceUseNumber()
    89      switch vvv.(type) {
    90      case json.Number:
    91          assert.Equal(t, expect, n2f64(vvv.(json.Number)))
    92      case []interface{}:
    93          x := vvv.([]interface{})
    94          for i, e := range x {
    95              if ev,ok := e.(json.Number);ok {
    96                  x[i] = n2f64(ev)
    97              }
    98          }
    99          assert.Equal(t, expect, x)
   100      case map[string]interface{}:
   101          x := vvv.(map[string]interface{})
   102          for k,v := range x {
   103              if ev, ok := v.(json.Number); ok {
   104                  x[k] = n2f64(ev)
   105              }
   106          }
   107          assert.Equal(t, expect, x)
   108      }
   109  }
   110  
   111  func n2f64(i json.Number) float64{
   112      x, err := i.Float64()
   113      if err != nil {
   114          panic(err)
   115      }
   116      return x
   117  }
   118  
   119  func TestParser_Basic(t *testing.T) {
   120      runDecoderTest(t, `null`, nil)
   121      runDecoderTest(t, `true`, true)
   122      runDecoderTest(t, `false`, false)
   123      runDecoderTest(t, `"hello, world \\ \/ \b \f \n \r \t \u666f 测试中文"`, "hello, world \\ / \b \f \n \r \t \u666f 测试中文")
   124      runDecoderTest(t, `"\ud83d\ude00"`, "😀")
   125      runDecoderTest(t, `0`, float64(0))
   126      runDecoderTest(t, `-0`, float64(0))
   127      runDecoderTest(t, `123456`, float64(123456))
   128      runDecoderTest(t, `-12345`, float64(-12345))
   129      runDecoderTest(t, `0.2`, 0.2)
   130      runDecoderTest(t, `1.2`, 1.2)
   131      runDecoderTest(t, `-0.2`, -0.2)
   132      runDecoderTest(t, `-1.2`, -1.2)
   133      runDecoderTest(t, `0e12`, 0e12)
   134      runDecoderTest(t, `0e+12`, 0e+12)
   135      runDecoderTest(t, `0e-12`, 0e-12)
   136      runDecoderTest(t, `-0e12`, -0e12)
   137      runDecoderTest(t, `-0e+12`, -0e+12)
   138      runDecoderTest(t, `-0e-12`, -0e-12)
   139      runDecoderTest(t, `2e12`, 2e12)
   140      runDecoderTest(t, `2E12`, 2e12)
   141      runDecoderTest(t, `2e+12`, 2e+12)
   142      runDecoderTest(t, `2e-12`, 2e-12)
   143      runDecoderTest(t, `-2e12`, -2e12)
   144      runDecoderTest(t, `-2e+12`, -2e+12)
   145      runDecoderTest(t, `-2e-12`, -2e-12)
   146      runDecoderTest(t, `0.2e12`, 0.2e12)
   147      runDecoderTest(t, `0.2e+12`, 0.2e+12)
   148      runDecoderTest(t, `0.2e-12`, 0.2e-12)
   149      runDecoderTest(t, `-0.2e12`, -0.2e12)
   150      runDecoderTest(t, `-0.2e+12`, -0.2e+12)
   151      runDecoderTest(t, `-0.2e-12`, -0.2e-12)
   152      runDecoderTest(t, `1.2e12`, 1.2e12)
   153      runDecoderTest(t, `1.2e+12`, 1.2e+12)
   154      runDecoderTest(t, `1.2e-12`, 1.2e-12)
   155      runDecoderTest(t, `-1.2e12`, -1.2e12)
   156      runDecoderTest(t, `-1.2e+12`, -1.2e+12)
   157      runDecoderTest(t, `-1.2e-12`, -1.2e-12)
   158      runDecoderTest(t, `-1.2E-12`, -1.2e-12)
   159      runDecoderTest(t, `[]`, []interface{}{})
   160      runDecoderTest(t, `{}`, map[string]interface{}{})
   161      runDecoderTest(t, `["asd", "123", true, false, null, 2.4, 1.2e15]`, []interface{}{"asd", "123", true, false, nil, 2.4, 1.2e15})
   162      runDecoderTest(t, `{"asdf": "qwer", "zxcv": true}`, map[string]interface{}{"asdf": "qwer", "zxcv": true})
   163      runDecoderTest(t, `{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`, map[string]interface{}{"a":"123", "b":true, "c":false, "d":nil, "e": 2.4, "f": 1.2e15, "g":float64(1)})
   164  
   165      runDecoderTestUseNumber(t, `null`, nil)
   166      runDecoderTestUseNumber(t, `true`, true)
   167      runDecoderTestUseNumber(t, `false`, false)
   168      runDecoderTestUseNumber(t, `"hello, world \\ \/ \b \f \n \r \t \u666f 测试中文"`, "hello, world \\ / \b \f \n \r \t \u666f 测试中文")
   169      runDecoderTestUseNumber(t, `"\ud83d\ude00"`, "😀")
   170      runDecoderTestUseNumber(t, `0`, float64(0))
   171      runDecoderTestUseNumber(t, `-0`, float64(0))
   172      runDecoderTestUseNumber(t, `123456`, float64(123456))
   173      runDecoderTestUseNumber(t, `-12345`, float64(-12345))
   174      runDecoderTestUseNumber(t, `0.2`, 0.2)
   175      runDecoderTestUseNumber(t, `1.2`, 1.2)
   176      runDecoderTestUseNumber(t, `-0.2`, -0.2)
   177      runDecoderTestUseNumber(t, `-1.2`, -1.2)
   178      runDecoderTestUseNumber(t, `0e12`, 0e12)
   179      runDecoderTestUseNumber(t, `0e+12`, 0e+12)
   180      runDecoderTestUseNumber(t, `0e-12`, 0e-12)
   181      runDecoderTestUseNumber(t, `-0e12`, -0e12)
   182      runDecoderTestUseNumber(t, `-0e+12`, -0e+12)
   183      runDecoderTestUseNumber(t, `-0e-12`, -0e-12)
   184      runDecoderTestUseNumber(t, `2e12`, 2e12)
   185      runDecoderTestUseNumber(t, `2E12`, 2e12)
   186      runDecoderTestUseNumber(t, `2e+12`, 2e+12)
   187      runDecoderTestUseNumber(t, `2e-12`, 2e-12)
   188      runDecoderTestUseNumber(t, `-2e12`, -2e12)
   189      runDecoderTestUseNumber(t, `-2e+12`, -2e+12)
   190      runDecoderTestUseNumber(t, `-2e-12`, -2e-12)
   191      runDecoderTestUseNumber(t, `0.2e12`, 0.2e12)
   192      runDecoderTestUseNumber(t, `0.2e+12`, 0.2e+12)
   193      runDecoderTestUseNumber(t, `0.2e-12`, 0.2e-12)
   194      runDecoderTestUseNumber(t, `-0.2e12`, -0.2e12)
   195      runDecoderTestUseNumber(t, `-0.2e+12`, -0.2e+12)
   196      runDecoderTestUseNumber(t, `-0.2e-12`, -0.2e-12)
   197      runDecoderTestUseNumber(t, `1.2e12`, 1.2e12)
   198      runDecoderTestUseNumber(t, `1.2e+12`, 1.2e+12)
   199      runDecoderTestUseNumber(t, `1.2e-12`, 1.2e-12)
   200      runDecoderTestUseNumber(t, `-1.2e12`, -1.2e12)
   201      runDecoderTestUseNumber(t, `-1.2e+12`, -1.2e+12)
   202      runDecoderTestUseNumber(t, `-1.2e-12`, -1.2e-12)
   203      runDecoderTestUseNumber(t, `-1.2E-12`, -1.2e-12)
   204      runDecoderTestUseNumber(t, `["asd", "123", true, false, null, 2.4, 1.2e15, 1]`, []interface{}{"asd", "123", true, false, nil, 2.4, 1.2e15, float64(1)})
   205      runDecoderTestUseNumber(t, `{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`, map[string]interface{}{"a":"123", "b":true, "c":false, "d":nil, "e": 2.4, "f": 1.2e15, "g":float64(1)})
   206  }
   207  
   208  func TestLoads(t *testing.T) {
   209      _,i,e := Loads(`{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`)
   210      if e != nil {
   211          t.Fatal(e)
   212      }
   213      assert.Equal(t, map[string]interface{}{"a": "123", "b": true, "c": false, "d": nil, "e": 2.4, "f": 1.2e15, "g": float64(1)}, i)
   214      _,i,e = LoadsUseNumber(`{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`)
   215      if e != nil {
   216          t.Fatal(e)
   217      }
   218      assert.Equal(t, map[string]interface{}{"a": "123", "b": true, "c": false, "d": nil, "e": json.Number("2.4"), "f": json.Number("1.2e15"), "g": json.Number("1")}, i)
   219  }
   220  
   221  func TestParsehNotExist(t *testing.T) {
   222      s,err := NewParser(` { "xx" : [ 0, "" ] ,"yy" :{ "2": "" } } `).Parse()
   223      if err != 0 {
   224          t.Fatal(err)
   225      }
   226      node := s.GetByPath("xx", 2)
   227      if node.Exists() {
   228          t.Fatalf("node: %v", node)
   229      }
   230      node = s.GetByPath("xx", 1)
   231      if !node.Exists() {
   232          t.Fatalf("node: %v", nil)
   233      }
   234      node = s.GetByPath("yy", "3")
   235      if node.Exists() {
   236          t.Fatalf("node: %v", node)
   237      }
   238      node = s.GetByPath("yy", "2")
   239      if !node.Exists() {
   240          t.Fatalf("node: %v", nil)
   241      }
   242  }
   243  
   244  func BenchmarkParser_Sonic(b *testing.B) {
   245      r, err := NewParser(_TwitterJson).Parse()
   246      if err != 0 {
   247          b.Fatal(err)
   248      }
   249      if err := r.LoadAll(); err != nil {
   250          b.Fatal(err)
   251      }
   252      b.SetBytes(int64(len(_TwitterJson)))
   253      b.ResetTimer()
   254      for i := 0; i < b.N; i++ {
   255          r, _ = NewParser(_TwitterJson).Parse()
   256          _ = r.LoadAll()
   257      }
   258  }
   259  
   260  func BenchmarkParser_Parallel_Sonic(b *testing.B) {
   261      r, _ := NewParser(_TwitterJson).Parse()
   262      if err := r.LoadAll(); err != nil {
   263          b.Fatal(err)
   264      }
   265      b.SetBytes(int64(len(_TwitterJson)))
   266      b.ResetTimer()
   267      b.RunParallel(func(pb *testing.PB) {
   268          for pb.Next() {
   269              r, _ := NewParser(_TwitterJson).Parse()
   270              _ = r.LoadAll()
   271          }
   272      })
   273  }
   274  
   275  func BenchmarkParseEmpty_Sonic(b *testing.B) {
   276      var emptySample = `{"a":[],"b":{},"c":[{},{},{},{}],"d":{"e":[],"f":[],"g":[],"h":[]}}`
   277      p := NewParserObj(emptySample)
   278      ast, _ := p.Parse()
   279      require.NoError(b, ast.LoadAll())
   280      b.SetBytes(int64(len(_TwitterJson)))
   281      b.ResetTimer()
   282      for i := 0; i < b.N; i++ {
   283          p := NewParserObj(emptySample)
   284          ast, _ := p.Parse()
   285          _ = ast.LoadAll()
   286      }
   287  }
   288  
   289  func BenchmarkParseOne_Sonic(b *testing.B) {
   290      ast, _ := NewParser(_TwitterJson).Parse()
   291      node, _ := ast.Get("statuses").Index(2).Get("id").Int64()
   292      if node != 249289491129438208 {
   293          b.Fail()
   294      }
   295      b.SetBytes(int64(len(_TwitterJson)))
   296      b.ResetTimer()
   297      for i := 0; i < b.N; i++ {
   298          ast, _ := NewParser(_TwitterJson).Parse()
   299          _, _ = ast.Get("statuses").Index(2).Get("id").Int64()
   300      }
   301  }
   302  
   303  func BenchmarkParseOne_Parallel_Sonic(b *testing.B) {
   304      ast, _ := NewParser(_TwitterJson).Parse()
   305      node, _ := ast.Get("statuses").Index(2).Get("id").Int64()
   306      if node != 249289491129438208 {
   307          b.Fail()
   308      }
   309      b.SetBytes(int64(len(_TwitterJson)))
   310      b.ResetTimer()
   311      b.RunParallel(func(pb *testing.PB) {
   312          for pb.Next() {
   313              ast, _ := NewParser(_TwitterJson).Parse()
   314              _, _ = ast.Get("statuses").Index(2).Get("id").Int64()
   315          }
   316      })
   317  }
   318  
   319  func BenchmarkParseSeven_Sonic(b *testing.B) {
   320      b.SetBytes(int64(len(_TwitterJson)))
   321      b.ResetTimer()
   322      for i := 0; i < b.N; i++ {
   323          ast, _ := NewParser(_TwitterJson).Parse()
   324          node := ast.GetByPath("statuses", 3, "id")
   325          node = ast.GetByPath("statuses",  3, "user", "entities","description")
   326          node = ast.GetByPath("statuses",  3, "user", "entities","url","urls")
   327          node = ast.GetByPath("statuses",  3, "user", "entities","url")
   328          node = ast.GetByPath("statuses",  3, "user", "created_at")
   329          node = ast.GetByPath("statuses",  3, "user", "name")
   330          node = ast.GetByPath("statuses",  3, "text")
   331          if node.Check() != nil {
   332              b.Fail()
   333          }
   334      }
   335  }
   336  
   337  func BenchmarkParseSeven_Parallel_Sonic(b *testing.B) {
   338      b.SetBytes(int64(len(_TwitterJson)))
   339      b.ResetTimer()
   340      b.RunParallel(func(pb *testing.PB) {
   341          for pb.Next() {
   342              ast, _ := NewParser(_TwitterJson).Parse()
   343              node := ast.GetByPath("statuses", 3, "id")
   344              node = ast.GetByPath("statuses",  3, "user", "entities","description")
   345              node = ast.GetByPath("statuses",  3, "user", "entities","url","urls")
   346              node = ast.GetByPath("statuses",  3, "user", "entities","url")
   347              node = ast.GetByPath("statuses",  3, "user", "created_at")
   348              node = ast.GetByPath("statuses",  3, "user", "name")
   349              node = ast.GetByPath("statuses",  3, "text")
   350              if node.Check() != nil {
   351                  b.Fail()
   352              }
   353          }
   354      })
   355  }