Skip to content

Commit

Permalink
fix: SetByPath() didn't reset start pos when looping
Browse files Browse the repository at this point in the history
  • Loading branch information
AsterDY committed May 19, 2024
1 parent 0caaf9d commit 79ef946
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 2 deletions.
10 changes: 10 additions & 0 deletions dev/ast/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,13 @@ func makeSyntaxError(json string, p int, msg string) decoder.SyntaxError {
Msg: msg,
}
}

// speciall used for `SetByPath()`, tells which path is array index of range
type ErrIndexOutOfRange struct {
Index int // index of path
Err error
}

func (e ErrIndexOutOfRange) Error() string {
return e.Err.Error()
}

Check failure on line 56 in dev/ast/error.go

View workflow job for this annotation

GitHub Actions / build (1.20.x)

syntax error: unexpected var after top level declaration
49 changes: 49 additions & 0 deletions dev/ast/error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ast

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestErrIndexOutOfRange_Error(t *testing.T) {
tests := []struct {
name string
src string
path []interface{}
want int
err string
}{
{
name: "top",
src: ` [ 1 ] `,
path: []interface{}{1},
want: 0,
err: ErrNotExist.Error(),
},
{
name: "second",
src: `{ "1" : [ 1 ] }`,
path: []interface{}{"1", 2, 3},
want: 1,
err: ErrNotExist.Error(),
},
{
name: "thrid",
src: `{ "1" : [ 1, [ 1 ] ] }`,
path: []interface{}{"1", 1, 3},
want: 2,
err: ErrNotExist.Error(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
n := NewRaw(tt.src)
exist, err := n.SetByPath(false, "1", tt.path...)
require.False(t, exist)
require.Error(t, err)
require.Equal(t, tt.err, err.Error())
require.Equal(t, tt.want, err.(ErrIndexOutOfRange).Index)
})
}
}
1 change: 1 addition & 0 deletions dev/ast/native.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ func parseLazy(json string, path *[]interface{}) (Node, error) {
v := node.node.JSON
node.node.JSON = v
runtime.KeepAlive(json)
runtime.KeepAlive(path)
return node, nil
}

Expand Down
6 changes: 5 additions & 1 deletion dev/ast/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ func (self *Node) SetByPath(allowArrayAppend bool, json string, path ...interfac
if err != types.ERR_NOT_FOUND {
return exist, makeSyntaxError(self.node.JSON, p.pos, err.Message())
} else if !allowArrayAppend {
return false, ErrNotExist
return false, ErrIndexOutOfRange{Index: i, Err: ErrNotExist}
} else {
missing = i
break
Expand All @@ -576,6 +576,10 @@ func (self *Node) SetByPath(allowArrayAppend bool, json string, path ...interfac
} else {
panic("path must be either int or string")
}
// next layer, reset pos
if i != l - 1 {
p.pos = start
}
}
var b []byte
if err == types.ERR_NOT_FOUND {
Expand Down
41 changes: 41 additions & 0 deletions dev/ast/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,22 @@ func TestNode_SetByPath(t *testing.T) {
exist: true,
val: map[string]interface{}{"1":int64(-1)},
},
{
name: "two object exist",
src: ` { "1" : { "2" : 2 } } `,
args: args{path: []interface{}{"1", "2"}, val: "-1"},
want: ` { "1" : { "2" : -1} } `,
exist: true,
val: map[string]interface{}{"1":map[string]interface{}{"2":int64(-1)}},
},
{
name: "two object not exist",
src: ` { "1" : { "2" : 2 } } `,
args: args{path: []interface{}{"1", "3"}, val: "3"},
want: ` { "1" : { "2" : 2,"3":3 } } `,
exist: false,
val: map[string]interface{}{"1":map[string]interface{}{"2":int64(2),"3":int64(3)}},
},
{
name: "empty array",
src: ` [ ] `,
Expand Down Expand Up @@ -408,6 +424,31 @@ func TestNode_SetByPath(t *testing.T) {
exist: true,
val: []interface{}{int64(-1)},
},
{
name: "two array exist",
src: ` [ [ 1 ] ] `,
args: args{path: []interface{}{0, 0}, val: "-1"},
want: ` [ [ -1] ] `,
exist: true,
val: []interface{}{[]interface{}{int64(-1)}},
},
{
name: "two array not exist, disallow append",
src: ` [ [ 1 ] ] `,
args: args{path: []interface{}{0, 1}, val: "-1"},
want: ` [ [ 1 ] ] `,
exist: false,
val: []interface{}{[]interface{}{int64(1)}},
err: ErrNotExist,
},
{
name: "two array not exist, allow append",
src: ` [ [ 1 ] ] `,
args: args{path: []interface{}{0, 1}, val: "-1", allowArrayAppend: true},
want: ` [ [ 1,-1 ] ] `,
exist: false,
val: []interface{}{[]interface{}{int64(1), int64(-1)}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion dev/ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (self *Parser) locate(flags uint64, path ...interface{}) (start int, err ty
if start < 0 {
return -1, types.ParsingError(-start)
}
runtime.KeepAlive(path)
return start, 0
}

Expand All @@ -72,10 +73,10 @@ func (self *Parser) locateAndValidate(flags uint64, path ...interface{}) (start
var fsm = types.NewStateMachine()
start = native.GetByPath(&self.src, &self.pos, &path, fsm, flags)
types.FreeStateMachine(fsm)
runtime.KeepAlive(path)
if start < 0 {
return -1, types.ParsingError(-start)
}
runtime.KeepAlive(path)
return start, 0
}

Expand Down

0 comments on commit 79ef946

Please sign in to comment.