add more parsing tests
This commit is contained in:
@@ -61,7 +61,11 @@ func Parse(str string) (Selector, error) {
|
||||
|
||||
// explicit field, ["abcd"]
|
||||
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
|
||||
case sliceRegex.MatchString(lookup):
|
||||
|
||||
@@ -412,6 +412,213 @@ func TestParse(t *testing.T) {
|
||||
require.NotNil(t, 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) {
|
||||
|
||||
@@ -171,7 +171,79 @@ func TestSelect(t *testing.T) {
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user