github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/ast/encode_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  	"runtime"
    22  	"sync"
    23  	"testing"
    24  
    25  	"github.com/goshafaq/sonic/internal/native/types"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func TestGC_Encode(t *testing.T) {
    31  	if debugSyncGC {
    32  		return
    33  	}
    34  	root, err := NewSearcher(_TwitterJson).GetByPath()
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	root.LoadAll()
    39  	_, err = root.MarshalJSON()
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  	wg := &sync.WaitGroup{}
    44  	N := 10000
    45  	for i := 0; i < N; i++ {
    46  		wg.Add(1)
    47  		go func(wg *sync.WaitGroup) {
    48  			defer wg.Done()
    49  			root, err := NewSearcher(_TwitterJson).GetByPath()
    50  			if err != nil {
    51  				t.Error(err)
    52  				return
    53  			}
    54  			root.Load()
    55  			_, err = root.MarshalJSON()
    56  			if err != nil {
    57  				t.Error(err)
    58  				return
    59  			}
    60  			runtime.GC()
    61  		}(wg)
    62  	}
    63  	wg.Wait()
    64  }
    65  
    66  func TestEncodeValue(t *testing.T) {
    67  	obj := new(_TwitterStruct)
    68  	if err := json.Unmarshal([]byte(_TwitterJson), obj); err != nil {
    69  		t.Fatal(err)
    70  	}
    71  	// buf, err := encoder.Encode(obj, encoder.EscapeHTML|encoder.SortMapKeys)
    72  	buf, err := json.Marshal(obj)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  	quote, err := json.Marshal(_TwitterJson)
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	type Case struct {
    81  		node Node
    82  		exp  string
    83  		err  bool
    84  	}
    85  	input := []Case{
    86  		{NewNull(), "null", false},
    87  		{NewBool(true), "true", false},
    88  		{NewBool(false), "false", false},
    89  		{NewNumber("0.0"), "0.0", false},
    90  		{NewString(""), `""`, false},
    91  		{NewString(`\"\"`), `"\\\"\\\""`, false},
    92  		{NewString(_TwitterJson), string(quote), false},
    93  		{NewArray([]Node{}), "[]", false},
    94  		{NewArray([]Node{NewString(""), NewNull()}), `["",null]`, false},
    95  		{NewArray([]Node{NewBool(true), NewString("true"), NewString("\t")}), `[true,"true","\t"]`, false},
    96  		{NewObject([]Pair{Pair{"a", NewNull()}, Pair{"b", NewNumber("0")}}), `{"a":null,"b":0}`, false},
    97  		{NewObject([]Pair{Pair{"\ta", NewString("\t")}, Pair{"\bb", NewString("\b")}, Pair{"\nb", NewString("\n")}, Pair{"\ra", NewString("\r")}}), `{"\ta":"\t","\u0008b":"\u0008","\nb":"\n","\ra":"\r"}`, false},
    98  		{NewObject([]Pair{}), `{}`, false},
    99  		{NewObject([]Pair{Pair{Key: "", Value: NewNull()}}), `{"":null}`, false},
   100  		{NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, false},
   101  		{NewAny(obj), string(buf), false},
   102  		{NewRaw(`[{ }]`), "[{}]", false},
   103  		{Node{}, "", true},
   104  		{Node{t: types.ValueType(1)}, "", true},
   105  	}
   106  	for i, c := range input {
   107  		t.Log(i)
   108  		buf, err := json.Marshal(&c.node)
   109  		if c.err {
   110  			if err == nil {
   111  				t.Fatal(i)
   112  			}
   113  			continue
   114  		}
   115  		if err != nil {
   116  			t.Fatal(i, err)
   117  		}
   118  		assert.Equal(t, c.exp, string(buf))
   119  	}
   120  }
   121  
   122  func TestEncodeNode(t *testing.T) {
   123  	data := `{"a":[{},[],-0.1,true,false,null,""],"b":0,"c":true,"d":false,"e":null,"g":""}`
   124  	root, e := NewSearcher(data).GetByPath()
   125  	if e != nil {
   126  		t.Fatal(root)
   127  	}
   128  	ret, err := root.MarshalJSON()
   129  	if err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	if string(ret) != data {
   133  		t.Fatal(string(ret))
   134  	}
   135  	root.skipAllKey()
   136  	ret, err = root.MarshalJSON()
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	if string(ret) != data {
   141  		t.Fatal(string(ret))
   142  	}
   143  	root.loadAllKey()
   144  	ret, err = root.MarshalJSON()
   145  	if err != nil {
   146  		t.Fatal(err)
   147  	}
   148  	if string(ret) != data {
   149  		t.Fatal(string(ret))
   150  	}
   151  }
   152  
   153  type SortableNode struct {
   154  	sorted bool
   155  	*Node
   156  }
   157  
   158  func (j *SortableNode) UnmarshalJSON(data []byte) error {
   159  	j.Node = new(Node)
   160  	return j.Node.UnmarshalJSON(data)
   161  }
   162  
   163  func (j *SortableNode) MarshalJSON() ([]byte, error) {
   164  	if !j.sorted {
   165  		j.Node.SortKeys(true)
   166  		j.sorted = true
   167  	}
   168  	return j.Node.MarshalJSON()
   169  }
   170  
   171  func TestMarshalSort(t *testing.T) {
   172  	var data = `{"d":3,"a":{"c":1,"b":2},"e":null}`
   173  	var obj map[string]*SortableNode
   174  	require.NoError(t, json.Unmarshal([]byte(data), &obj))
   175  	out, err := json.Marshal(obj)
   176  	require.NoError(t, err)
   177  	require.Equal(t, `{"a":{"b":2,"c":1},"d":3,"e":null}`, string(out))
   178  	out, err = json.Marshal(obj)
   179  	require.NoError(t, err)
   180  	require.Equal(t, `{"a":{"b":2,"c":1},"d":3,"e":null}`, string(out))
   181  }
   182  
   183  func BenchmarkEncodeRaw_Sonic(b *testing.B) {
   184  	data := _TwitterJson
   185  	root, e := NewSearcher(data).GetByPath()
   186  	if e != nil {
   187  		b.Fatal(root)
   188  	}
   189  	_, err := root.MarshalJSON()
   190  	if err != nil {
   191  		b.Fatal(err)
   192  	}
   193  	b.SetBytes(int64(len(data)))
   194  	b.ResetTimer()
   195  	for i := 0; i < b.N; i++ {
   196  		_, err := root.MarshalJSON()
   197  		if err != nil {
   198  			b.Fatal(err)
   199  		}
   200  	}
   201  }
   202  
   203  func BenchmarkEncodeSkip_Sonic(b *testing.B) {
   204  	data := _TwitterJson
   205  	root, e := NewParser(data).Parse()
   206  	if e != 0 {
   207  		b.Fatal(root)
   208  	}
   209  	root.skipAllKey()
   210  	_, err := root.MarshalJSON()
   211  	if err != nil {
   212  		b.Fatal(err)
   213  	}
   214  	b.SetBytes(int64(len(data)))
   215  	b.ResetTimer()
   216  	for i := 0; i < b.N; i++ {
   217  		_, err := root.MarshalJSON()
   218  		if err != nil {
   219  			b.Fatal(err)
   220  		}
   221  	}
   222  }
   223  
   224  func BenchmarkEncodeLoad_Sonic(b *testing.B) {
   225  	data := _TwitterJson
   226  	root, e := NewParser(data).Parse()
   227  	if e != 0 {
   228  		b.Fatal(root)
   229  	}
   230  	root.loadAllKey()
   231  	_, err := root.MarshalJSON()
   232  	if err != nil {
   233  		b.Fatal(err)
   234  	}
   235  	b.SetBytes(int64(len(data)))
   236  	b.ResetTimer()
   237  	for i := 0; i < b.N; i++ {
   238  		_, err := root.MarshalJSON()
   239  		if err != nil {
   240  			b.Fatal(err)
   241  		}
   242  	}
   243  }
   244  
   245  func TestEncodeNone(t *testing.T) {
   246  	n := NewObject([]Pair{{Key: "a", Value: Node{}}})
   247  	out, err := n.MarshalJSON()
   248  	require.NoError(t, err)
   249  	require.Equal(t, "{}", string(out))
   250  	n = NewObject([]Pair{{Key: "a", Value: NewNull()}, {Key: "b", Value: Node{}}})
   251  	out, err = n.MarshalJSON()
   252  	require.NoError(t, err)
   253  	require.Equal(t, `{"a":null}`, string(out))
   254  
   255  	n = NewArray([]Node{Node{}})
   256  	out, err = n.MarshalJSON()
   257  	require.NoError(t, err)
   258  	require.Equal(t, "[]", string(out))
   259  	n = NewArray([]Node{NewNull(), Node{}})
   260  	out, err = n.MarshalJSON()
   261  	require.NoError(t, err)
   262  	require.Equal(t, `[null]`, string(out))
   263  }