github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/rpcclient/nep11/base_test.go (about)

     1  package nep11
     2  
     3  import (
     4  	"errors"
     5  	"math/big"
     6  	"testing"
     7  
     8  	"github.com/google/uuid"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    10  	"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
    11  	"github.com/nspcc-dev/neo-go/pkg/util"
    12  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  type testAct struct {
    17  	err error
    18  	res *result.Invoke
    19  	tx  *transaction.Transaction
    20  	txh util.Uint256
    21  	vub uint32
    22  }
    23  
    24  func (t *testAct) Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) {
    25  	return t.res, t.err
    26  }
    27  func (t *testAct) MakeRun(script []byte) (*transaction.Transaction, error) {
    28  	return t.tx, t.err
    29  }
    30  func (t *testAct) MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error) {
    31  	return t.tx, t.err
    32  }
    33  func (t *testAct) SendRun(script []byte) (util.Uint256, uint32, error) {
    34  	return t.txh, t.vub, t.err
    35  }
    36  func (t *testAct) CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...any) (*result.Invoke, error) {
    37  	return t.res, t.err
    38  }
    39  func (t *testAct) TerminateSession(sessionID uuid.UUID) error {
    40  	return t.err
    41  }
    42  func (t *testAct) TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error) {
    43  	return t.res.Stack, t.err
    44  }
    45  
    46  func TestReaderBalanceOf(t *testing.T) {
    47  	ta := new(testAct)
    48  	tr := NewBaseReader(ta, util.Uint160{1, 2, 3})
    49  
    50  	ta.err = errors.New("")
    51  	_, err := tr.BalanceOf(util.Uint160{3, 2, 1})
    52  	require.Error(t, err)
    53  
    54  	ta.err = nil
    55  	ta.res = &result.Invoke{
    56  		State: "HALT",
    57  		Stack: []stackitem.Item{
    58  			stackitem.Make(100500),
    59  		},
    60  	}
    61  	bal, err := tr.BalanceOf(util.Uint160{3, 2, 1})
    62  	require.NoError(t, err)
    63  	require.Equal(t, big.NewInt(100500), bal)
    64  
    65  	ta.res = &result.Invoke{
    66  		State: "HALT",
    67  		Stack: []stackitem.Item{
    68  			stackitem.Make([]stackitem.Item{}),
    69  		},
    70  	}
    71  	_, err = tr.BalanceOf(util.Uint160{3, 2, 1})
    72  	require.Error(t, err)
    73  }
    74  
    75  func TestReaderProperties(t *testing.T) {
    76  	ta := new(testAct)
    77  	tr := NewBaseReader(ta, util.Uint160{1, 2, 3})
    78  
    79  	ta.err = errors.New("")
    80  	_, err := tr.Properties([]byte{3, 2, 1})
    81  	require.Error(t, err)
    82  
    83  	ta.res = &result.Invoke{
    84  		State: "HALT",
    85  		Stack: []stackitem.Item{
    86  			stackitem.Make([]stackitem.Item{}),
    87  		},
    88  	}
    89  	_, err = tr.Properties([]byte{3, 2, 1})
    90  	require.Error(t, err)
    91  
    92  	ta.err = nil
    93  	ta.res = &result.Invoke{
    94  		State: "HALT",
    95  		Stack: []stackitem.Item{
    96  			stackitem.NewMap(),
    97  		},
    98  	}
    99  	m, err := tr.Properties([]byte{3, 2, 1})
   100  	require.NoError(t, err)
   101  	require.Equal(t, 0, m.Len())
   102  }
   103  
   104  func TestReaderTokensOfExpanded(t *testing.T) {
   105  	ta := new(testAct)
   106  	tr := NewBaseReader(ta, util.Uint160{1, 2, 3})
   107  
   108  	for name, fun := range map[string]func(int) ([][]byte, error){
   109  		"Tokens": tr.TokensExpanded,
   110  		"TokensOf": func(n int) ([][]byte, error) {
   111  			return tr.TokensOfExpanded(util.Uint160{1, 2, 3}, n)
   112  		},
   113  	} {
   114  		t.Run(name, func(t *testing.T) {
   115  			ta.err = errors.New("")
   116  			_, err := fun(1)
   117  			require.Error(t, err)
   118  
   119  			ta.err = nil
   120  			ta.res = &result.Invoke{
   121  				State: "HALT",
   122  				Stack: []stackitem.Item{
   123  					stackitem.Make(100500),
   124  				},
   125  			}
   126  			_, err = fun(1)
   127  			require.Error(t, err)
   128  
   129  			ta.res = &result.Invoke{
   130  				State: "HALT",
   131  				Stack: []stackitem.Item{
   132  					stackitem.Make([]stackitem.Item{stackitem.Make("one")}),
   133  				},
   134  			}
   135  			toks, err := fun(1)
   136  			require.NoError(t, err)
   137  			require.Equal(t, [][]byte{[]byte("one")}, toks)
   138  		})
   139  	}
   140  }
   141  
   142  func TestReaderTokensOf(t *testing.T) {
   143  	ta := new(testAct)
   144  	tr := NewBaseReader(ta, util.Uint160{1, 2, 3})
   145  
   146  	for name, fun := range map[string]func() (*TokenIterator, error){
   147  		"Tokens": tr.Tokens,
   148  		"TokensOf": func() (*TokenIterator, error) {
   149  			return tr.TokensOf(util.Uint160{1, 2, 3})
   150  		},
   151  	} {
   152  		t.Run(name, func(t *testing.T) {
   153  			ta.err = errors.New("")
   154  			_, err := fun()
   155  			require.Error(t, err)
   156  
   157  			iid := uuid.New()
   158  			ta.err = nil
   159  			ta.res = &result.Invoke{
   160  				Session: uuid.New(),
   161  				State:   "HALT",
   162  				Stack: []stackitem.Item{
   163  					stackitem.NewInterop(result.Iterator{
   164  						ID: &iid,
   165  					}),
   166  				},
   167  			}
   168  			iter, err := fun()
   169  			require.NoError(t, err)
   170  
   171  			ta.res = &result.Invoke{
   172  				Stack: []stackitem.Item{
   173  					stackitem.Make("one"),
   174  					stackitem.Make([]stackitem.Item{}),
   175  				},
   176  			}
   177  			_, err = iter.Next(10)
   178  			require.Error(t, err)
   179  
   180  			ta.res = &result.Invoke{
   181  				Stack: []stackitem.Item{
   182  					stackitem.Make("one"),
   183  					stackitem.Make("two"),
   184  				},
   185  			}
   186  			vals, err := iter.Next(10)
   187  			require.NoError(t, err)
   188  			require.Equal(t, [][]byte{[]byte("one"), []byte("two")}, vals)
   189  
   190  			ta.err = errors.New("")
   191  			_, err = iter.Next(1)
   192  			require.Error(t, err)
   193  
   194  			err = iter.Terminate()
   195  			require.Error(t, err)
   196  
   197  			// Value-based iterator.
   198  			ta.err = nil
   199  			ta.res = &result.Invoke{
   200  				State: "HALT",
   201  				Stack: []stackitem.Item{
   202  					stackitem.NewInterop(result.Iterator{
   203  						Values: []stackitem.Item{
   204  							stackitem.Make("one"),
   205  							stackitem.Make("two"),
   206  						},
   207  					}),
   208  				},
   209  			}
   210  			iter, err = fun()
   211  			require.NoError(t, err)
   212  
   213  			ta.err = errors.New("")
   214  			err = iter.Terminate()
   215  			require.NoError(t, err)
   216  		})
   217  	}
   218  }
   219  
   220  type tData struct {
   221  	someInt    int
   222  	someString string
   223  }
   224  
   225  func (d *tData) ToStackItem() (stackitem.Item, error) {
   226  	return stackitem.NewStruct([]stackitem.Item{
   227  		stackitem.Make(d.someInt),
   228  		stackitem.Make(d.someString),
   229  	}), nil
   230  }
   231  
   232  func (d *tData) FromStackItem(si stackitem.Item) error {
   233  	panic("TODO")
   234  }
   235  
   236  func TestTokenTransfer(t *testing.T) {
   237  	ta := new(testAct)
   238  	tok := NewBase(ta, util.Uint160{1, 2, 3})
   239  
   240  	ta.err = errors.New("")
   241  	_, _, err := tok.Transfer(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, nil)
   242  	require.Error(t, err)
   243  
   244  	ta.err = nil
   245  	ta.txh = util.Uint256{1, 2, 3}
   246  	ta.vub = 42
   247  	h, vub, err := tok.Transfer(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, nil)
   248  	require.NoError(t, err)
   249  	require.Equal(t, ta.txh, h)
   250  	require.Equal(t, ta.vub, vub)
   251  
   252  	ta.err = nil
   253  	ta.txh = util.Uint256{1, 2, 3}
   254  	ta.vub = 42
   255  	h, vub, err = tok.Transfer(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, &tData{
   256  		someInt:    5,
   257  		someString: "ur",
   258  	})
   259  	require.NoError(t, err)
   260  	require.Equal(t, ta.txh, h)
   261  	require.Equal(t, ta.vub, vub)
   262  
   263  	_, _, err = tok.Transfer(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, stackitem.NewPointer(123, []byte{123}))
   264  	require.Error(t, err)
   265  }
   266  
   267  func TestTokenTransferTransaction(t *testing.T) {
   268  	ta := new(testAct)
   269  	tok := NewBase(ta, util.Uint160{1, 2, 3})
   270  
   271  	for _, fun := range []func(to util.Uint160, token []byte, data any) (*transaction.Transaction, error){
   272  		tok.TransferTransaction,
   273  		tok.TransferUnsigned,
   274  	} {
   275  		ta.err = errors.New("")
   276  		_, err := fun(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, nil)
   277  		require.Error(t, err)
   278  
   279  		ta.err = nil
   280  		ta.tx = &transaction.Transaction{Nonce: 100500, ValidUntilBlock: 42}
   281  		tx, err := fun(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, nil)
   282  		require.NoError(t, err)
   283  		require.Equal(t, ta.tx, tx)
   284  
   285  		ta.err = nil
   286  		ta.tx = &transaction.Transaction{Nonce: 100500, ValidUntilBlock: 42}
   287  		tx, err = fun(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, &tData{
   288  			someInt:    5,
   289  			someString: "ur",
   290  		})
   291  		require.NoError(t, err)
   292  		require.Equal(t, ta.tx, tx)
   293  
   294  		_, err = fun(util.Uint160{3, 2, 1}, []byte{3, 2, 1}, stackitem.NewInterop(nil))
   295  		require.Error(t, err)
   296  	}
   297  }
   298  
   299  func TestUnwrapKnownProperties(t *testing.T) {
   300  	_, err := UnwrapKnownProperties(stackitem.NewMap(), errors.New(""))
   301  	require.Error(t, err)
   302  
   303  	m, err := UnwrapKnownProperties(stackitem.NewMap(), nil)
   304  	require.NoError(t, err)
   305  	require.NotNil(t, m)
   306  	require.Equal(t, 0, len(m))
   307  
   308  	m, err = UnwrapKnownProperties(stackitem.NewMapWithValue([]stackitem.MapElement{
   309  		{Key: stackitem.Make("some"), Value: stackitem.Make("thing")},
   310  	}), nil)
   311  	require.NoError(t, err)
   312  	require.NotNil(t, m)
   313  	require.Equal(t, 0, len(m))
   314  
   315  	m, err = UnwrapKnownProperties(stackitem.NewMapWithValue([]stackitem.MapElement{
   316  		{Key: stackitem.Make([]stackitem.Item{}), Value: stackitem.Make("thing")},
   317  	}), nil)
   318  	require.NoError(t, err)
   319  	require.NotNil(t, m)
   320  	require.Equal(t, 0, len(m))
   321  
   322  	_, err = UnwrapKnownProperties(stackitem.NewMapWithValue([]stackitem.MapElement{
   323  		{Key: stackitem.Make("name"), Value: stackitem.Make([]stackitem.Item{})},
   324  	}), nil)
   325  	require.Error(t, err)
   326  
   327  	_, err = UnwrapKnownProperties(stackitem.NewMapWithValue([]stackitem.MapElement{
   328  		{Key: stackitem.Make("name"), Value: stackitem.Make([]byte{0xff})},
   329  	}), nil)
   330  	require.Error(t, err)
   331  
   332  	m, err = UnwrapKnownProperties(stackitem.NewMapWithValue([]stackitem.MapElement{
   333  		{Key: stackitem.Make("name"), Value: stackitem.Make("thing")},
   334  		{Key: stackitem.Make("description"), Value: stackitem.Make("good NFT")},
   335  	}), nil)
   336  	require.NoError(t, err)
   337  	require.NotNil(t, m)
   338  	require.Equal(t, 2, len(m))
   339  	require.Equal(t, "thing", m["name"])
   340  	require.Equal(t, "good NFT", m["description"])
   341  }