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 }