From 00ff88ef2371c4efed528cead7066d261c917fbc Mon Sep 17 00:00:00 2001 From: Fabio Bozzo Date: Thu, 24 Oct 2024 12:27:01 +0200 Subject: [PATCH] add slicing/indexing for bytes kind --- pkg/policy/selector/parsing_test.go | 36 ------------------- pkg/policy/selector/selector.go | 40 ++++++++++----------- pkg/policy/selector/selector_test.go | 52 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 56 deletions(-) diff --git a/pkg/policy/selector/parsing_test.go b/pkg/policy/selector/parsing_test.go index cbf7309..3edcfd6 100644 --- a/pkg/policy/selector/parsing_test.go +++ b/pkg/policy/selector/parsing_test.go @@ -413,42 +413,6 @@ func TestParse(t *testing.T) { 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) diff --git a/pkg/policy/selector/selector.go b/pkg/policy/selector/selector.go index f18f71f..829008f 100644 --- a/pkg/policy/selector/selector.go +++ b/pkg/policy/selector/selector.go @@ -3,7 +3,6 @@ package selector import ( "errors" "fmt" - "math" "strconv" "strings" @@ -229,7 +228,7 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, error) { idx = len(b) + idx } if idx < 0 || idx >= len(b) { - err := newResolutionError(fmt.Sprintf("index out of bounds: %d", seg.Index()), at) + err := newResolutionError(fmt.Sprintf("index %d out of bounds for bytes of length %d", seg.Index(), len(b)), at) return nil, errIfNotOptional(seg, err) } cur = basicnode.NewInt(int64(b[idx])) @@ -263,32 +262,33 @@ func resolveSliceIndices(slice []int64, length int64) (start int64, end int64) { start, end = slice[0], slice[1] - // adjust boundaries - switch { - case slice[0] == math.MinInt: - start = 0 - case slice[0] < 0: - start = length + slice[0] + // clamp start index + if start < 0 { + start = length + start + if start < 0 { + start = 0 + } } - switch { - case slice[1] == math.MaxInt: - end = length - case slice[1] < 0: - end = length + slice[1] + if start > length { + start = length } - // backward iteration is not allowed, shortcut to an empty result - if start >= end { - start, end = 0, 0 - } - // clamp out of bound - if start < 0 { - start = 0 + // clamp end index + if end < 0 { + end = length + end + if end < 0 { + end = 0 + } } if end > length { end = length } + // handle backward slicing + if start > end { + start, end = 0, 0 + } + return start, end } diff --git a/pkg/policy/selector/selector_test.go b/pkg/policy/selector/selector_test.go index e28fd51..4795efb 100644 --- a/pkg/policy/selector/selector_test.go +++ b/pkg/policy/selector/selector_test.go @@ -246,6 +246,58 @@ func TestSelect(t *testing.T) { require.NoError(t, err) require.Equal(t, 2, int(must.Int(val))) // Assert sliced value at index 1 }) + + t.Run("slice on bytes", func(t *testing.T) { + sel, err := Parse(`.[1:3]`) + require.NoError(t, err) + + node := basicnode.NewBytes([]byte{0x01, 0x02, 0x03, 0x04, 0x05}) + res, err := sel.Select(node) + require.NoError(t, err) + require.NotEmpty(t, res) + + bytes, err := res.AsBytes() + require.NoError(t, err) + require.Equal(t, []byte{0x02, 0x03}, bytes) // assert sliced bytes + }) + + t.Run("index on bytes", func(t *testing.T) { + sel, err := Parse(`.[2]`) + require.NoError(t, err) + + node := basicnode.NewBytes([]byte{0x01, 0x02, 0x03, 0x04, 0x05}) + res, err := sel.Select(node) + require.NoError(t, err) + require.NotEmpty(t, res) + + val, err := res.AsInt() + require.NoError(t, err) + require.Equal(t, int64(0x03), val) // assert indexed byte value + }) + + t.Run("out of bounds slicing on bytes", func(t *testing.T) { + sel, err := Parse(`.[10:20]`) + require.NoError(t, err) + + node := basicnode.NewBytes([]byte{0x01, 0x02, 0x03}) + res, err := sel.Select(node) + require.NoError(t, err) + require.NotNil(t, res) + + bytes, err := res.AsBytes() + require.NoError(t, err) + require.Empty(t, bytes) // assert empty result for out of bounds slice + }) + + t.Run("out of bounds indexing on bytes", func(t *testing.T) { + sel, err := Parse(`.[10]`) + require.NoError(t, err) + + node := basicnode.NewBytes([]byte{0x01, 0x02, 0x03}) + _, err = sel.Select(node) + require.Error(t, err) + require.Contains(t, err.Error(), "can not resolve path: .10") // assert error for out of bounds index + }) } func FuzzParse(f *testing.F) {