add more parsing tests
This commit is contained in:
@@ -61,7 +61,11 @@ func Parse(str string) (Selector, error) {
|
|||||||
|
|
||||||
// explicit field, ["abcd"]
|
// explicit field, ["abcd"]
|
||||||
case strings.HasPrefix(lookup, "\"") && strings.HasSuffix(lookup, "\""):
|
case strings.HasPrefix(lookup, "\"") && strings.HasSuffix(lookup, "\""):
|
||||||
sel = append(sel, segment{str: tok, optional: opt, field: lookup[1 : len(lookup)-1]})
|
fieldName := lookup[1 : len(lookup)-1]
|
||||||
|
if strings.Contains(fieldName, ":") {
|
||||||
|
return nil, newParseError(fmt.Sprintf("invalid segment: %s", seg), str, col, tok)
|
||||||
|
}
|
||||||
|
sel = append(sel, segment{str: tok, optional: opt, field: fieldName})
|
||||||
|
|
||||||
// slice [3:5] or [:5] or [3:], also negative numbers
|
// slice [3:5] or [:5] or [3:], also negative numbers
|
||||||
case sliceRegex.MatchString(lookup):
|
case sliceRegex.MatchString(lookup):
|
||||||
|
|||||||
@@ -412,6 +412,213 @@ func TestParse(t *testing.T) {
|
|||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("index out of range", func(t *testing.T) {
|
||||||
|
sel, err := Parse(".[1000]")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Empty(t, sel[1].Slice())
|
||||||
|
require.Empty(t, sel[1].Field())
|
||||||
|
require.Equal(t, sel[1].Index(), 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("negative index out of range", func(t *testing.T) {
|
||||||
|
sel, err := Parse(".[-1000]")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Empty(t, sel[1].Slice())
|
||||||
|
require.Empty(t, sel[1].Field())
|
||||||
|
require.Equal(t, sel[1].Index(), -1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice with negative start and positive end", func(t *testing.T) {
|
||||||
|
sel, err := Parse(".[0:-2]")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Equal(t, sel[1].Slice(), []int64{0, -2})
|
||||||
|
require.Empty(t, sel[1].Field())
|
||||||
|
require.Empty(t, sel[1].Index())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice with start greater than end", func(t *testing.T) {
|
||||||
|
sel, err := Parse(".[5:2]")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Equal(t, sel[1].Slice(), []int64{5, 2})
|
||||||
|
require.Empty(t, sel[1].Field())
|
||||||
|
require.Empty(t, sel[1].Index())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice on string", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`.["foo"].[1:3]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 4, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Empty(t, sel[1].Slice())
|
||||||
|
require.Equal(t, sel[1].Field(), "foo")
|
||||||
|
require.Empty(t, sel[1].Index())
|
||||||
|
require.True(t, sel[2].Identity())
|
||||||
|
require.False(t, sel[2].Optional())
|
||||||
|
require.False(t, sel[2].Iterator())
|
||||||
|
require.Empty(t, sel[2].Slice())
|
||||||
|
require.Empty(t, sel[2].Field())
|
||||||
|
require.Empty(t, sel[2].Index())
|
||||||
|
require.False(t, sel[3].Identity())
|
||||||
|
require.False(t, sel[3].Optional())
|
||||||
|
require.False(t, sel[3].Iterator())
|
||||||
|
require.Equal(t, sel[3].Slice(), []int64{1, 3})
|
||||||
|
require.Empty(t, sel[3].Field())
|
||||||
|
require.Empty(t, sel[3].Index())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("index on string", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`.["foo"].[1]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 4, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Empty(t, sel[1].Slice())
|
||||||
|
require.Equal(t, sel[1].Field(), "foo")
|
||||||
|
require.Empty(t, sel[1].Index())
|
||||||
|
require.True(t, sel[2].Identity())
|
||||||
|
require.False(t, sel[2].Optional())
|
||||||
|
require.False(t, sel[2].Iterator())
|
||||||
|
require.Empty(t, sel[2].Slice())
|
||||||
|
require.Empty(t, sel[2].Field())
|
||||||
|
require.Empty(t, sel[2].Index())
|
||||||
|
require.False(t, sel[3].Identity())
|
||||||
|
require.False(t, sel[3].Optional())
|
||||||
|
require.False(t, sel[3].Iterator())
|
||||||
|
require.Empty(t, sel[3].Slice())
|
||||||
|
require.Empty(t, sel[3].Field())
|
||||||
|
require.Equal(t, sel[3].Index(), 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice on array", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`.[1:3]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Equal(t, sel[1].Slice(), []int64{1, 3})
|
||||||
|
require.Empty(t, sel[1].Field())
|
||||||
|
require.Empty(t, sel[1].Index())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("index on array", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`.[1]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Empty(t, sel[1].Slice())
|
||||||
|
require.Empty(t, sel[1].Field())
|
||||||
|
require.Equal(t, sel[1].Index(), 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid slice on object", func(t *testing.T) {
|
||||||
|
_, err := Parse(`.["foo":"bar"]`)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "invalid segment")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("index on object", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`.["foo"]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(sel))
|
||||||
|
require.True(t, sel[0].Identity())
|
||||||
|
require.False(t, sel[0].Optional())
|
||||||
|
require.False(t, sel[0].Iterator())
|
||||||
|
require.Empty(t, sel[0].Slice())
|
||||||
|
require.Empty(t, sel[0].Field())
|
||||||
|
require.Empty(t, sel[0].Index())
|
||||||
|
require.False(t, sel[1].Identity())
|
||||||
|
require.False(t, sel[1].Optional())
|
||||||
|
require.False(t, sel[1].Iterator())
|
||||||
|
require.Empty(t, sel[1].Slice())
|
||||||
|
require.Equal(t, sel[1].Field(), "foo")
|
||||||
|
require.Empty(t, sel[1].Index())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice with non-integer start", func(t *testing.T) {
|
||||||
|
_, err := Parse(".[foo:3]")
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice with non-integer end", func(t *testing.T) {
|
||||||
|
_, err := Parse(".[1:bar]")
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("index with non-integer", func(t *testing.T) {
|
||||||
|
_, err := Parse(".[foo]")
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSegments(s Selector) {
|
func printSegments(s Selector) {
|
||||||
|
|||||||
@@ -171,7 +171,79 @@ func TestSelect(t *testing.T) {
|
|||||||
require.Equal(t, alice.Interests[1].Name, iname)
|
require.Equal(t, alice.Interests[1].Name, iname)
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: fully test slicing + negative numbers
|
t.Run("slice on string", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`["foo"].[1:3]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
node := basicnode.NewString("hello")
|
||||||
|
res, err := sel.Select(node)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, res)
|
||||||
|
|
||||||
|
str, err := res.AsString()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "el", str)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("index on string", func(t *testing.T) {
|
||||||
|
sel, err := Parse(`["foo"].[2]`)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
node := basicnode.NewString("hello")
|
||||||
|
res, err := sel.Select(node)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, res)
|
||||||
|
|
||||||
|
str, err := res.AsString()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "l", str)
|
||||||
|
})
|
||||||
|
|
||||||
|
//t.Run("out of bounds slicing", func(t *testing.T) {
|
||||||
|
// sel, err := Parse(`.[10:20]`)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
//
|
||||||
|
// node, err := qp.BuildList(basicnode.Prototype.Any, 3, func(la datamodel.ListAssembler) {
|
||||||
|
// qp.ListEntry(la, qp.Int(1))
|
||||||
|
// qp.ListEntry(la, qp.Int(2))
|
||||||
|
// qp.ListEntry(la, qp.Int(3))
|
||||||
|
// })
|
||||||
|
// require.NoError(t, err)
|
||||||
|
//
|
||||||
|
// res, err := sel.Select(node)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// require.NotEmpty(t, res)
|
||||||
|
//
|
||||||
|
// bytes, err := res.AsBytes()
|
||||||
|
// require.NoError(t, err)
|
||||||
|
//
|
||||||
|
// list, err := qp.DecodeList(basicnode.Prototype.Any, bytes)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// require.Equal(t, 0, list.Length())
|
||||||
|
//})
|
||||||
|
//
|
||||||
|
//t.Run("backward slicing", func(t *testing.T) {
|
||||||
|
// sel, err := Parse(`.[5:2]`)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
//
|
||||||
|
// node, err := qp.BuildList(basicnode.Prototype.Any, 3, func(la datamodel.ListAssembler) {
|
||||||
|
// qp.ListEntry(la, qp.Int(1))
|
||||||
|
// qp.ListEntry(la, qp.Int(2))
|
||||||
|
// qp.ListEntry(la, qp.Int(3))
|
||||||
|
// })
|
||||||
|
// require.NoError(t, err)
|
||||||
|
//
|
||||||
|
// res, err := sel.Select(node)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// require.NotEmpty(t, res)
|
||||||
|
//
|
||||||
|
// bytes, err := res.AsBytes()
|
||||||
|
// require.NoError(t, err)
|
||||||
|
//
|
||||||
|
// list, err := qp.DecodeList(basicnode.Prototype.Any, bytes)
|
||||||
|
// require.NoError(t, err)
|
||||||
|
// require.Equal(t, 0, list.Length())
|
||||||
|
//})
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestMatch(t *testing.T) {
|
// func TestMatch(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user