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
34 changes: 28 additions & 6 deletions array.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,20 @@ func (a *Array) Length() *Number {
return newNumber(opChain, float64(len(a.value)))
}

// rawIndex returns array index for given index. Supports negative index. issue #461
// If index is out of array bounds, remain unchanged
// index must be between [-len(a.value), len(a.value)-1]
func (a *Array) rawIndex(index int) int {
maxIdx := len(a.value)
// support negative index
if index < 0 {
// negative index, calculate actual index
index += maxIdx
}

return index
}

// Value returns a new Value instance with array element for given index.
//
// If index is out of array bounds, Value reports failure and returns empty
Expand All @@ -168,12 +182,15 @@ func (a *Array) Value(index int) *Value {
return newValue(opChain, nil)
}

srcIndex := index
index = a.rawIndex(index)

if index < 0 || index >= len(a.value) {
opChain.fail(AssertionFailure{
Type: AssertInRange,
Actual: &AssertionValue{index},
Actual: &AssertionValue{srcIndex},
Expected: &AssertionValue{AssertionRange{
Min: 0,
Min: -len(a.value),
Max: len(a.value) - 1,
}},
Errors: []error{
Expand Down Expand Up @@ -208,12 +225,15 @@ func (a *Array) HasValue(index int, value interface{}) *Array {
return a
}

srcIndex := index
index = a.rawIndex(index)

if index < 0 || index >= len(a.value) {
opChain.fail(AssertionFailure{
Type: AssertInRange,
Actual: &AssertionValue{index},
Actual: &AssertionValue{srcIndex},
Expected: &AssertionValue{AssertionRange{
Min: 0,
Min: -len(a.value),
Max: len(a.value) - 1,
}},
Errors: []error{
Expand Down Expand Up @@ -262,12 +282,14 @@ func (a *Array) NotHasValue(index int, value interface{}) *Array {
return a
}

srcIndex := index
index = a.rawIndex(index)
if index < 0 || index >= len(a.value) {
opChain.fail(AssertionFailure{
Type: AssertInRange,
Actual: &AssertionValue{index},
Actual: &AssertionValue{srcIndex},
Expected: &AssertionValue{AssertionRange{
Min: 0,
Min: -len(a.value),
Max: len(a.value) - 1,
}},
Errors: []error{
Expand Down
57 changes: 57 additions & 0 deletions array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2568,3 +2568,60 @@ func TestArray_ComparatorErrors(t *testing.T) {
chain.assert(t, success)
})
}

func TestArray_NegativeIndex(t *testing.T) {
waitTestArr := []interface{}{"1", "2", "3", "4", "5", "6"}
testArgs := []struct {
index int
value string
}{{-1, "6"}, {-2, "5"}, {-3, "4"}, {-4, "3"}, {-5, "2"}, {-6, "1"}}

newTestArr := func() *Array {
reporter := newMockReporter(t)
return NewArray(reporter, waitTestArr)
}

t.Run("negative index Value", func(t *testing.T) {

for _, arg := range testArgs {
value := newTestArr().Value(arg.index)
value.chain.assert(t, success)
assert.Equal(t, value.Raw(), arg.value)
}

failedArgs := []int{-7, -9999999}
for _, arg := range failedArgs {
value := newTestArr().Value(arg)
value.chain.assert(t, failure)

}

})

t.Run("negative index HasValue", func(t *testing.T) {

for _, arg := range testArgs {
newTestArr().HasValue(arg.index, arg.value).
chain.assert(t, success)
}
})

t.Run("negative index NotHasValue_failure", func(t *testing.T) {

for _, arg := range testArgs {
newTestArr().NotHasValue(arg.index, arg.value).
chain.assert(t, failure)
}

})

t.Run("negative index NotHasValue_success", func(t *testing.T) {

for _, arg := range testArgs {
newTestArr().NotHasValue(arg.index, arg.value+"1").
chain.assert(t, success)
}

})

}
Loading