Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions jsonpath.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,9 @@ func get_range(obj, frm, to interface{}) (interface{}, error) {
if _to > length {
_to = length
}
if _frm > _to {
_frm = _to
}
//fmt.Println("_frm, _to: ", _frm, _to)
res_v := reflect.ValueOf(obj).Slice(_frm, _to)
return res_v.Interface(), nil
Expand Down
54 changes: 53 additions & 1 deletion jsonpath_accessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

package jsonpath

import "testing"
import (
"reflect"
"testing"
)

// Accessor tests - test get_key, get_idx, get_range, get_scan functions

Expand Down Expand Up @@ -178,6 +181,55 @@ func Test_jsonpath_get_range(t *testing.T) {
}
}

func Test_jsonpath_reversed_ranges(t *testing.T) {
type intSlice []int
inputs := []struct {
name string
obj interface{}
}{
{"int_slice", []int{1, 2, 3, 4, 5}},
{"interface_slice", []interface{}{1, 2, 3, 4, 5}},
{"named_slice", intSlice{1, 2, 3, 4, 5}},
}
paths := []string{"$[3:1]", "$[-1:1]", "$[-1:-3]", "$[2:-10]", "$[3:0]", "$[2:2]"}
lookups := []struct {
name string
lookup func(interface{}, string) (interface{}, error)
}{
{"direct", JsonPathLookup},
{"compiled", func(obj interface{}, path string) (interface{}, error) {
compiled, err := Compile(path)
if err != nil {
return nil, err
}
return compiled.Lookup(obj)
}},
}
for _, input := range inputs {
for _, path := range paths {
for _, lookup := range lookups {
t.Run(input.name+"/"+path+"/"+lookup.name, func(t *testing.T) {
defer func() {
if p := recover(); p != nil {
t.Errorf("lookup panicked: %v", p)
}
}()
res, err := lookup.lookup(input.obj, path)
if err != nil {
t.Fatalf("lookup failed: %v", err)
}
if reflect.TypeOf(res) != reflect.TypeOf(input.obj) {
t.Fatalf("result type = %T, want %T", res, input.obj)
}
if reflect.ValueOf(res).Len() != 0 {
t.Errorf("result = %v, want empty slice", res)
}
})
}
}
}
}

func Test_jsonpath_get_scan(t *testing.T) {
obj := map[string]interface{}{
"key": 1,
Expand Down
18 changes: 4 additions & 14 deletions jsonpath_extra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,20 +352,13 @@ func Test_get_range_uncovered(t *testing.T) {
// Test: get_range negative to value (clamping to 0)
t.Run("get_range_negative_to_clamp", func(t *testing.T) {
obj := []interface{}{1, 2, 3, 4, 5}
// Negative to that would clamp below 0
// _to = 5 + (-10) + 1 = -4, clamped to 0
// But _frm = 2 > _to = 0, which causes panic in Slice
// This is actually a bug in the get_range function - it should check _frm > _to
// For now, we test a valid negative to case
res, err := get_range(obj, 0, -2)
res, err := get_range(obj, 2, -10)
if err != nil {
t.Fatalf("get_range failed: %v", err)
}
resSlice := res.([]interface{})
// _to = 5 + (-2) + 1 = 4
// Result should be [0:4] = 4 elements
if len(resSlice) != 4 {
t.Errorf("Expected 4, got %d", len(resSlice))
if len(resSlice) != 0 {
t.Errorf("Expected empty slice, got %d elements", len(resSlice))
}
})

Expand Down Expand Up @@ -1245,10 +1238,7 @@ func Test_get_range_more_coverage(t *testing.T) {
// Test: from >= to (returns empty slice)
t.Run("from_greater_or_equal_to", func(t *testing.T) {
obj := []interface{}{1, 2, 3, 4, 5}
// When from > to, the code clamps from to to, so from=3, to=1 becomes from=1, to=1
// This results in an empty slice [1:1]
// But the actual code may panic, so let's test a safer case
res, err := get_range(obj, 2, 2)
res, err := get_range(obj, 3, 1)
if err != nil {
t.Fatalf("get_range failed: %v", err)
}
Expand Down