mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 19:29:39 +00:00
1b83dc2476
Mostly it's about Go 1.22+ syntax with ranging over integers, but it also prefers ranging over slices where possible (it makes code a little better to read). Notice that we have a number of dangerous loops where slices are mutated during loop execution, many of these can't be converted since we need proper length evalutation at every iteration. Signed-off-by: Roman Khimov <roman@nspcc.ru>
393 lines
8.1 KiB
Go
393 lines
8.1 KiB
Go
package vm
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPushElement(t *testing.T) {
|
|
elems := makeElements(10)
|
|
s := NewStack("test")
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
|
|
assert.Equal(t, len(elems), s.Len())
|
|
|
|
for i := range elems {
|
|
assert.Equal(t, elems[len(elems)-1-i], s.Peek(i))
|
|
}
|
|
}
|
|
|
|
func TestStack_PushVal(t *testing.T) {
|
|
type (
|
|
i32 int32
|
|
testByte uint8
|
|
)
|
|
|
|
s := NewStack("test")
|
|
require.NotPanics(t, func() { s.PushVal(i32(123)) })
|
|
require.NotPanics(t, func() { s.PushVal(testByte(42)) })
|
|
require.Equal(t, 2, s.Len())
|
|
require.Equal(t, big.NewInt(42), s.Pop().Value())
|
|
require.Equal(t, big.NewInt(123), s.Pop().Value())
|
|
}
|
|
|
|
func TestPopElement(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(10)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
|
|
for i := len(elems) - 1; i >= 0; i-- {
|
|
assert.Equal(t, elems[i], s.Pop())
|
|
assert.Equal(t, i, s.Len())
|
|
}
|
|
}
|
|
|
|
func TestPeekElement(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(10)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
for i := len(elems) - 1; i >= 0; i-- {
|
|
assert.Equal(t, elems[i], s.Peek(len(elems)-i-1))
|
|
}
|
|
}
|
|
|
|
func TestRemoveAt(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(10)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
|
|
elem := s.RemoveAt(8)
|
|
assert.Equal(t, elems[1], elem)
|
|
|
|
// Test if the pointers are moved.
|
|
assert.Equal(t, elems[0], s.Peek(8))
|
|
assert.Equal(t, elems[2], s.Peek(7))
|
|
}
|
|
|
|
func TestPushFromOtherStack(t *testing.T) {
|
|
var (
|
|
s1 = NewStack("test")
|
|
s2 = NewStack("test2")
|
|
elems = makeElements(2)
|
|
)
|
|
for _, elem := range elems {
|
|
s1.Push(elem)
|
|
}
|
|
s2.Push(NewElement(100))
|
|
s2.Push(NewElement(101))
|
|
|
|
s1.Push(s2.Pop())
|
|
assert.Equal(t, len(elems)+1, s1.Len())
|
|
assert.Equal(t, 1, s2.Len())
|
|
}
|
|
|
|
func TestDupElement(t *testing.T) {
|
|
s := NewStack("test")
|
|
elemA := NewElement(101)
|
|
s.Push(elemA)
|
|
|
|
dupped := s.Dup(0)
|
|
s.Push(dupped)
|
|
assert.Equal(t, 2, s.Len())
|
|
assert.Equal(t, dupped, s.Peek(0))
|
|
}
|
|
|
|
func TestBack(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(10)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
|
|
assert.Equal(t, elems[0], s.Back())
|
|
}
|
|
|
|
func TestTop(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(10)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
|
|
assert.Equal(t, elems[len(elems)-1], s.Top())
|
|
}
|
|
|
|
func TestRemoveLastElement(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(2)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
elem := s.RemoveAt(1)
|
|
assert.Equal(t, elems[0], elem)
|
|
assert.Equal(t, 1, s.Len())
|
|
}
|
|
|
|
func TestIterAfterRemove(t *testing.T) {
|
|
var (
|
|
s = NewStack("test")
|
|
elems = makeElements(10)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
s.RemoveAt(0)
|
|
|
|
i := 0
|
|
s.Iter(func(_ Element) {
|
|
i++
|
|
})
|
|
assert.Equal(t, len(elems)-1, i)
|
|
}
|
|
|
|
func TestIteration(t *testing.T) {
|
|
var (
|
|
n = 10
|
|
s = NewStack("test")
|
|
elems = makeElements(n)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
assert.Equal(t, len(elems), s.Len())
|
|
|
|
iteratedElems := make([]Element, 0)
|
|
|
|
s.Iter(func(elem Element) {
|
|
iteratedElems = append(iteratedElems, elem)
|
|
})
|
|
|
|
// Top to bottom order of iteration.
|
|
poppedElems := make([]Element, 0)
|
|
for s.Len() != 0 {
|
|
poppedElems = append(poppedElems, s.Pop())
|
|
}
|
|
assert.Equal(t, poppedElems, iteratedElems)
|
|
}
|
|
|
|
func TestBackIteration(t *testing.T) {
|
|
var (
|
|
n = 10
|
|
s = NewStack("test")
|
|
elems = makeElements(n)
|
|
)
|
|
for _, elem := range elems {
|
|
s.Push(elem)
|
|
}
|
|
assert.Equal(t, len(elems), s.Len())
|
|
|
|
iteratedElems := make([]Element, 0)
|
|
|
|
s.IterBack(func(elem Element) {
|
|
iteratedElems = append(iteratedElems, elem)
|
|
})
|
|
// Bottom to the top order of iteration.
|
|
assert.Equal(t, elems, iteratedElems)
|
|
}
|
|
|
|
func TestPushVal(t *testing.T) {
|
|
s := NewStack("test")
|
|
|
|
// integer
|
|
s.PushVal(2)
|
|
elem := s.Pop()
|
|
assert.Equal(t, int64(2), elem.BigInt().Int64())
|
|
|
|
// byteArray
|
|
s.PushVal([]byte("foo"))
|
|
elem = s.Pop()
|
|
assert.Equal(t, "foo", string(elem.Bytes()))
|
|
|
|
// boolean
|
|
s.PushVal(true)
|
|
elem = s.Pop()
|
|
assert.Equal(t, true, elem.Bool())
|
|
|
|
// array
|
|
s.PushVal([]stackitem.Item{stackitem.NewBool(true), stackitem.NewBool(false), stackitem.NewBool(true)})
|
|
elem = s.Pop()
|
|
assert.IsType(t, elem.value, &stackitem.Array{})
|
|
}
|
|
|
|
func TestStack_ToArray(t *testing.T) {
|
|
t.Run("Empty", func(t *testing.T) {
|
|
s := NewStack("test")
|
|
items := s.ToArray()
|
|
require.Equal(t, 0, len(items))
|
|
})
|
|
t.Run("NonEmpty", func(t *testing.T) {
|
|
s := NewStack("test")
|
|
expected := []stackitem.Item{stackitem.Make(1), stackitem.Make(true)}
|
|
for i := range expected {
|
|
s.PushVal(expected[i])
|
|
}
|
|
require.Equal(t, expected, s.ToArray())
|
|
})
|
|
}
|
|
|
|
func TestSwapElemValues(t *testing.T) {
|
|
s := NewStack("test")
|
|
|
|
s.PushVal(2)
|
|
s.PushVal(4)
|
|
|
|
assert.NoError(t, s.Swap(0, 1))
|
|
assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
|
|
|
|
s.PushVal(1)
|
|
s.PushVal(2)
|
|
s.PushVal(3)
|
|
s.PushVal(4)
|
|
|
|
assert.NoError(t, s.Swap(1, 3))
|
|
assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
|
|
|
|
s.PushVal(1)
|
|
s.PushVal(2)
|
|
s.PushVal(3)
|
|
s.PushVal(4)
|
|
|
|
assert.Error(t, s.Swap(-1, 0))
|
|
assert.Error(t, s.Swap(0, -3))
|
|
assert.Error(t, s.Swap(0, 4))
|
|
assert.Error(t, s.Swap(5, 0))
|
|
|
|
assert.NoError(t, s.Swap(1, 1))
|
|
assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
|
|
}
|
|
|
|
func TestRoll(t *testing.T) {
|
|
s := NewStack("test")
|
|
|
|
s.PushVal(1)
|
|
s.PushVal(2)
|
|
s.PushVal(3)
|
|
s.PushVal(4)
|
|
|
|
assert.NoError(t, s.Roll(2))
|
|
assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
|
|
|
|
s.PushVal(1)
|
|
s.PushVal(2)
|
|
s.PushVal(3)
|
|
s.PushVal(4)
|
|
|
|
assert.NoError(t, s.Roll(3))
|
|
assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
|
|
|
|
s.PushVal(1)
|
|
s.PushVal(2)
|
|
s.PushVal(3)
|
|
s.PushVal(4)
|
|
|
|
assert.Error(t, s.Roll(-1))
|
|
assert.Error(t, s.Roll(4))
|
|
|
|
assert.NoError(t, s.Roll(0))
|
|
assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
|
|
assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
|
|
}
|
|
|
|
func TestInsertAt(t *testing.T) {
|
|
s := NewStack("stack")
|
|
s.PushVal(1)
|
|
s.PushVal(2)
|
|
s.PushVal(3)
|
|
s.PushVal(4)
|
|
s.PushVal(5)
|
|
|
|
e := s.Dup(1) // it's `4`
|
|
s.InsertAt(e, 3)
|
|
|
|
assert.Equal(t, int64(5), s.Peek(0).BigInt().Int64())
|
|
assert.Equal(t, int64(4), s.Peek(1).BigInt().Int64())
|
|
assert.Equal(t, int64(3), s.Peek(2).BigInt().Int64())
|
|
assert.Equal(t, int64(4), s.Peek(3).BigInt().Int64())
|
|
assert.Equal(t, int64(2), s.Peek(4).BigInt().Int64())
|
|
assert.Equal(t, int64(1), s.Peek(5).BigInt().Int64())
|
|
}
|
|
|
|
func TestPopSigElements(t *testing.T) {
|
|
s := NewStack("test")
|
|
|
|
_, err := s.PopSigElements()
|
|
assert.NotNil(t, err)
|
|
|
|
s.PushVal([]stackitem.Item{})
|
|
_, err = s.PopSigElements()
|
|
assert.NotNil(t, err)
|
|
|
|
s.PushVal([]stackitem.Item{stackitem.NewBool(false)})
|
|
_, err = s.PopSigElements()
|
|
assert.NotNil(t, err)
|
|
|
|
b1 := []byte("smth")
|
|
b2 := []byte("strange")
|
|
s.PushVal([]stackitem.Item{stackitem.NewByteArray(b1), stackitem.NewByteArray(b2)})
|
|
z, err := s.PopSigElements()
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, z, [][]byte{b1, b2})
|
|
|
|
s.PushVal(2)
|
|
_, err = s.PopSigElements()
|
|
assert.NotNil(t, err)
|
|
|
|
s.PushVal(b1)
|
|
s.PushVal(2)
|
|
_, err = s.PopSigElements()
|
|
assert.NotNil(t, err)
|
|
|
|
s.PushVal(b2)
|
|
s.PushVal(b1)
|
|
s.PushVal(2)
|
|
z, err = s.PopSigElements()
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, z, [][]byte{b1, b2})
|
|
}
|
|
|
|
func makeElements(n int) []Element {
|
|
elems := make([]Element, n)
|
|
for i := range n {
|
|
elems[i] = NewElement(i)
|
|
}
|
|
return elems
|
|
}
|