enable string indexing/slicing and new selector tests

This commit is contained in:
Fabio Bozzo
2024-10-23 17:01:00 +02:00
parent 1728bf29b8
commit 2fafbe7bf3
2 changed files with 76 additions and 60 deletions

View File

@@ -229,17 +229,17 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, error) {
}
cur, _ = cur.LookupByIndex(int64(idx))
// TODO: cleanup if confirmed that slicing/indexing on string is not legal
// case datamodel.Kind_String:
// str, _ := cur.AsString()
// if idx < 0 {
// idx = len(str) + idx
// }
// if idx < 0 || idx >= len(str) {
// err := newResolutionError(fmt.Sprintf("index out of bounds: %d", seg.Index()), at)
// return nil, errIfNotOptional(seg, err)
// }
// cur = basicnode.NewString(string(str[idx]))
case datamodel.Kind_String:
str, _ := cur.AsString()
runes := []rune(str)
if idx < 0 {
idx = len(runes) + idx
}
if idx < 0 || idx >= len(runes) {
err := newResolutionError(fmt.Sprintf("index out of bounds: %d", seg.Index()), at)
return nil, errIfNotOptional(seg, err)
}
cur = basicnode.NewString(string(runes[idx]))
case datamodel.Kind_Bytes:
b, _ := cur.AsBytes()

View File

@@ -7,6 +7,8 @@ import (
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ipld/go-ipld-prime/fluent/qp"
"github.com/ipld/go-ipld-prime/must"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/node/bindnode"
@@ -172,7 +174,7 @@ func TestSelect(t *testing.T) {
})
t.Run("slice on string", func(t *testing.T) {
sel, err := Parse(`["foo"].[1:3]`)
sel, err := Parse(`.[1:3]`)
require.NoError(t, err)
node := basicnode.NewString("hello")
@@ -182,11 +184,11 @@ func TestSelect(t *testing.T) {
str, err := res.AsString()
require.NoError(t, err)
require.Equal(t, "el", str)
require.Equal(t, "el", str) // assert sliced substring
})
t.Run("index on string", func(t *testing.T) {
sel, err := Parse(`["foo"].[2]`)
sel, err := Parse(`.[2]`)
require.NoError(t, err)
node := basicnode.NewString("hello")
@@ -196,54 +198,68 @@ func TestSelect(t *testing.T) {
str, err := res.AsString()
require.NoError(t, err)
require.Equal(t, "l", str)
require.Equal(t, "l", str) // assert indexed character
})
//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())
//})
t.Run("out of bounds slicing", func(t *testing.T) {
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)
sel, err := Parse(`.[10:20]`)
require.NoError(t, err)
res, err := sel.Select(node)
require.NoError(t, err)
require.NotEmpty(t, res)
require.Equal(t, int64(0), res.Length())
_, err = res.LookupByIndex(0)
require.ErrorIs(t, err, datamodel.ErrNotExists{}) // assert empty result for out of bounds slice
})
t.Run("backward slicing", func(t *testing.T) {
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)
sel, err := Parse(`.[5:2]`)
require.NoError(t, err)
res, err := sel.Select(node)
require.NoError(t, err)
require.NotEmpty(t, res)
require.Equal(t, int64(0), res.Length())
_, err = res.LookupByIndex(0)
require.ErrorIs(t, err, datamodel.ErrNotExists{}) // assert empty result for backward slice
})
t.Run("slice with negative index", func(t *testing.T) {
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)
sel, err := Parse(`.[0:-1]`)
require.NoError(t, err)
res, err := sel.Select(node)
require.NoError(t, err)
require.NotEmpty(t, res)
val, err := res.LookupByIndex(1)
require.NoError(t, err)
require.Equal(t, 2, int(must.Int(val))) // Assert sliced value at index 1
})
}
// func TestMatch(t *testing.T) {