github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/vm/stack_test.go (about)

     1  package vm
     2  
     3  import (
     4  	"math/big"
     5  	"testing"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestPushElement(t *testing.T) {
    13  	elems := makeElements(10)
    14  	s := NewStack("test")
    15  	for _, elem := range elems {
    16  		s.Push(elem)
    17  	}
    18  
    19  	assert.Equal(t, len(elems), s.Len())
    20  
    21  	for i := 0; i < len(elems); i++ {
    22  		assert.Equal(t, elems[len(elems)-1-i], s.Peek(i))
    23  	}
    24  }
    25  
    26  func TestStack_PushVal(t *testing.T) {
    27  	type (
    28  		i32      int32
    29  		testByte uint8
    30  	)
    31  
    32  	s := NewStack("test")
    33  	require.NotPanics(t, func() { s.PushVal(i32(123)) })
    34  	require.NotPanics(t, func() { s.PushVal(testByte(42)) })
    35  	require.Equal(t, 2, s.Len())
    36  	require.Equal(t, big.NewInt(42), s.Pop().Value())
    37  	require.Equal(t, big.NewInt(123), s.Pop().Value())
    38  }
    39  
    40  func TestPopElement(t *testing.T) {
    41  	var (
    42  		s     = NewStack("test")
    43  		elems = makeElements(10)
    44  	)
    45  	for _, elem := range elems {
    46  		s.Push(elem)
    47  	}
    48  
    49  	for i := len(elems) - 1; i >= 0; i-- {
    50  		assert.Equal(t, elems[i], s.Pop())
    51  		assert.Equal(t, i, s.Len())
    52  	}
    53  }
    54  
    55  func TestPeekElement(t *testing.T) {
    56  	var (
    57  		s     = NewStack("test")
    58  		elems = makeElements(10)
    59  	)
    60  	for _, elem := range elems {
    61  		s.Push(elem)
    62  	}
    63  	for i := len(elems) - 1; i >= 0; i-- {
    64  		assert.Equal(t, elems[i], s.Peek(len(elems)-i-1))
    65  	}
    66  }
    67  
    68  func TestRemoveAt(t *testing.T) {
    69  	var (
    70  		s     = NewStack("test")
    71  		elems = makeElements(10)
    72  	)
    73  	for _, elem := range elems {
    74  		s.Push(elem)
    75  	}
    76  
    77  	elem := s.RemoveAt(8)
    78  	assert.Equal(t, elems[1], elem)
    79  
    80  	// Test if the pointers are moved.
    81  	assert.Equal(t, elems[0], s.Peek(8))
    82  	assert.Equal(t, elems[2], s.Peek(7))
    83  }
    84  
    85  func TestPushFromOtherStack(t *testing.T) {
    86  	var (
    87  		s1    = NewStack("test")
    88  		s2    = NewStack("test2")
    89  		elems = makeElements(2)
    90  	)
    91  	for _, elem := range elems {
    92  		s1.Push(elem)
    93  	}
    94  	s2.Push(NewElement(100))
    95  	s2.Push(NewElement(101))
    96  
    97  	s1.Push(s2.Pop())
    98  	assert.Equal(t, len(elems)+1, s1.Len())
    99  	assert.Equal(t, 1, s2.Len())
   100  }
   101  
   102  func TestDupElement(t *testing.T) {
   103  	s := NewStack("test")
   104  	elemA := NewElement(101)
   105  	s.Push(elemA)
   106  
   107  	dupped := s.Dup(0)
   108  	s.Push(dupped)
   109  	assert.Equal(t, 2, s.Len())
   110  	assert.Equal(t, dupped, s.Peek(0))
   111  }
   112  
   113  func TestBack(t *testing.T) {
   114  	var (
   115  		s     = NewStack("test")
   116  		elems = makeElements(10)
   117  	)
   118  	for _, elem := range elems {
   119  		s.Push(elem)
   120  	}
   121  
   122  	assert.Equal(t, elems[0], s.Back())
   123  }
   124  
   125  func TestTop(t *testing.T) {
   126  	var (
   127  		s     = NewStack("test")
   128  		elems = makeElements(10)
   129  	)
   130  	for _, elem := range elems {
   131  		s.Push(elem)
   132  	}
   133  
   134  	assert.Equal(t, elems[len(elems)-1], s.Top())
   135  }
   136  
   137  func TestRemoveLastElement(t *testing.T) {
   138  	var (
   139  		s     = NewStack("test")
   140  		elems = makeElements(2)
   141  	)
   142  	for _, elem := range elems {
   143  		s.Push(elem)
   144  	}
   145  	elem := s.RemoveAt(1)
   146  	assert.Equal(t, elems[0], elem)
   147  	assert.Equal(t, 1, s.Len())
   148  }
   149  
   150  func TestIterAfterRemove(t *testing.T) {
   151  	var (
   152  		s     = NewStack("test")
   153  		elems = makeElements(10)
   154  	)
   155  	for _, elem := range elems {
   156  		s.Push(elem)
   157  	}
   158  	s.RemoveAt(0)
   159  
   160  	i := 0
   161  	s.Iter(func(_ Element) {
   162  		i++
   163  	})
   164  	assert.Equal(t, len(elems)-1, i)
   165  }
   166  
   167  func TestIteration(t *testing.T) {
   168  	var (
   169  		n     = 10
   170  		s     = NewStack("test")
   171  		elems = makeElements(n)
   172  	)
   173  	for _, elem := range elems {
   174  		s.Push(elem)
   175  	}
   176  	assert.Equal(t, len(elems), s.Len())
   177  
   178  	iteratedElems := make([]Element, 0)
   179  
   180  	s.Iter(func(elem Element) {
   181  		iteratedElems = append(iteratedElems, elem)
   182  	})
   183  
   184  	// Top to bottom order of iteration.
   185  	poppedElems := make([]Element, 0)
   186  	for s.Len() != 0 {
   187  		poppedElems = append(poppedElems, s.Pop())
   188  	}
   189  	assert.Equal(t, poppedElems, iteratedElems)
   190  }
   191  
   192  func TestBackIteration(t *testing.T) {
   193  	var (
   194  		n     = 10
   195  		s     = NewStack("test")
   196  		elems = makeElements(n)
   197  	)
   198  	for _, elem := range elems {
   199  		s.Push(elem)
   200  	}
   201  	assert.Equal(t, len(elems), s.Len())
   202  
   203  	iteratedElems := make([]Element, 0)
   204  
   205  	s.IterBack(func(elem Element) {
   206  		iteratedElems = append(iteratedElems, elem)
   207  	})
   208  	// Bottom to the top order of iteration.
   209  	assert.Equal(t, elems, iteratedElems)
   210  }
   211  
   212  func TestPushVal(t *testing.T) {
   213  	s := NewStack("test")
   214  
   215  	// integer
   216  	s.PushVal(2)
   217  	elem := s.Pop()
   218  	assert.Equal(t, int64(2), elem.BigInt().Int64())
   219  
   220  	// byteArray
   221  	s.PushVal([]byte("foo"))
   222  	elem = s.Pop()
   223  	assert.Equal(t, "foo", string(elem.Bytes()))
   224  
   225  	// boolean
   226  	s.PushVal(true)
   227  	elem = s.Pop()
   228  	assert.Equal(t, true, elem.Bool())
   229  
   230  	// array
   231  	s.PushVal([]stackitem.Item{stackitem.NewBool(true), stackitem.NewBool(false), stackitem.NewBool(true)})
   232  	elem = s.Pop()
   233  	assert.IsType(t, elem.value, &stackitem.Array{})
   234  }
   235  
   236  func TestStack_ToArray(t *testing.T) {
   237  	t.Run("Empty", func(t *testing.T) {
   238  		s := NewStack("test")
   239  		items := s.ToArray()
   240  		require.Equal(t, 0, len(items))
   241  	})
   242  	t.Run("NonEmpty", func(t *testing.T) {
   243  		s := NewStack("test")
   244  		expected := []stackitem.Item{stackitem.Make(1), stackitem.Make(true)}
   245  		for i := range expected {
   246  			s.PushVal(expected[i])
   247  		}
   248  		require.Equal(t, expected, s.ToArray())
   249  	})
   250  }
   251  
   252  func TestSwapElemValues(t *testing.T) {
   253  	s := NewStack("test")
   254  
   255  	s.PushVal(2)
   256  	s.PushVal(4)
   257  
   258  	assert.NoError(t, s.Swap(0, 1))
   259  	assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
   260  	assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
   261  
   262  	s.PushVal(1)
   263  	s.PushVal(2)
   264  	s.PushVal(3)
   265  	s.PushVal(4)
   266  
   267  	assert.NoError(t, s.Swap(1, 3))
   268  	assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
   269  	assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
   270  	assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
   271  	assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
   272  
   273  	s.PushVal(1)
   274  	s.PushVal(2)
   275  	s.PushVal(3)
   276  	s.PushVal(4)
   277  
   278  	assert.Error(t, s.Swap(-1, 0))
   279  	assert.Error(t, s.Swap(0, -3))
   280  	assert.Error(t, s.Swap(0, 4))
   281  	assert.Error(t, s.Swap(5, 0))
   282  
   283  	assert.NoError(t, s.Swap(1, 1))
   284  	assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
   285  	assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
   286  	assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
   287  	assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
   288  }
   289  
   290  func TestRoll(t *testing.T) {
   291  	s := NewStack("test")
   292  
   293  	s.PushVal(1)
   294  	s.PushVal(2)
   295  	s.PushVal(3)
   296  	s.PushVal(4)
   297  
   298  	assert.NoError(t, s.Roll(2))
   299  	assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
   300  	assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
   301  	assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
   302  	assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
   303  
   304  	s.PushVal(1)
   305  	s.PushVal(2)
   306  	s.PushVal(3)
   307  	s.PushVal(4)
   308  
   309  	assert.NoError(t, s.Roll(3))
   310  	assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
   311  	assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
   312  	assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
   313  	assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
   314  
   315  	s.PushVal(1)
   316  	s.PushVal(2)
   317  	s.PushVal(3)
   318  	s.PushVal(4)
   319  
   320  	assert.Error(t, s.Roll(-1))
   321  	assert.Error(t, s.Roll(4))
   322  
   323  	assert.NoError(t, s.Roll(0))
   324  	assert.Equal(t, int64(4), s.Pop().BigInt().Int64())
   325  	assert.Equal(t, int64(3), s.Pop().BigInt().Int64())
   326  	assert.Equal(t, int64(2), s.Pop().BigInt().Int64())
   327  	assert.Equal(t, int64(1), s.Pop().BigInt().Int64())
   328  }
   329  
   330  func TestInsertAt(t *testing.T) {
   331  	s := NewStack("stack")
   332  	s.PushVal(1)
   333  	s.PushVal(2)
   334  	s.PushVal(3)
   335  	s.PushVal(4)
   336  	s.PushVal(5)
   337  
   338  	e := s.Dup(1) // it's `4`
   339  	s.InsertAt(e, 3)
   340  
   341  	assert.Equal(t, int64(5), s.Peek(0).BigInt().Int64())
   342  	assert.Equal(t, int64(4), s.Peek(1).BigInt().Int64())
   343  	assert.Equal(t, int64(3), s.Peek(2).BigInt().Int64())
   344  	assert.Equal(t, int64(4), s.Peek(3).BigInt().Int64())
   345  	assert.Equal(t, int64(2), s.Peek(4).BigInt().Int64())
   346  	assert.Equal(t, int64(1), s.Peek(5).BigInt().Int64())
   347  }
   348  
   349  func TestPopSigElements(t *testing.T) {
   350  	s := NewStack("test")
   351  
   352  	_, err := s.PopSigElements()
   353  	assert.NotNil(t, err)
   354  
   355  	s.PushVal([]stackitem.Item{})
   356  	_, err = s.PopSigElements()
   357  	assert.NotNil(t, err)
   358  
   359  	s.PushVal([]stackitem.Item{stackitem.NewBool(false)})
   360  	_, err = s.PopSigElements()
   361  	assert.NotNil(t, err)
   362  
   363  	b1 := []byte("smth")
   364  	b2 := []byte("strange")
   365  	s.PushVal([]stackitem.Item{stackitem.NewByteArray(b1), stackitem.NewByteArray(b2)})
   366  	z, err := s.PopSigElements()
   367  	assert.Nil(t, err)
   368  	assert.Equal(t, z, [][]byte{b1, b2})
   369  
   370  	s.PushVal(2)
   371  	_, err = s.PopSigElements()
   372  	assert.NotNil(t, err)
   373  
   374  	s.PushVal(b1)
   375  	s.PushVal(2)
   376  	_, err = s.PopSigElements()
   377  	assert.NotNil(t, err)
   378  
   379  	s.PushVal(b2)
   380  	s.PushVal(b1)
   381  	s.PushVal(2)
   382  	z, err = s.PopSigElements()
   383  	assert.Nil(t, err)
   384  	assert.Equal(t, z, [][]byte{b1, b2})
   385  }
   386  
   387  func makeElements(n int) []Element {
   388  	elems := make([]Element, n)
   389  	for i := 0; i < n; i++ {
   390  		elems[i] = NewElement(i)
   391  	}
   392  	return elems
   393  }