From b3543c527e2d625b4ff91afaf3190c1af3928267 Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Tue, 16 Jan 2024 22:41:19 +0800 Subject: [PATCH] test --- ast/raw.go | 56 +++++++----- ast/raw_test.go | 227 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 234 insertions(+), 49 deletions(-) diff --git a/ast/raw.go b/ast/raw.go index 3bc232f49..ba4d6ac2b 100644 --- a/ast/raw.go +++ b/ast/raw.go @@ -2,10 +2,8 @@ package ast import ( "encoding/json" - "errors" "sort" "strconv" - "strings" "sync" "github.com/bytedance/sonic/encoder" @@ -90,7 +88,7 @@ func (self Value) Error() string { // Check checks if the node itself is valid, and return func (self Value) Check() error { if self.t == V_ERROR { - return errors.New(self.js) + return self } return nil } @@ -102,18 +100,22 @@ func errRawNode(err error) Value { // Len returns children count of a array|object|string node // // WARN: this calculation consumes much CPU time -func (self Value) Len() int { +func (self Value) Len() (int, error) { switch self.t { case V_STRING: - return len(self.js) - 2 + str, e := self.toString() + if e != 0 { + return -1, e + } + return len(str), nil case V_ARRAY: c, _ := self.count_elems() - return c + return c, nil case V_OBJECT: c, _ := self.count_kvs() - return c + return c, nil default: - return -1 + return -1, ErrUnsupportType } } @@ -325,11 +327,9 @@ func (self *Value) UnsetByPath(path ...interface{}) (bool, error) { } e := p.p - println(string(self.js[s])) if self.js[s] != ',' { // first elem // check if trailling ',' p.p = p.lspace(p.p) - println(string(self.js[p.p])) if p.p < len(self.js) && self.js[p.p] == ',' { e = p.p+1 } @@ -970,17 +970,12 @@ func (self Value) str() string { return self.js[1:len(self.js)-1] } -// Raw returns json representation of the node -// If it's invalid json, return empty string -func (self Value) Raw() (string) { - if e := self.Check(); e != nil { - return "" - } - return self.js +func (self Value) raw() string { + return self.js } -// StrictRaw returns json representation of the node -func (self Value) StrictRaw() (string, error) { +// Raw returns json representation of the node +func (self Value) Raw() (string, error) { if e := self.Check(); e != nil { return "", e } @@ -1008,10 +1003,25 @@ func (self Value) toNumber() json.Number { } func (self Value) toString() (string, types.ParsingError) { - if strings.Contains(self.js, "\\") { - return unquote(self.js) - } else { - return self.str(), 0 + p := NewParserObj(self.js) + switch val := p.decodeValue(); val.Vt { + case types.V_STRING : + /* fast path: no escape sequence */ + if val.Ep == -1 { + return self.str(), 0 + } + + /* unquote the string */ + s := p.s[val.Iv:p.p - 1] + out, err := unquote(s) + + /* check for errors */ + if err != 0 { + return "", err + } else { + return out, 0 + } + default: return "", _ERR_UNSUPPORT_TYPE } } diff --git a/ast/raw_test.go b/ast/raw_test.go index a23c489e4..2073d2208 100644 --- a/ast/raw_test.go +++ b/ast/raw_test.go @@ -1,44 +1,214 @@ package ast import ( + "encoding/json" + "errors" "fmt" "reflect" + "strconv" "sync" "testing" "github.com/bytedance/sonic/internal/native/types" + "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/require" ) var concurrency = 1000 -func TestValAPI(t *testing.T) { +func TestCast(t *testing.T) { + v, err := strconv.ParseInt("1.1", 0, 0) + spew.Dump(v, err) +} + +func TestValueAPI(t *testing.T) { + var nonEmptyErr error = errors.New("") + var cases = []struct { method string - js string - exp []interface{} + js Node + exp interface{} + err error }{ - {"Len", `""`, []interface{}{0}}, - {"Len", `"a"`, []interface{}{1}}, - {"Len", `1`, []interface{}{-1}}, - {"Len", `true`, []interface{}{-1}}, - {"Len", `null`, []interface{}{-1}}, - {"Len", `[]`, []interface{}{0}}, - {"Len", `[1]`, []interface{}{1}}, - {"Len", `[ 1 , 2 ]`, []interface{}{2}}, - {"Len", `{}`, []interface{}{0}}, - {"Len", `{"a":1}`, []interface{}{1}}, - {"Len", `{ "a" : 1, "b" : [1] }`, []interface{}{2}}, + {"Len", NewAny(""), 0, nil}, + {"Len", NewAny("a"), 1,nil}, + {"Len", NewAny(1), -1, ErrUnsupportType}, + {"Len", NewAny(true), -1,ErrUnsupportType}, + {"Len", NewAny(nil), -1,ErrUnsupportType}, + {"Len", NewAny([]int{}), 0,nil}, + {"Len", NewAny([]int{1}), 1,nil}, + {"Len", NewAny([]int{1,2}), 2,nil}, + {"Len", NewAny(map[string]string{}), 0,nil}, + {"Len", NewAny(map[string]int{"a":1}), 1,nil}, + {"Len", NewAny(map[string]int{"a":1,"b":2}), 2,nil}, + + {"Bool", Node{}, false, nonEmptyErr}, + {"Bool", NewAny(true), true, nil}, + {"Bool", NewAny(false), false, nil}, + {"Bool", NewAny(int(0)), false, nil}, + {"Bool", NewAny(int8(1)), true, nil}, + {"Bool", NewAny(int16(1)), true, nil}, + {"Bool", NewAny(int32(1)), true, nil}, + {"Bool", NewAny(int64(1)), true, nil}, + {"Bool", NewAny(uint(1)), true, nil}, + {"Bool", NewAny(uint16(1)), true, nil}, + {"Bool", NewAny(uint32(1)), true, nil}, + {"Bool", NewAny(uint64(1)), true, nil}, + {"Bool", NewAny(float64(0)), false, nil}, + {"Bool", NewAny(float32(1)), true, nil}, + {"Bool", NewAny(float64(1)), true, nil}, + {"Bool", NewAny(json.Number("0")), false, nil}, + {"Bool", NewAny(json.Number("1")), true, nil}, + {"Bool", NewAny(json.Number("1.1")), true, nil}, + {"Bool", NewAny(json.Number("+x1.1")), false, nonEmptyErr}, + {"Bool", NewAny(string("0")), false, nil}, + {"Bool", NewAny(string("t")), true, nil}, + {"Bool", NewAny([]byte{0}), false, nonEmptyErr}, + {"Bool", NewRaw("true"), true, nil}, + {"Bool", NewRaw("false"), false, nil}, + {"Bool", NewRaw("null"), false, nil}, + {"Bool", NewString(`true`), true, nil}, + {"Bool", NewString(`false`), false, nil}, + {"Bool", NewString(``), false, nonEmptyErr}, + {"Bool", NewNumber("2"), true, nil}, + {"Bool", NewNumber("-2.1"), true, nil}, + {"Bool", NewNumber("-x-2.1"), false, nonEmptyErr}, + + {"Int64", NewRaw("true"), int64(1), nil}, + {"Int64", NewRaw("false"), int64(0), nil}, + {"Int64", NewRaw("\"1\""), int64(1), nil}, + {"Int64", NewRaw("\"1.1\""), int64(0), nonEmptyErr}, + {"Int64", NewRaw("\"1.0\""), int64(0), nonEmptyErr}, + {"Int64", NewNumber("+x.0"), int64(0), nonEmptyErr}, + {"Int64", NewAny(false), int64(0), nil}, + {"Int64", NewAny(true), int64(1), nil}, + {"Int64", NewAny(int(1)), int64(1), nil}, + {"Int64", NewAny(int8(1)), int64(1), nil}, + {"Int64", NewAny(int16(1)), int64(1), nil}, + {"Int64", NewAny(int32(1)), int64(1), nil}, + {"Int64", NewAny(int64(1)), int64(1), nil}, + {"Int64", NewAny(uint(1)), int64(1), nil}, + {"Int64", NewAny(uint8(1)), int64(1), nil}, + {"Int64", NewAny(uint32(1)), int64(1), nil}, + {"Int64", NewAny(uint64(1)), int64(1), nil}, + {"Int64", NewAny(float32(1)), int64(1), nil}, + {"Int64", NewAny(float64(1)), int64(1), nil}, + {"Int64", NewAny("1"), int64(1), nil}, + {"Int64", NewAny("1.1"), int64(0), nonEmptyErr}, + {"Int64", NewAny("+1x.1"), int64(0), nonEmptyErr}, + {"Int64", NewAny(json.Number("1")), int64(1), nil}, + {"Int64", NewAny(json.Number("1.1")), int64(0), nonEmptyErr}, + {"Int64", NewAny(json.Number("+1x.1")), int64(0), nonEmptyErr}, + {"Int64", NewAny([]byte{0}), int64(0), nonEmptyErr}, + {"Int64", Node{}, int64(0), nonEmptyErr}, + {"Int64", NewRaw("0"), int64(0), nil}, + {"Int64", NewRaw("null"), int64(0), nil}, + + {"Float64", NewRaw("true"), float64(1), nil}, + {"Float64", NewRaw("false"), float64(0), nil}, + {"Float64", NewRaw("\"1.0\""), float64(1.0), nil}, + {"Float64", NewRaw("\"xx\""), float64(0), nonEmptyErr}, + {"Float64", Node{}, float64(0), nonEmptyErr}, + {"Float64", NewAny(false), float64(0), nil}, + {"Float64", NewAny(true), float64(1), nil}, + {"Float64", NewAny(int(1)), float64(1), nil}, + {"Float64", NewAny(int8(1)), float64(1), nil}, + {"Float64", NewAny(int16(1)), float64(1), nil}, + {"Float64", NewAny(int32(1)), float64(1), nil}, + {"Float64", NewAny(int64(1)), float64(1), nil}, + {"Float64", NewAny(uint(1)), float64(1), nil}, + {"Float64", NewAny(uint8(1)), float64(1), nil}, + {"Float64", NewAny(uint32(1)), float64(1), nil}, + {"Float64", NewAny(uint64(1)), float64(1), nil}, + {"Float64", NewAny(float32(1)), float64(1), nil}, + {"Float64", NewAny(float64(1)), float64(1), nil}, + {"Float64", NewAny("1.1"), float64(1.1), nil}, + {"Float64", NewAny("+1x.1"), float64(0), nonEmptyErr}, + {"Float64", NewAny(json.Number("0")), float64(0), nil}, + {"Float64", NewAny(json.Number("x")), float64(0), nonEmptyErr}, + {"Float64", NewAny([]byte{0}), float64(0), nonEmptyErr}, + {"Float64", NewRaw("0.0"), float64(0.0), nil}, + {"Float64", NewRaw("1"), float64(1.0), nil}, + {"Float64", NewRaw("null"), float64(0.0), nil}, + + {"Number", Node{}, json.Number(""), nonEmptyErr}, + {"Number", NewAny(false), json.Number("0"), nil}, + {"Number", NewAny(true), json.Number("1"), nil}, + {"Number", NewAny(int(1)), json.Number("1"), nil}, + {"Number", NewAny(int8(1)), json.Number("1"), nil}, + {"Number", NewAny(int16(1)), json.Number("1"), nil}, + {"Number", NewAny(int32(1)), json.Number("1"), nil}, + {"Number", NewAny(int64(1)), json.Number("1"), nil}, + {"Number", NewAny(uint(1)), json.Number("1"), nil}, + {"Number", NewAny(uint8(1)), json.Number("1"), nil}, + {"Number", NewAny(uint32(1)), json.Number("1"), nil}, + {"Number", NewAny(uint64(1)), json.Number("1"), nil}, + {"Number", NewAny(float32(1)), json.Number("1"), nil}, + {"Number", NewAny(float64(1)), json.Number("1"), nil}, + {"Number", NewAny("1.1"), json.Number("1.1"), nil}, + {"Number", NewAny("+1x.1"), json.Number(""), nonEmptyErr}, + {"Number", NewAny(json.Number("0")), json.Number("0"), nil}, + {"Number", NewAny(json.Number("x")), json.Number("x"), nil}, + {"Number", NewAny(json.Number("+1x.1")), json.Number("+1x.1"), nil}, + {"Number", NewAny([]byte{0}), json.Number(""), nonEmptyErr}, + {"Number", NewRaw("x"), json.Number(""), nonEmptyErr}, + {"Number", NewRaw("0.0"), json.Number("0.0"), nil}, + {"Number", NewRaw("\"1\""), json.Number("1"), nil}, + {"Number", NewRaw("\"1.1\""), json.Number("1.1"), nil}, + {"Number", NewRaw("\"0.x0\""), json.Number(""), nonEmptyErr}, + {"Number", NewRaw("{]"), json.Number(""), nonEmptyErr}, + {"Number", NewRaw("true"), json.Number("1"), nil}, + {"Number", NewRaw("false"), json.Number("0"), nil}, + {"Number", NewRaw("null"), json.Number("0"), nil}, + + {"String", Node{}, "", nonEmptyErr}, + {"String", NewAny(`\u263a`), `\u263a`, nil}, + {"String", NewRaw(`"\u263a"`), `☺`, nil}, + {"String", NewString(`\u263a`), `\u263a`, nil}, + {"String", NewRaw(`0.0`), "0.0", nil}, + {"String", NewRaw(`true`), "true", nil}, + {"String", NewRaw(`false`), "false", nil}, + {"String", NewRaw(`null`), "", nil}, + {"String", NewAny(false), "false", nil}, + {"String", NewAny(true), "true", nil}, + {"String", NewAny(int(1)), "1", nil}, + {"String", NewAny(int8(1)), "1", nil}, + {"String", NewAny(int16(1)), "1", nil}, + {"String", NewAny(int32(1)), "1", nil}, + {"String", NewAny(int64(1)), "1", nil}, + {"String", NewAny(uint(1)), "1", nil}, + {"String", NewAny(uint8(1)), "1", nil}, + {"String", NewAny(uint32(1)), "1", nil}, + {"String", NewAny(uint64(1)), "1", nil}, + {"String", NewAny(float32(1)), "1", nil}, + {"String", NewAny(float64(1)), "1", nil}, + {"String", NewAny("1.1"), "1.1", nil}, + {"String", NewAny("+1x.1"), "+1x.1", nil}, + {"String", NewAny(json.Number("0")), ("0"), nil}, + {"String", NewAny(json.Number("x")), ("x"), nil}, + {"String", NewAny([]byte{0}), (""), nonEmptyErr}, } for i, c := range cases { - fmt.Println(i, c) - node := NewValueJSON(c.js) + fmt.Println(i) + node := NewValue(&c.js) + println(node.js, node.t) rt := reflect.ValueOf(&node) m := rt.MethodByName(c.method) rets := m.Call([]reflect.Value{}) - for i, v := range c.exp { - require.Equal(t, v, rets[i].Interface()) - } + if len(rets) != 2 { + t.Fatal(i, rets) + } + if !reflect.DeepEqual(rets[0].Interface(), c.exp) { + t.Fatal(i, c.exp, "::", rets[0].Interface()) + } + v := rets[1].Interface() + if c.err == nonEmptyErr { + if rets[1].IsNil() { + t.Fatal(i, v) + } + } else if v != c.err { + t.Fatal(i, v) + } } } @@ -48,6 +218,11 @@ type IndexVal struct { Val Value } +type keyVal struct { + Key string + Val Value +} + func TestGetMany(t *testing.T) { var cases = []struct { name string @@ -140,7 +315,7 @@ func TestSetMany(t *testing.T) { vals = append(vals, kv.Val) } _, err = node.SetMany(keys, vals) - require.Equal(t, c.exp, node.Raw()) + require.Equal(t, c.exp, node.raw()) } else if ids, ok := c.kvs.([]IndexVal); ok { keys := []int{} vals := []Value{} @@ -149,7 +324,7 @@ func TestSetMany(t *testing.T) { vals = append(vals, kv.Val) } _, err = node.SetManyByIndex(keys, vals) - require.Equal(t, c.exp, node.Raw()) + require.Equal(t, c.exp, node.raw()) } if err != nil && c.err != err.Error() { t.Fatal(err) @@ -310,7 +485,7 @@ func TestRawNode_Set(t *testing.T) { if err != nil && err.Error() != c.err { t.Fatal() } - if out := root.Raw(); err != nil { + if out := root.raw(); err != nil { t.Fatal() } else { require.Equal(t, c.out, out) @@ -347,7 +522,7 @@ func TestRawNode_SetByPath(t *testing.T) { if err != nil && err.Error() != c.err { t.Fatal(err) } - if out := root.Raw(); err != nil { + if out := root.raw(); err != nil { t.Fatal() } else { require.Equal(t, c.out, out) @@ -389,7 +564,7 @@ func TestRawNode_UnsetByPath(t *testing.T) { if err != nil && err.Error() != c.err { t.Fatal(err) } - if out := root.Raw(); err != nil { + if out := root.raw(); err != nil { t.Fatal() } else { require.Equal(t, c.out, out) @@ -433,7 +608,7 @@ func TestRawNode_Unset(t *testing.T) { if err != nil && err.Error() != c.err { t.Fatal(err.Error()) } - if out := root.Raw(); err != nil { + if out := root.raw(); err != nil { t.Fatal() } else { require.Equal(t, c.out, out) @@ -490,7 +665,7 @@ func TestRawNode_UnsetMany(t *testing.T) { if err != nil && err.Error() != c.err { t.Fatal(err.Error()) } - if out := root.Raw(); err != nil { + if out := root.raw(); err != nil { t.Fatal() } else { require.Equal(t, c.out, out)