github.com/Finschia/finschia-sdk@v0.48.1/x/collection/keeper/keeper_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
     9  
    10  	"github.com/Finschia/finschia-sdk/crypto/keys/secp256k1"
    11  	"github.com/Finschia/finschia-sdk/simapp"
    12  	sdk "github.com/Finschia/finschia-sdk/types"
    13  	"github.com/Finschia/finschia-sdk/x/collection"
    14  	"github.com/Finschia/finschia-sdk/x/collection/keeper"
    15  )
    16  
    17  type KeeperTestSuite struct {
    18  	suite.Suite
    19  
    20  	ctx         sdk.Context
    21  	goCtx       context.Context
    22  	keeper      keeper.Keeper
    23  	queryServer collection.QueryServer
    24  	msgServer   collection.MsgServer
    25  
    26  	vendor   sdk.AccAddress
    27  	operator sdk.AccAddress
    28  	customer sdk.AccAddress
    29  	stranger sdk.AccAddress
    30  
    31  	contractID string
    32  	ftClassID  string
    33  	nftClassID string
    34  
    35  	balance sdk.Int
    36  
    37  	depthLimit int
    38  
    39  	numNFTs  int
    40  	numRoots int
    41  }
    42  
    43  func (s *KeeperTestSuite) createRandomAccounts(accNum int) []sdk.AccAddress {
    44  	seenAddresses := make(map[string]bool, accNum)
    45  	addresses := make([]sdk.AccAddress, accNum)
    46  	for i := range addresses {
    47  		var address sdk.AccAddress
    48  		for {
    49  			pk := secp256k1.GenPrivKey().PubKey()
    50  			address = sdk.AccAddress(pk.Address())
    51  			if !seenAddresses[address.String()] {
    52  				seenAddresses[address.String()] = true
    53  				break
    54  			}
    55  		}
    56  		addresses[i] = address
    57  	}
    58  	return addresses
    59  }
    60  
    61  func (s *KeeperTestSuite) SetupTest() {
    62  	checkTx := false
    63  	app := simapp.Setup(checkTx)
    64  	s.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{})
    65  	s.goCtx = sdk.WrapSDKContext(s.ctx)
    66  	s.keeper = app.CollectionKeeper
    67  
    68  	s.queryServer = keeper.NewQueryServer(s.keeper)
    69  	s.msgServer = keeper.NewMsgServer(s.keeper)
    70  
    71  	s.depthLimit = 4
    72  	s.keeper.SetParams(s.ctx, collection.Params{
    73  		DepthLimit: uint32(s.depthLimit),
    74  		WidthLimit: 4,
    75  	})
    76  
    77  	addresses := []*sdk.AccAddress{
    78  		&s.vendor,
    79  		&s.operator,
    80  		&s.customer,
    81  		&s.stranger,
    82  	}
    83  	for i, address := range s.createRandomAccounts(len(addresses)) {
    84  		*addresses[i] = address
    85  	}
    86  
    87  	s.balance = sdk.NewInt(1000000)
    88  
    89  	// create a contract
    90  	s.contractID = s.keeper.CreateContract(s.ctx, s.vendor, collection.Contract{
    91  		Name: "fox",
    92  	})
    93  
    94  	for _, permission := range []collection.Permission{
    95  		collection.PermissionMint,
    96  		collection.PermissionBurn,
    97  	} {
    98  		s.keeper.Grant(s.ctx, s.contractID, s.vendor, s.operator, permission)
    99  	}
   100  
   101  	// create a fungible token class
   102  	ftClassID, err := s.keeper.CreateTokenClass(s.ctx, s.contractID, &collection.FTClass{
   103  		Name:     "tibetian fox",
   104  		Mintable: true,
   105  	})
   106  	s.Require().NoError(err)
   107  	s.ftClassID = *ftClassID
   108  
   109  	// create a non-fungible token class
   110  	nftClassID, err := s.keeper.CreateTokenClass(s.ctx, s.contractID, &collection.NFTClass{
   111  		Name: "fennec fox",
   112  	})
   113  	s.Require().NoError(err)
   114  	s.nftClassID = *nftClassID
   115  
   116  	// mint & burn fts
   117  	for _, to := range []sdk.AccAddress{s.customer, s.operator, s.vendor} {
   118  		tokenID := collection.NewFTID(s.ftClassID)
   119  		amount := collection.NewCoins(collection.NewCoin(tokenID, s.balance))
   120  
   121  		err := s.keeper.MintFT(s.ctx, s.contractID, to, amount)
   122  		s.Require().NoError(err)
   123  
   124  		_, err = s.keeper.BurnCoins(s.ctx, s.contractID, to, amount)
   125  		s.Require().NoError(err)
   126  		err = s.keeper.MintFT(s.ctx, s.contractID, to, amount)
   127  		s.Require().NoError(err)
   128  	}
   129  
   130  	// mint nfts
   131  	newParams := func(classID string, size int) []collection.MintNFTParam {
   132  		res := make([]collection.MintNFTParam, size)
   133  		for i := range res {
   134  			res[i] = collection.MintNFTParam{
   135  				TokenType: s.nftClassID,
   136  			}
   137  		}
   138  		return res
   139  	}
   140  	// 1 for the successful attach, 2 for the failure
   141  	remainders := 1 + 2
   142  	s.numNFTs = s.depthLimit + remainders
   143  	// 3 chains, and each chain has depth_limit, 1 and 2 of its length.
   144  	s.numRoots = 3
   145  	for _, to := range []sdk.AccAddress{s.customer, s.operator, s.vendor} {
   146  		tokens, err := s.keeper.MintNFT(s.ctx, s.contractID, to, newParams(s.nftClassID, s.depthLimit))
   147  		s.Require().NoError(err)
   148  
   149  		// create a chain of its length depth_limit
   150  		for i := range tokens[1:] {
   151  			r := len(tokens) - 1 - i
   152  			subject := tokens[r].TokenId
   153  			target := tokens[r-1].TokenId
   154  			err := s.keeper.Attach(s.ctx, s.contractID, to, subject, target)
   155  			s.Require().NoError(err)
   156  		}
   157  
   158  		tokens, err = s.keeper.MintNFT(s.ctx, s.contractID, to, newParams(s.nftClassID, remainders))
   159  		s.Require().NoError(err)
   160  
   161  		// a chain of length 2
   162  		err = s.keeper.Attach(s.ctx, s.contractID, to, tokens[remainders-1].TokenId, tokens[remainders-2].TokenId)
   163  		s.Require().NoError(err)
   164  
   165  	}
   166  
   167  	// authorize
   168  	err = s.keeper.AuthorizeOperator(s.ctx, s.contractID, s.customer, s.operator)
   169  	s.Require().NoError(err)
   170  	err = s.keeper.AuthorizeOperator(s.ctx, s.contractID, s.customer, s.stranger)
   171  	s.Require().NoError(err)
   172  
   173  	// not token contract
   174  	notTokenContractID := app.ClassKeeper.NewID(s.ctx)
   175  	err = keeper.ValidateLegacyContract(s.keeper, s.ctx, notTokenContractID)
   176  	s.Require().ErrorIs(err, collection.ErrCollectionNotExist)
   177  }
   178  
   179  func TestKeeperTestSuite(t *testing.T) {
   180  	suite.Run(t, new(KeeperTestSuite))
   181  }