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

     1  package stackitem
     2  
     3  import (
     4  	"math/big"
     5  	"testing"
     6  
     7  	"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
     8  	"github.com/nspcc-dev/neo-go/pkg/util"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  var makeStackItemTestCases = []struct {
    14  	input  any
    15  	result Item
    16  }{
    17  	{
    18  		input:  int64(3),
    19  		result: (*BigInteger)(big.NewInt(3)),
    20  	},
    21  	{
    22  		input:  int16(3),
    23  		result: (*BigInteger)(big.NewInt(3)),
    24  	},
    25  	{
    26  		input:  3,
    27  		result: (*BigInteger)(big.NewInt(3)),
    28  	},
    29  	{
    30  		input:  uint8(3),
    31  		result: (*BigInteger)(big.NewInt(3)),
    32  	},
    33  	{
    34  		input:  uint16(3),
    35  		result: (*BigInteger)(big.NewInt(3)),
    36  	},
    37  	{
    38  		input:  uint32(3),
    39  		result: (*BigInteger)(big.NewInt(3)),
    40  	},
    41  	{
    42  		input:  uint64(3),
    43  		result: (*BigInteger)(big.NewInt(3)),
    44  	},
    45  	{
    46  		input:  big.NewInt(3),
    47  		result: (*BigInteger)(big.NewInt(3)),
    48  	},
    49  	{
    50  		input:  []byte{1, 2, 3, 4},
    51  		result: NewByteArray([]byte{1, 2, 3, 4}),
    52  	},
    53  	{
    54  		input:  []byte{},
    55  		result: NewByteArray([]byte{}),
    56  	},
    57  	{
    58  		input:  "bla",
    59  		result: NewByteArray([]byte("bla")),
    60  	},
    61  	{
    62  		input:  "",
    63  		result: NewByteArray([]byte{}),
    64  	},
    65  	{
    66  		input:  true,
    67  		result: Bool(true),
    68  	},
    69  	{
    70  		input:  false,
    71  		result: Bool(false),
    72  	},
    73  	{
    74  		input:  []Item{(*BigInteger)(big.NewInt(3)), NewByteArray([]byte{1, 2, 3})},
    75  		result: &Array{value: []Item{(*BigInteger)(big.NewInt(3)), NewByteArray([]byte{1, 2, 3})}},
    76  	},
    77  	{
    78  		input:  []int{1, 2, 3},
    79  		result: &Array{value: []Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}},
    80  	},
    81  	{
    82  		input:  nil,
    83  		result: Null{},
    84  	},
    85  	{
    86  		input:  &util.Uint160{1, 2, 3},
    87  		result: NewByteArray(util.Uint160{1, 2, 3}.BytesBE()),
    88  	},
    89  	{
    90  		input:  &util.Uint256{1, 2, 3},
    91  		result: NewByteArray(util.Uint256{1, 2, 3}.BytesBE()),
    92  	},
    93  	{
    94  		input:  (*util.Uint160)(nil),
    95  		result: Null{},
    96  	},
    97  	{
    98  		input:  (*util.Uint256)(nil),
    99  		result: Null{},
   100  	},
   101  }
   102  
   103  var makeStackItemErrorCases = []struct {
   104  	input any
   105  }{
   106  	{
   107  		input: map[int]int{1: 2},
   108  	},
   109  }
   110  
   111  func TestMakeStackItem(t *testing.T) {
   112  	for _, testCase := range makeStackItemTestCases {
   113  		assert.Equal(t, testCase.result, Make(testCase.input))
   114  	}
   115  	for _, errorCase := range makeStackItemErrorCases {
   116  		assert.Panics(t, func() { Make(errorCase.input) })
   117  	}
   118  }
   119  
   120  var stringerTestCases = []struct {
   121  	input  Item
   122  	result string
   123  }{
   124  	{
   125  		input:  NewStruct([]Item{}),
   126  		result: "Struct",
   127  	},
   128  	{
   129  		input:  NewBigInteger(big.NewInt(3)),
   130  		result: "BigInteger",
   131  	},
   132  	{
   133  		input:  NewBool(true),
   134  		result: "Boolean",
   135  	},
   136  	{
   137  		input:  NewByteArray([]byte{}),
   138  		result: "ByteString",
   139  	},
   140  	{
   141  		input:  NewArray([]Item{}),
   142  		result: "Array",
   143  	},
   144  	{
   145  		input:  NewMap(),
   146  		result: "Map",
   147  	},
   148  	{
   149  		input:  NewInterop(nil),
   150  		result: "InteropInterface",
   151  	},
   152  	{
   153  		input:  NewPointer(0, nil),
   154  		result: "Pointer",
   155  	},
   156  }
   157  
   158  func TestStringer(t *testing.T) {
   159  	for _, testCase := range stringerTestCases {
   160  		assert.Equal(t, testCase.result, testCase.input.String())
   161  	}
   162  }
   163  
   164  var equalsTestCases = map[string][]struct {
   165  	item1  Item
   166  	item2  Item
   167  	result bool
   168  	panics bool
   169  }{
   170  	"struct": {
   171  		{
   172  			item1:  NewStruct(nil),
   173  			item2:  nil,
   174  			result: false,
   175  		},
   176  		{
   177  			item1:  NewStruct(nil),
   178  			item2:  NewBigInteger(big.NewInt(1)),
   179  			result: false,
   180  		},
   181  		{
   182  			item1:  NewStruct(nil),
   183  			item2:  NewStruct([]Item{NewBigInteger(big.NewInt(1))}),
   184  			result: false,
   185  		},
   186  		{
   187  			item1:  NewStruct([]Item{NewBigInteger(big.NewInt(1))}),
   188  			item2:  NewStruct([]Item{NewBigInteger(big.NewInt(2))}),
   189  			result: false,
   190  		},
   191  		{
   192  			item1:  NewStruct([]Item{NewBigInteger(big.NewInt(1))}),
   193  			item2:  NewStruct([]Item{NewBigInteger(big.NewInt(1))}),
   194  			result: true,
   195  		},
   196  		{
   197  			item1:  NewStruct([]Item{NewBigInteger(big.NewInt(1)), NewStruct([]Item{})}),
   198  			item2:  NewStruct([]Item{NewBigInteger(big.NewInt(1)), NewStruct([]Item{})}),
   199  			result: true,
   200  		},
   201  	},
   202  	"bigint": {
   203  		{
   204  			item1:  NewBigInteger(big.NewInt(2)),
   205  			item2:  nil,
   206  			result: false,
   207  		},
   208  		{
   209  			item1:  NewBigInteger(big.NewInt(2)),
   210  			item2:  NewBigInteger(big.NewInt(2)),
   211  			result: true,
   212  		},
   213  		{
   214  			item1:  NewBigInteger(big.NewInt(2)),
   215  			item2:  NewBool(false),
   216  			result: false,
   217  		},
   218  		{
   219  			item1:  NewBigInteger(big.NewInt(0)),
   220  			item2:  NewBool(false),
   221  			result: false,
   222  		},
   223  		{
   224  			item1:  NewBigInteger(big.NewInt(2)),
   225  			item2:  Make(int32(2)),
   226  			result: true,
   227  		},
   228  	},
   229  	"bool": {
   230  		{
   231  			item1:  NewBool(true),
   232  			item2:  nil,
   233  			result: false,
   234  		},
   235  		{
   236  			item1:  NewBool(true),
   237  			item2:  NewBool(true),
   238  			result: true,
   239  		},
   240  		{
   241  			item1:  NewBool(true),
   242  			item2:  NewBigInteger(big.NewInt(1)),
   243  			result: false,
   244  		},
   245  		{
   246  			item1:  NewBool(true),
   247  			item2:  NewBool(false),
   248  			result: false,
   249  		},
   250  		{
   251  			item1:  NewBool(true),
   252  			item2:  Make(true),
   253  			result: true,
   254  		},
   255  	},
   256  	"bytearray": {
   257  		{
   258  			item1:  NewByteArray(nil),
   259  			item2:  nil,
   260  			result: false,
   261  		},
   262  		{
   263  			item1:  NewByteArray([]byte{1, 2, 3}),
   264  			item2:  NewByteArray([]byte{1, 2, 3}),
   265  			result: true,
   266  		},
   267  		{
   268  			item1:  NewByteArray([]byte{1}),
   269  			item2:  NewBigInteger(big.NewInt(1)),
   270  			result: false,
   271  		},
   272  		{
   273  			item1:  NewByteArray([]byte{1, 2, 3}),
   274  			item2:  NewByteArray([]byte{1, 2, 4}),
   275  			result: false,
   276  		},
   277  		{
   278  			item1:  NewByteArray([]byte{1, 2, 3}),
   279  			item2:  Make([]byte{1, 2, 3}),
   280  			result: true,
   281  		},
   282  		{
   283  			item1:  NewByteArray(make([]byte, MaxByteArrayComparableSize+1)),
   284  			item2:  NewByteArray([]byte{1, 2, 3}),
   285  			panics: true,
   286  		},
   287  		{
   288  			item1:  NewByteArray([]byte{1, 2, 3}),
   289  			item2:  NewByteArray(make([]byte, MaxByteArrayComparableSize+1)),
   290  			panics: true,
   291  		},
   292  		{
   293  			item1:  NewByteArray(make([]byte, MaxByteArrayComparableSize+1)),
   294  			item2:  NewByteArray(make([]byte, MaxByteArrayComparableSize+1)),
   295  			panics: true,
   296  		},
   297  	},
   298  	"array": {
   299  		{
   300  			item1:  NewArray(nil),
   301  			item2:  nil,
   302  			result: false,
   303  		},
   304  		{
   305  			item1:  NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
   306  			item2:  NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
   307  			result: false,
   308  		},
   309  		{
   310  			item1:  NewArray([]Item{(*BigInteger)(big.NewInt(1))}),
   311  			item2:  NewBigInteger(big.NewInt(1)),
   312  			result: false,
   313  		},
   314  		{
   315  			item1:  NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(3))}),
   316  			item2:  NewArray([]Item{(*BigInteger)(big.NewInt(1)), (*BigInteger)(big.NewInt(2)), (*BigInteger)(big.NewInt(4))}),
   317  			result: false,
   318  		},
   319  	},
   320  	"map": {
   321  		{
   322  			item1:  NewMap(),
   323  			item2:  nil,
   324  			result: false,
   325  		},
   326  		{
   327  			item1:  NewMap(),
   328  			item2:  NewMap(),
   329  			result: false,
   330  		},
   331  		{
   332  			item1:  &Map{value: []MapElement{{NewByteArray([]byte("first")), NewBigInteger(big.NewInt(1))}, {NewBool(true), NewByteArray([]byte{2})}}},
   333  			item2:  &Map{value: []MapElement{{NewByteArray([]byte("first")), NewBigInteger(big.NewInt(1))}, {NewBool(true), NewByteArray([]byte{2})}}},
   334  			result: false,
   335  		},
   336  		{
   337  			item1:  &Map{value: []MapElement{{NewByteArray([]byte("first")), NewBigInteger(big.NewInt(1))}, {NewBool(true), NewByteArray([]byte{2})}}},
   338  			item2:  &Map{value: []MapElement{{NewByteArray([]byte("first")), NewBigInteger(big.NewInt(1))}, {NewBool(true), NewByteArray([]byte{3})}}},
   339  			result: false,
   340  		},
   341  	},
   342  	"interop": {
   343  		{
   344  			item1:  NewInterop(nil),
   345  			item2:  nil,
   346  			result: false,
   347  		},
   348  		{
   349  			item1:  NewInterop(nil),
   350  			item2:  NewInterop(nil),
   351  			result: true,
   352  		},
   353  		{
   354  			item1:  NewInterop(2),
   355  			item2:  NewInterop(3),
   356  			result: false,
   357  		},
   358  		{
   359  			item1:  NewInterop(3),
   360  			item2:  NewInterop(3),
   361  			result: true,
   362  		},
   363  	},
   364  	"pointer": {
   365  		{
   366  			item1:  NewPointer(0, []byte{}),
   367  			result: false,
   368  		},
   369  		{
   370  			item1:  NewPointer(1, []byte{1}),
   371  			item2:  NewPointer(1, []byte{1}),
   372  			result: true,
   373  		},
   374  		{
   375  			item1:  NewPointer(1, []byte{1}),
   376  			item2:  NewPointer(2, []byte{1}),
   377  			result: false,
   378  		},
   379  		{
   380  			item1:  NewPointer(1, []byte{1}),
   381  			item2:  NewPointer(1, []byte{2}),
   382  			result: false,
   383  		},
   384  		{
   385  			item1:  NewPointer(0, []byte{}),
   386  			item2:  NewBigInteger(big.NewInt(0)),
   387  			result: false,
   388  		},
   389  	},
   390  }
   391  
   392  func TestEquals(t *testing.T) {
   393  	for name, testBatch := range equalsTestCases {
   394  		for _, testCase := range testBatch {
   395  			t.Run(name, func(t *testing.T) {
   396  				if testCase.panics {
   397  					assert.Panics(t, func() {
   398  						testCase.item1.Equals(testCase.item2)
   399  					})
   400  				} else {
   401  					assert.Equal(t, testCase.result, testCase.item1.Equals(testCase.item2))
   402  					// Reference equals
   403  					assert.Equal(t, true, testCase.item1.Equals(testCase.item1))
   404  				}
   405  			})
   406  		}
   407  	}
   408  }
   409  
   410  func TestEqualsDeepStructure(t *testing.T) {
   411  	const perStruct = 4
   412  	var items = []Item{}
   413  	var num int
   414  	for i := 0; i < perStruct; i++ {
   415  		items = append(items, Make(0))
   416  		num++
   417  	}
   418  	var layerUp = func(sa *Struct, num int) (*Struct, int) {
   419  		items := []Item{}
   420  		for i := 0; i < perStruct; i++ {
   421  			clon, err := sa.Clone()
   422  			require.NoError(t, err)
   423  			items = append(items, clon)
   424  		}
   425  		num *= perStruct
   426  		num++
   427  		return NewStruct(items), num
   428  	}
   429  	var sa = NewStruct(items)
   430  	for i := 0; i < 4; i++ {
   431  		sa, num = layerUp(sa, num)
   432  	}
   433  	require.Less(t, num, MaxComparableNumOfItems)
   434  	sb, err := sa.Clone()
   435  	require.NoError(t, err)
   436  	require.True(t, sa.Equals(sb))
   437  	sa, num = layerUp(sa, num)
   438  	sb, num = layerUp(sb, num)
   439  
   440  	require.Less(t, MaxComparableNumOfItems, num)
   441  	require.Panics(t, func() { sa.Equals(sb) })
   442  }
   443  
   444  var marshalJSONTestCases = []struct {
   445  	input  Item
   446  	result []byte
   447  }{
   448  	{
   449  		input:  NewBigInteger(big.NewInt(2)),
   450  		result: []byte(`2`),
   451  	},
   452  	{
   453  		input:  NewBool(true),
   454  		result: []byte(`true`),
   455  	},
   456  	{
   457  		input:  NewByteArray([]byte{1, 2, 3}),
   458  		result: []byte(`"010203"`),
   459  	},
   460  	{
   461  		input:  NewBuffer([]byte{1, 2, 3}),
   462  		result: []byte(`"010203"`),
   463  	},
   464  	{
   465  		input:  &Array{value: []Item{(*BigInteger)(big.NewInt(3)), NewByteArray([]byte{1, 2, 3})}},
   466  		result: []byte(`[3,"010203"]`),
   467  	},
   468  	{
   469  		input:  &Interop{value: 3},
   470  		result: []byte(`3`),
   471  	},
   472  }
   473  
   474  func TestMarshalJSON(t *testing.T) {
   475  	var (
   476  		actual []byte
   477  		err    error
   478  	)
   479  	for _, testCase := range marshalJSONTestCases {
   480  		switch testCase.input.(type) {
   481  		case *BigInteger:
   482  			actual, err = testCase.input.(*BigInteger).MarshalJSON()
   483  		case Bool:
   484  			actual, err = testCase.input.(Bool).MarshalJSON()
   485  		case *ByteArray:
   486  			actual, err = testCase.input.(*ByteArray).MarshalJSON()
   487  		case *Array:
   488  			actual, err = testCase.input.(*Array).MarshalJSON()
   489  		case *Interop:
   490  			actual, err = testCase.input.(*Interop).MarshalJSON()
   491  		default:
   492  			continue
   493  		}
   494  
   495  		assert.NoError(t, err)
   496  		assert.Equal(t, testCase.result, actual)
   497  	}
   498  }
   499  
   500  func TestNewVeryBigInteger(t *testing.T) {
   501  	check := func(ok bool, v *big.Int) {
   502  		bs := bigint.ToBytes(v)
   503  		if ok {
   504  			assert.True(t, len(bs)*8 <= MaxBigIntegerSizeBits)
   505  		} else {
   506  			assert.True(t, len(bs)*8 > MaxBigIntegerSizeBits)
   507  			assert.Panics(t, func() { NewBigInteger(v) })
   508  		}
   509  	}
   510  
   511  	maxBitSet := big.NewInt(1)
   512  	maxBitSet.Lsh(maxBitSet, MaxBigIntegerSizeBits-1)
   513  
   514  	check(false, maxBitSet)
   515  	check(true, new(big.Int).Neg(maxBitSet))
   516  
   517  	minus1 := new(big.Int).Sub(maxBitSet, big.NewInt(1))
   518  	check(true, minus1)
   519  	check(true, new(big.Int).Neg(minus1))
   520  
   521  	plus1 := new(big.Int).Add(maxBitSet, big.NewInt(1))
   522  	check(false, plus1)
   523  	check(false, new(big.Int).Neg(plus1))
   524  
   525  	check(false, new(big.Int).Mul(maxBitSet, big.NewInt(2)))
   526  }
   527  
   528  func TestStructClone(t *testing.T) {
   529  	st0 := Struct{}
   530  	st := Struct{value: []Item{&st0}}
   531  	for i := 0; i < MaxClonableNumOfItems-1; i++ {
   532  		nst, err := st.Clone()
   533  		require.NoError(t, err)
   534  		st = Struct{value: []Item{nst}}
   535  	}
   536  	_, err := st.Clone()
   537  	require.Error(t, err)
   538  }
   539  
   540  func TestDeepCopy(t *testing.T) {
   541  	testCases := []struct {
   542  		name string
   543  		item Item
   544  	}{
   545  		{"Integer", NewBigInteger(big.NewInt(1))},
   546  		{"ByteArray", NewByteArray([]byte{1, 2, 3})},
   547  		{"Buffer", NewBuffer([]byte{1, 2, 3})},
   548  		{"Bool", NewBool(true)},
   549  		{"Pointer", NewPointer(1, []byte{1, 2, 3})},
   550  		{"Interop", NewInterop(&[]byte{1, 2})},
   551  	}
   552  	for _, tc := range testCases {
   553  		t.Run(tc.name, func(t *testing.T) {
   554  			actual := DeepCopy(tc.item, false)
   555  			if immut, ok := tc.item.(Immutable); ok {
   556  				immut.MarkAsReadOnly() // tiny hack for test to be able to compare object references.
   557  			}
   558  			require.Equal(t, tc.item, actual)
   559  			if tc.item.Type() != BooleanT {
   560  				require.False(t, actual == tc.item)
   561  			}
   562  		})
   563  	}
   564  
   565  	t.Run("Null", func(t *testing.T) {
   566  		require.Equal(t, Null{}, DeepCopy(Null{}, false))
   567  	})
   568  
   569  	t.Run("Array", func(t *testing.T) {
   570  		arr := NewArray(make([]Item, 2))
   571  		arr.value[0] = NewBool(true)
   572  		arr.value[1] = arr
   573  
   574  		actual := DeepCopy(arr, false)
   575  		arr.isReadOnly = true // tiny hack for test to be able to compare object references.
   576  		require.Equal(t, arr, actual)
   577  		require.False(t, arr == actual)
   578  		require.True(t, actual == actual.(*Array).value[1])
   579  	})
   580  
   581  	t.Run("Struct", func(t *testing.T) {
   582  		arr := NewStruct(make([]Item, 2))
   583  		arr.value[0] = NewBool(true)
   584  		arr.value[1] = arr
   585  
   586  		actual := DeepCopy(arr, false)
   587  		arr.isReadOnly = true // tiny hack for test to be able to compare object references.
   588  		require.Equal(t, arr, actual)
   589  		require.False(t, arr == actual)
   590  		require.True(t, actual == actual.(*Struct).value[1])
   591  	})
   592  
   593  	t.Run("Map", func(t *testing.T) {
   594  		m := NewMapWithValue(make([]MapElement, 2))
   595  		m.value[0] = MapElement{Key: NewBool(true), Value: m}
   596  		m.value[1] = MapElement{Key: NewBigInteger(big.NewInt(1)), Value: NewByteArray([]byte{1, 2, 3})}
   597  
   598  		actual := DeepCopy(m, false)
   599  		m.isReadOnly = true // tiny hack for test to be able to compare object references.
   600  		require.Equal(t, m, actual)
   601  		require.False(t, m == actual)
   602  		require.True(t, actual == actual.(*Map).value[0].Value)
   603  	})
   604  }