github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/native/std_test.go (about)

     1  package native
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/hex"
     6  	"math"
     7  	"math/big"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/mr-tron/base58"
    12  	"github.com/nspcc-dev/neo-go/pkg/core/dao"
    13  	"github.com/nspcc-dev/neo-go/pkg/core/interop"
    14  	base58neogo "github.com/nspcc-dev/neo-go/pkg/encoding/base58"
    15  	"github.com/nspcc-dev/neo-go/pkg/vm"
    16  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func TestStdLibItoaAtoi(t *testing.T) {
    22  	s := newStd()
    23  	ic := &interop.Context{VM: vm.New(), DAO: &dao.Simple{}}
    24  	var actual stackitem.Item
    25  
    26  	t.Run("itoa-atoi", func(t *testing.T) {
    27  		var testCases = []struct {
    28  			num    *big.Int
    29  			base   *big.Int
    30  			result string
    31  		}{
    32  			{big.NewInt(0), big.NewInt(10), "0"},
    33  			{big.NewInt(0), big.NewInt(16), "0"},
    34  			{big.NewInt(1), big.NewInt(10), "1"},
    35  			{big.NewInt(-1), big.NewInt(10), "-1"},
    36  			{big.NewInt(1), big.NewInt(16), "1"},
    37  			{big.NewInt(7), big.NewInt(16), "7"},
    38  			{big.NewInt(8), big.NewInt(16), "08"},
    39  			{big.NewInt(65535), big.NewInt(16), "0ffff"},
    40  			{big.NewInt(15), big.NewInt(16), "0f"},
    41  			{big.NewInt(-1), big.NewInt(16), "f"},
    42  		}
    43  
    44  		for _, tc := range testCases {
    45  			require.NotPanics(t, func() {
    46  				actual = s.itoa(ic, []stackitem.Item{stackitem.Make(tc.num), stackitem.Make(tc.base)})
    47  			})
    48  			require.Equal(t, stackitem.Make(tc.result), actual)
    49  
    50  			require.NotPanics(t, func() {
    51  				actual = s.atoi(ic, []stackitem.Item{stackitem.Make(tc.result), stackitem.Make(tc.base)})
    52  			})
    53  			require.Equal(t, stackitem.Make(tc.num), actual)
    54  
    55  			if tc.base.Int64() == 10 {
    56  				require.NotPanics(t, func() {
    57  					actual = s.itoa10(ic, []stackitem.Item{stackitem.Make(tc.num)})
    58  				})
    59  				require.Equal(t, stackitem.Make(tc.result), actual)
    60  
    61  				require.NotPanics(t, func() {
    62  					actual = s.atoi10(ic, []stackitem.Item{stackitem.Make(tc.result)})
    63  				})
    64  				require.Equal(t, stackitem.Make(tc.num), actual)
    65  				if tc.result[0] != '-' {
    66  					require.NotPanics(t, func() {
    67  						actual = s.atoi10(ic, []stackitem.Item{stackitem.Make("+" + tc.result)})
    68  					})
    69  					require.Equal(t, stackitem.Make(tc.num), actual)
    70  				}
    71  			}
    72  		}
    73  
    74  		t.Run("-1", func(t *testing.T) {
    75  			for _, str := range []string{"FF", "FFF", "FFFF"} {
    76  				require.NotPanics(t, func() {
    77  					actual = s.atoi(ic, []stackitem.Item{stackitem.Make(str), stackitem.Make(16)})
    78  				})
    79  
    80  				require.Equal(t, stackitem.Make(-1), actual)
    81  			}
    82  		})
    83  	})
    84  
    85  	t.Run("itoa error", func(t *testing.T) {
    86  		var testCases = []struct {
    87  			num  *big.Int
    88  			base *big.Int
    89  			err  error
    90  		}{
    91  			{big.NewInt(1), big.NewInt(13), ErrInvalidBase},
    92  			{big.NewInt(-1), new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(10)), ErrInvalidBase},
    93  		}
    94  
    95  		for _, tc := range testCases {
    96  			require.PanicsWithError(t, tc.err.Error(), func() {
    97  				_ = s.itoa(ic, []stackitem.Item{stackitem.Make(tc.num), stackitem.Make(tc.base)})
    98  			})
    99  		}
   100  	})
   101  
   102  	t.Run("atoi error", func(t *testing.T) {
   103  		var testCases = []struct {
   104  			num  string
   105  			base *big.Int
   106  			err  error
   107  		}{
   108  			{"1", big.NewInt(13), ErrInvalidBase},
   109  			{"1", new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(16)), ErrInvalidBase},
   110  			{"1_000", big.NewInt(10), ErrInvalidFormat},
   111  			{" 1", big.NewInt(10), ErrInvalidFormat},
   112  			{"1 ", big.NewInt(10), ErrInvalidFormat},
   113  			{"FE", big.NewInt(10), ErrInvalidFormat},
   114  			{"XD", big.NewInt(16), ErrInvalidFormat},
   115  			{strings.Repeat("0", stdMaxInputLength+1), big.NewInt(10), ErrTooBigInput},
   116  		}
   117  
   118  		for _, tc := range testCases {
   119  			require.PanicsWithError(t, tc.err.Error(), func() {
   120  				_ = s.atoi(ic, []stackitem.Item{stackitem.Make(tc.num), stackitem.Make(tc.base)})
   121  			})
   122  		}
   123  	})
   124  }
   125  
   126  func TestStdLibJSON(t *testing.T) {
   127  	s := newStd()
   128  	ic := &interop.Context{VM: vm.New()}
   129  	var actual stackitem.Item
   130  
   131  	t.Run("JSONSerialize", func(t *testing.T) {
   132  		t.Run("Good", func(t *testing.T) {
   133  			require.NotPanics(t, func() {
   134  				actual = s.jsonSerialize(ic, []stackitem.Item{stackitem.Make(42)})
   135  			})
   136  
   137  			require.Equal(t, stackitem.Make([]byte("42")), actual)
   138  		})
   139  
   140  		t.Run("Bad", func(t *testing.T) {
   141  			arr := stackitem.NewArray([]stackitem.Item{
   142  				stackitem.NewByteArray(make([]byte, stackitem.MaxSize/2)),
   143  				stackitem.NewByteArray(make([]byte, stackitem.MaxSize/2)),
   144  			})
   145  			require.Panics(t, func() {
   146  				_ = s.jsonSerialize(ic, []stackitem.Item{arr})
   147  			})
   148  		})
   149  	})
   150  
   151  	t.Run("JSONDeserialize", func(t *testing.T) {
   152  		t.Run("Good", func(t *testing.T) {
   153  			require.NotPanics(t, func() {
   154  				actual = s.jsonDeserialize(ic, []stackitem.Item{stackitem.Make("42")})
   155  			})
   156  
   157  			require.Equal(t, stackitem.Make(42), actual)
   158  		})
   159  		t.Run("Bad", func(t *testing.T) {
   160  			require.Panics(t, func() {
   161  				_ = s.jsonDeserialize(ic, []stackitem.Item{stackitem.Make("{]")})
   162  			})
   163  			require.Panics(t, func() {
   164  				_ = s.jsonDeserialize(ic, []stackitem.Item{stackitem.NewInterop(nil)})
   165  			})
   166  		})
   167  	})
   168  }
   169  
   170  func TestStdLibEncodeDecode(t *testing.T) {
   171  	s := newStd()
   172  	original := []byte("my pretty string")
   173  	encoded64 := base64.StdEncoding.EncodeToString(original)
   174  	encoded58 := base58.Encode(original)
   175  	encoded58Check := base58neogo.CheckEncode(original)
   176  	ic := &interop.Context{VM: vm.New()}
   177  	var actual stackitem.Item
   178  
   179  	bigInputArgs := []stackitem.Item{stackitem.Make(strings.Repeat("6", stdMaxInputLength+1))}
   180  
   181  	t.Run("Encode64", func(t *testing.T) {
   182  		require.NotPanics(t, func() {
   183  			actual = s.base64Encode(ic, []stackitem.Item{stackitem.Make(original)})
   184  		})
   185  		require.Equal(t, stackitem.Make(encoded64), actual)
   186  	})
   187  	t.Run("Encode64/error", func(t *testing.T) {
   188  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   189  			func() { s.base64Encode(ic, bigInputArgs) })
   190  	})
   191  	t.Run("Encode58", func(t *testing.T) {
   192  		require.NotPanics(t, func() {
   193  			actual = s.base58Encode(ic, []stackitem.Item{stackitem.Make(original)})
   194  		})
   195  		require.Equal(t, stackitem.Make(encoded58), actual)
   196  	})
   197  	t.Run("Encode58/error", func(t *testing.T) {
   198  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   199  			func() { s.base58Encode(ic, bigInputArgs) })
   200  	})
   201  	t.Run("CheckEncode58", func(t *testing.T) {
   202  		require.NotPanics(t, func() {
   203  			actual = s.base58CheckEncode(ic, []stackitem.Item{stackitem.Make(original)})
   204  		})
   205  		require.Equal(t, stackitem.Make(encoded58Check), actual)
   206  	})
   207  	t.Run("CheckEncode58/error", func(t *testing.T) {
   208  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   209  			func() { s.base58CheckEncode(ic, bigInputArgs) })
   210  	})
   211  	t.Run("Decode64/positive", func(t *testing.T) {
   212  		require.NotPanics(t, func() {
   213  			actual = s.base64Decode(ic, []stackitem.Item{stackitem.Make(encoded64)})
   214  		})
   215  		require.Equal(t, stackitem.Make(original), actual)
   216  	})
   217  	t.Run("Decode64/error", func(t *testing.T) {
   218  		require.Panics(t, func() {
   219  			_ = s.base64Decode(ic, []stackitem.Item{stackitem.Make(encoded64 + "%")})
   220  		})
   221  		require.Panics(t, func() {
   222  			_ = s.base64Decode(ic, []stackitem.Item{stackitem.NewInterop(nil)})
   223  		})
   224  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   225  			func() { s.base64Decode(ic, bigInputArgs) })
   226  	})
   227  	t.Run("Decode58/positive", func(t *testing.T) {
   228  		require.NotPanics(t, func() {
   229  			actual = s.base58Decode(ic, []stackitem.Item{stackitem.Make(encoded58)})
   230  		})
   231  		require.Equal(t, stackitem.Make(original), actual)
   232  	})
   233  	t.Run("Decode58/error", func(t *testing.T) {
   234  		require.Panics(t, func() {
   235  			_ = s.base58Decode(ic, []stackitem.Item{stackitem.Make(encoded58 + "%")})
   236  		})
   237  		require.Panics(t, func() {
   238  			_ = s.base58Decode(ic, []stackitem.Item{stackitem.NewInterop(nil)})
   239  		})
   240  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   241  			func() { s.base58Decode(ic, bigInputArgs) })
   242  	})
   243  	t.Run("CheckDecode58/positive", func(t *testing.T) {
   244  		require.NotPanics(t, func() {
   245  			actual = s.base58CheckDecode(ic, []stackitem.Item{stackitem.Make(encoded58Check)})
   246  		})
   247  		require.Equal(t, stackitem.Make(original), actual)
   248  	})
   249  	t.Run("CheckDecode58/error", func(t *testing.T) {
   250  		require.Panics(t, func() {
   251  			_ = s.base58CheckDecode(ic, []stackitem.Item{stackitem.Make(encoded58 + "%")})
   252  		})
   253  		require.Panics(t, func() {
   254  			_ = s.base58CheckDecode(ic, []stackitem.Item{stackitem.NewInterop(nil)})
   255  		})
   256  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   257  			func() { s.base58CheckDecode(ic, bigInputArgs) })
   258  	})
   259  }
   260  
   261  func TestStdLibSerialize(t *testing.T) {
   262  	s := newStd()
   263  	ic := &interop.Context{VM: vm.New(), DAO: &dao.Simple{}}
   264  
   265  	t.Run("recursive", func(t *testing.T) {
   266  		arr := stackitem.NewArray(nil)
   267  		arr.Append(arr)
   268  		require.Panics(t, func() {
   269  			_ = s.serialize(ic, []stackitem.Item{arr})
   270  		})
   271  	})
   272  	t.Run("big item", func(t *testing.T) {
   273  		require.Panics(t, func() {
   274  			_ = s.serialize(ic, []stackitem.Item{stackitem.NewByteArray(make([]byte, stackitem.MaxSize))})
   275  		})
   276  	})
   277  	t.Run("good", func(t *testing.T) {
   278  		var (
   279  			actualSerialized   stackitem.Item
   280  			actualDeserialized stackitem.Item
   281  		)
   282  		require.NotPanics(t, func() {
   283  			actualSerialized = s.serialize(ic, []stackitem.Item{stackitem.Make(42)})
   284  		})
   285  
   286  		encoded, err := stackitem.Serialize(stackitem.Make(42))
   287  		require.NoError(t, err)
   288  		require.Equal(t, stackitem.Make(encoded), actualSerialized)
   289  
   290  		require.NotPanics(t, func() {
   291  			actualDeserialized = s.deserialize(ic, []stackitem.Item{actualSerialized})
   292  		})
   293  		require.Equal(t, stackitem.Make(42), actualDeserialized)
   294  
   295  		t.Run("bad", func(t *testing.T) {
   296  			encoded[0] ^= 0xFF
   297  			require.Panics(t, func() {
   298  				_ = s.deserialize(ic, []stackitem.Item{stackitem.Make(encoded)})
   299  			})
   300  		})
   301  	})
   302  }
   303  
   304  func TestStdLibSerializeDeserialize(t *testing.T) {
   305  	s := newStd()
   306  	ic := &interop.Context{VM: vm.New(), DAO: &dao.Simple{}}
   307  	var actual stackitem.Item
   308  
   309  	checkSerializeDeserialize := func(t *testing.T, value any, expected stackitem.Item) {
   310  		require.NotPanics(t, func() {
   311  			actual = s.serialize(ic, []stackitem.Item{stackitem.Make(value)})
   312  		})
   313  		require.NotPanics(t, func() {
   314  			actual = s.deserialize(ic, []stackitem.Item{actual})
   315  		})
   316  		require.Equal(t, expected, actual)
   317  	}
   318  
   319  	t.Run("Bool", func(t *testing.T) {
   320  		checkSerializeDeserialize(t, true, stackitem.NewBool(true))
   321  	})
   322  	t.Run("ByteArray", func(t *testing.T) {
   323  		checkSerializeDeserialize(t, []byte{1, 2, 3}, stackitem.NewByteArray([]byte{1, 2, 3}))
   324  	})
   325  	t.Run("Integer", func(t *testing.T) {
   326  		checkSerializeDeserialize(t, 48, stackitem.NewBigInteger(big.NewInt(48)))
   327  	})
   328  	t.Run("Array", func(t *testing.T) {
   329  		arr := stackitem.NewArray([]stackitem.Item{
   330  			stackitem.Make(true),
   331  			stackitem.Make(123),
   332  			stackitem.NewMap()})
   333  		checkSerializeDeserialize(t, arr, arr)
   334  	})
   335  	t.Run("Struct", func(t *testing.T) {
   336  		st := stackitem.NewStruct([]stackitem.Item{
   337  			stackitem.Make(true),
   338  			stackitem.Make(123),
   339  			stackitem.NewMap(),
   340  		})
   341  		checkSerializeDeserialize(t, st, st)
   342  	})
   343  	t.Run("Map", func(t *testing.T) {
   344  		item := stackitem.NewMap()
   345  		item.Add(stackitem.Make(true), stackitem.Make([]byte{1, 2, 3}))
   346  		item.Add(stackitem.Make([]byte{0}), stackitem.Make(false))
   347  		checkSerializeDeserialize(t, item, item)
   348  	})
   349  	t.Run("Serialize MapCompat", func(t *testing.T) {
   350  		resHex := "480128036b6579280576616c7565"
   351  		res, err := hex.DecodeString(resHex)
   352  		require.NoError(t, err)
   353  
   354  		item := stackitem.NewMap()
   355  		item.Add(stackitem.Make([]byte("key")), stackitem.Make([]byte("value")))
   356  		require.NotPanics(t, func() {
   357  			actual = s.serialize(ic, []stackitem.Item{stackitem.Make(item)})
   358  		})
   359  		bytes, err := actual.TryBytes()
   360  		require.NoError(t, err)
   361  		assert.Equal(t, res, bytes)
   362  	})
   363  	t.Run("Serialize Interop", func(t *testing.T) {
   364  		require.Panics(t, func() {
   365  			actual = s.serialize(ic, []stackitem.Item{stackitem.NewInterop("kek")})
   366  		})
   367  	})
   368  	t.Run("Serialize Array bad", func(t *testing.T) {
   369  		item := stackitem.NewArray([]stackitem.Item{stackitem.NewBool(true), stackitem.NewBool(true)})
   370  		item.Value().([]stackitem.Item)[1] = item
   371  		require.Panics(t, func() {
   372  			actual = s.serialize(ic, []stackitem.Item{item})
   373  		})
   374  	})
   375  	t.Run("Deserialize unknown", func(t *testing.T) {
   376  		data, err := stackitem.Serialize(stackitem.NewBigInteger(big.NewInt(123)))
   377  		require.NoError(t, err)
   378  
   379  		data[0] = 0xFF
   380  		require.Panics(t, func() {
   381  			actual = s.deserialize(ic, []stackitem.Item{stackitem.Make(data)})
   382  		})
   383  	})
   384  	t.Run("Deserialize not a byte array", func(t *testing.T) {
   385  		require.Panics(t, func() {
   386  			actual = s.deserialize(ic, []stackitem.Item{stackitem.NewInterop(nil)})
   387  		})
   388  	})
   389  }
   390  
   391  func TestMemoryCompare(t *testing.T) {
   392  	s := newStd()
   393  	ic := &interop.Context{VM: vm.New(), DAO: &dao.Simple{}}
   394  
   395  	check := func(t *testing.T, result int64, s1, s2 string) {
   396  		actual := s.memoryCompare(ic, []stackitem.Item{stackitem.Make(s1), stackitem.Make(s2)})
   397  		require.Equal(t, big.NewInt(result), actual.Value())
   398  	}
   399  
   400  	check(t, -1, "a", "ab")
   401  	check(t, 1, "ab", "a")
   402  	check(t, 0, "ab", "ab")
   403  	check(t, -1, "", "a")
   404  	check(t, 0, "", "")
   405  
   406  	t.Run("C# compatibility", func(t *testing.T) {
   407  		// These tests are taken from C# node.
   408  		check(t, -1, "abc", "c")
   409  		check(t, -1, "abc", "d")
   410  		check(t, 0, "abc", "abc")
   411  		check(t, -1, "abc", "abcd")
   412  	})
   413  
   414  	t.Run("big arguments", func(t *testing.T) {
   415  		s1 := stackitem.Make(strings.Repeat("x", stdMaxInputLength+1))
   416  		s2 := stackitem.Make("xxx")
   417  
   418  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   419  			func() { s.memoryCompare(ic, []stackitem.Item{s1, s2}) })
   420  
   421  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   422  			func() { s.memoryCompare(ic, []stackitem.Item{s2, s1}) })
   423  	})
   424  }
   425  
   426  func TestMemorySearch(t *testing.T) {
   427  	s := newStd()
   428  	ic := &interop.Context{VM: vm.New()}
   429  
   430  	check := func(t *testing.T, result int64, args ...any) {
   431  		items := make([]stackitem.Item, len(args))
   432  		for i := range args {
   433  			items[i] = stackitem.Make(args[i])
   434  		}
   435  
   436  		var actual stackitem.Item
   437  		switch len(items) {
   438  		case 2:
   439  			actual = s.memorySearch2(ic, items)
   440  		case 3:
   441  			actual = s.memorySearch3(ic, items)
   442  		case 4:
   443  			actual = s.memorySearch4(ic, items)
   444  		default:
   445  			panic("invalid args length")
   446  		}
   447  		require.Equal(t, big.NewInt(result), actual.Value())
   448  	}
   449  
   450  	t.Run("C# compatibility", func(t *testing.T) {
   451  		// These tests are taken from C# node.
   452  		check(t, 2, "abc", "c", 0)
   453  		check(t, 2, "abc", "c", 1)
   454  		check(t, 2, "abc", "c", 2)
   455  		check(t, -1, "abc", "c", 3)
   456  		check(t, -1, "abc", "d", 0)
   457  
   458  		check(t, 2, "abc", "c", 0, false)
   459  		check(t, 2, "abc", "c", 1, false)
   460  		check(t, 2, "abc", "c", 2, false)
   461  		check(t, -1, "abc", "c", 3, false)
   462  		check(t, -1, "abc", "d", 0, false)
   463  
   464  		check(t, -1, "abc", "c", 0, true)
   465  		check(t, -1, "abc", "c", 1, true)
   466  		check(t, -1, "abc", "c", 2, true)
   467  		check(t, 2, "abc", "c", 3, true)
   468  		check(t, -1, "abc", "d", 0, true)
   469  	})
   470  
   471  	t.Run("boundary indices", func(t *testing.T) {
   472  		arg := stackitem.Make("aaa")
   473  		require.Panics(t, func() {
   474  			s.memorySearch3(ic, []stackitem.Item{arg, arg, stackitem.Make(-1)})
   475  		})
   476  		require.Panics(t, func() {
   477  			s.memorySearch3(ic, []stackitem.Item{arg, arg, stackitem.Make(4)})
   478  		})
   479  		t.Run("still in capacity", func(t *testing.T) {
   480  			require.Panics(t, func() {
   481  				arr := stackitem.NewByteArray(make([]byte, 5, 10))
   482  				s.memorySearch3(ic, []stackitem.Item{arr, arg, stackitem.Make(7)})
   483  			})
   484  			require.Panics(t, func() {
   485  				arr := stackitem.NewByteArray(make([]byte, 5, 10))
   486  				s.memorySearch4(ic, []stackitem.Item{arr, arg,
   487  					stackitem.Make(7), stackitem.Make(true)})
   488  			})
   489  		})
   490  	})
   491  
   492  	t.Run("big arguments", func(t *testing.T) {
   493  		s1 := stackitem.Make(strings.Repeat("x", stdMaxInputLength+1))
   494  		s2 := stackitem.Make("xxx")
   495  		start := stackitem.Make(1)
   496  		b := stackitem.Make(true)
   497  
   498  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   499  			func() { s.memorySearch2(ic, []stackitem.Item{s1, s2}) })
   500  
   501  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   502  			func() { s.memorySearch2(ic, []stackitem.Item{s2, s1}) })
   503  
   504  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   505  			func() { s.memorySearch3(ic, []stackitem.Item{s1, s2, start}) })
   506  
   507  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   508  			func() { s.memorySearch3(ic, []stackitem.Item{s2, s1, start}) })
   509  
   510  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   511  			func() { s.memorySearch4(ic, []stackitem.Item{s1, s2, start, b}) })
   512  
   513  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   514  			func() { s.memorySearch4(ic, []stackitem.Item{s2, s1, start, b}) })
   515  	})
   516  }
   517  
   518  func TestStringSplit(t *testing.T) {
   519  	s := newStd()
   520  	ic := &interop.Context{VM: vm.New()}
   521  
   522  	check := func(t *testing.T, result []string, str, sep string, remove any) {
   523  		args := []stackitem.Item{stackitem.Make(str), stackitem.Make(sep)}
   524  		var actual stackitem.Item
   525  		if remove == nil {
   526  			actual = s.stringSplit2(ic, args)
   527  		} else {
   528  			args = append(args, stackitem.NewBool(remove.(bool)))
   529  			actual = s.stringSplit3(ic, args)
   530  		}
   531  
   532  		arr, ok := actual.Value().([]stackitem.Item)
   533  		require.True(t, ok)
   534  		require.Equal(t, len(result), len(arr))
   535  		for i := range result {
   536  			require.Equal(t, stackitem.Make(result[i]), arr[i])
   537  		}
   538  	}
   539  
   540  	check(t, []string{"a", "b", "c"}, "abc", "", nil)
   541  	check(t, []string{"a", "b", "c"}, "abc", "", true)
   542  	check(t, []string{"a", "c", "", "", "d"}, "abcbbbd", "b", nil)
   543  	check(t, []string{"a", "c", "", "", "d"}, "abcbbbd", "b", false)
   544  	check(t, []string{"a", "c", "d"}, "abcbbbd", "b", true)
   545  	check(t, []string{""}, "", "abc", nil)
   546  	check(t, []string{}, "", "abc", true)
   547  
   548  	t.Run("C# compatibility", func(t *testing.T) {
   549  		// These tests are taken from C# node.
   550  		check(t, []string{"a", "b"}, "a,b", ",", nil)
   551  	})
   552  
   553  	t.Run("big arguments", func(t *testing.T) {
   554  		s1 := stackitem.Make(strings.Repeat("x", stdMaxInputLength+1))
   555  		s2 := stackitem.Make("xxx")
   556  
   557  		require.PanicsWithError(t, ErrTooBigInput.Error(),
   558  			func() { s.stringSplit2(ic, []stackitem.Item{s1, s2}) })
   559  	})
   560  }
   561  
   562  func TestStd_StrLen(t *testing.T) {
   563  	s := newStd()
   564  	ic := &interop.Context{VM: vm.New()}
   565  
   566  	check := func(t *testing.T, expected int64, str string) {
   567  		args := []stackitem.Item{stackitem.Make(str)}
   568  		actual := s.strLen(ic, args)
   569  		l, ok := actual.Value().(*big.Int)
   570  		require.True(t, ok)
   571  		require.Equal(t, expected, l.Int64())
   572  	}
   573  
   574  	// These tests are taken from https://github.com/neo-project/neo/pull/2854/files.
   575  	check(t, 1, "🦆")
   576  	check(t, 1, "ã")
   577  	check(t, 1, "a")
   578  
   579  	bad := string(rune(0xff))
   580  	check(t, 1, bad)
   581  	check(t, 3, bad+"ab")
   582  }