/* * Copyright 2021 ByteDance Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ast import ( `encoding/json` `errors` `fmt` `reflect` `runtime` `runtime/debug` `strconv` `testing` `github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/rt` `github.com/stretchr/testify/assert` ) func TestNodeSortKeys(t *testing.T) { var src = `{"b":1,"a":2,"c":3}` root, err := NewSearcher(src).GetByPath() if err != nil { t.Fatal(err) } obj, err := root.MapUseNumber() if err != nil { t.Fatal(err) } exp, err := json.Marshal(obj) if err != nil { t.Fatal(err) } if err := root.SortKeys(true); err != nil { t.Fatal(err) } act, err := root.MarshalJSON() if err != nil { t.Fatal(err) } assert.Equal(t, len(exp), len(act)) assert.Equal(t, string(exp), string(act)) } func BenchmarkNodeSortKeys(b *testing.B) { root, err := NewSearcher(_TwitterJson).GetByPath() if err != nil { b.Fatal(err) } if err := root.LoadAll(); err != nil { b.Fatal(err) } b.Run("single", func(b *testing.B) { r := root.Get("statuses") if r.Check() != nil { b.Fatal(r.Error()) } b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() for i:=0; i= 0; i-- { root.GetByPath("statuses", 3).Set("id_str"+strconv.Itoa(i), app) } val, _ = root.GetByPath("statuses", 3, "id_str0").Int64() if val != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) } root.GetByPath("statuses", 3).Set("id_str2", nroot) val2, _ := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String() if val2 != "c" { t.Fatalf("exp:%+v, got:%+v", "c", val2) } } func TestNodeAny(t *testing.T) { empty := Node{} _,err := empty.SetAny("any", map[string]interface{}{"a": []int{0}}) if err != nil { t.Fatal(err) } if m, err := empty.Get("any").Interface(); err != nil { t.Fatal(err) } else if v, ok := m.(map[string]interface{}); !ok { t.Fatal(v) } if buf, err := empty.MarshalJSON(); err != nil { t.Fatal(err) } else if string(buf) != `{"any":{"a":[0]}}` { t.Fatal(string(buf)) } if _, err := empty.Set("any2", Node{}); err != nil { t.Fatal(err) } if err := empty.Get("any2").AddAny(nil); err != nil { t.Fatal(err) } if buf, err := empty.MarshalJSON(); err != nil { t.Fatal(err) } else if string(buf) != `{"any":{"a":[0]},"any2":[null]}` { t.Fatal(string(buf)) } if _, err := empty.Get("any2").SetAnyByIndex(0, NewNumber("-0.0")); err != nil { t.Fatal(err) } if buf, err := empty.MarshalJSON(); err != nil { t.Fatal(err) } else if string(buf) != `{"any":{"a":[0]},"any2":[-0.0]}` { t.Fatal(string(buf)) } } func TestNodeSetByIndex(t *testing.T) { root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) } app, _ := NewParser("111").Parse() st := root.GetByPath("statuses") st.SetByIndex(0, app) st = root.GetByPath("statuses") val := st.Index(0) x, _ := val.Int64() if x != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) } root.GetByPath("statuses").SetByIndex(0, nroot) val2, _ := root.GetByPath("statuses", 0, "a", 4, "b").String() if val2 != "c" { t.Fatalf("exp:%+v, got:%+v", "c", val2) } } func TestNodeAdd(t *testing.T) { root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) } app, _ := NewParser("111").Parse() for i := root.GetByPath("statuses").cap(); i >= 0; i-- { root.GetByPath("statuses").Add(app) } val, _ := root.GetByPath("statuses", 4).Int64() if val != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } val, _ = root.GetByPath("statuses", root.GetByPath("statuses").len()-1).Int64() if val != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } nroot, derr := NewParser(`{"a":[0.1,true,0,"name",{"b":"c"}]}`).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) } root.GetByPath("statuses").Add(nroot) val2, _ := root.GetByPath("statuses", root.GetByPath("statuses").len()-1, "a", 4, "b").String() if val2 != "c" { t.Fatalf("exp:%+v, got:%+v", "c", val2) } } func BenchmarkLoadNode(b *testing.B) { b.Run("Interface()", func(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { root, err := NewSearcher(_TwitterJson).GetByPath("statuses", 0) if err != nil { b.Fatal(err) } _, _ = root.Interface() } }) }) b.Run("LoadAll()", func(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { root, err := NewSearcher(_TwitterJson).GetByPath("statuses", 0) if err != nil { b.Fatal(err) } _ = root.LoadAll() } }) }) b.Run("InterfaceUseNode()", func(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { root, err := NewSearcher(_TwitterJson).GetByPath("statuses", 0) if err != nil { b.Fatal(err) } _, _ = root.InterfaceUseNode() } }) }) b.Run("Load()", func(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { root, err := NewSearcher(_TwitterJson).GetByPath("statuses", 0) if err != nil { b.Fatal(err) } _ = root.Load() } }) }) } func BenchmarkNodeGetByPath(b *testing.B) { root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { b.Fatalf("decode failed: %v", derr.Error()) } _, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() } }) } func BenchmarkStructGetByPath(b *testing.B) { var root = _TwitterStruct{} err := json.Unmarshal([]byte(_TwitterJson), &root) if err != nil { b.Fatalf("unmarshal failed: %v", err) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = root.Statuses[3].Entities.Hashtags[0].Text } }) } func BenchmarkNodeIndex(b *testing.B) { root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { b.Fatalf("decode failed: %v", derr.Error()) } node := root.Get("statuses").Index(3).Get("entities").Get("hashtags").Index(0) node.Set("test1", NewNumber("1")) node.Set("test2", NewNumber("2")) node.Set("test3", NewNumber("3")) node.Set("test4", NewNumber("4")) node.Set("test5", NewNumber("5")) b.ResetTimer() for i := 0; i < b.N; i++ { node.Index(2) } } func BenchmarkStructIndex(b *testing.B) { type T struct { A Node B Node C Node D Node E Node } var obj = new(T) b.ResetTimer() for i := 0; i < b.N; i++ { _ = obj.C } } func BenchmarkSliceIndex(b *testing.B) { var obj = []Node{Node{},Node{},Node{},Node{},Node{}} b.ResetTimer() for i := 0; i < b.N; i++ { _ = obj[2] } } func BenchmarkMapIndex(b *testing.B) { var obj = map[string]interface{}{"test1":Node{}, "test2":Node{}, "test3":Node{}, "test4":Node{}, "test5":Node{}} b.ResetTimer() for i := 0; i < b.N; i++ { for k := range obj { if k == "test3" { break } } } } func BenchmarkNodeGet(b *testing.B) { var N = 5 var half = "test" + strconv.Itoa(N/2+1) root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { b.Fatalf("decode failed: %v", derr.Error()) } node := root.Get("statuses").Index(3).Get("entities").Get("hashtags").Index(0) for i:=0; i