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

View File

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