cosmos-sdk/x/nft/keeper/nft_batch_test.go

361 lines
7.7 KiB
Go

package keeper_test
import (
"fmt"
"math/rand"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/nft"
)
func (s *TestSuite) TestBatchMint() {
receiver := s.addrs[0]
testCases := []struct {
msg string
malleate func([]nft.NFT)
tokens []nft.NFT
expPass bool
}{
{
"success with empty nft",
func(tokens []nft.NFT) {
s.saveClass(tokens)
},
[]nft.NFT{},
true,
},
{
"success with single nft",
func(tokens []nft.NFT) {
s.saveClass(tokens)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
},
true,
},
{
"success with multiple nft",
func(tokens []nft.NFT) {
s.saveClass(tokens)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID2"},
},
true,
},
{
"success with multiple class and multiple nft",
func(tokens []nft.NFT) {
s.saveClass(tokens)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID2"},
{ClassId: "classID2", Id: "nftID1"},
{ClassId: "classID2", Id: "nftID2"},
},
true,
},
{
"faild with repeated nft",
func(tokens []nft.NFT) {
s.saveClass(tokens)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID2", Id: "nftID2"},
},
false,
},
{
"faild with not exist class",
func(tokens []nft.NFT) {
// do nothing
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID2", Id: "nftID2"},
},
false,
},
{
"faild with exist nft",
func(tokens []nft.NFT) {
s.saveClass(tokens)
idx := rand.Intn(len(tokens))
s.nftKeeper.Mint(s.ctx, tokens[idx], receiver)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID2"},
{ClassId: "classID2", Id: "nftID2"},
},
false,
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.msg), func() {
s.SetupTest() // reset
tc.malleate(tc.tokens)
err := s.nftKeeper.BatchMint(s.ctx, tc.tokens, receiver)
if tc.expPass {
s.Require().NoError(err)
classMap := groupByClassID(tc.tokens)
for classID, tokens := range classMap {
for _, token := range tokens {
actNFT, has := s.nftKeeper.GetNFT(s.ctx, token.ClassId, token.Id)
s.Require().True(has)
s.Require().EqualValues(token, actNFT)
owner := s.nftKeeper.GetOwner(s.ctx, token.ClassId, token.Id)
s.Require().True(receiver.Equals(owner))
}
actNFTs := s.nftKeeper.GetNFTsOfClass(s.ctx, classID)
s.Require().EqualValues(tokens, actNFTs)
actNFTs = s.nftKeeper.GetNFTsOfClassByOwner(s.ctx, classID, receiver)
s.Require().EqualValues(tokens, actNFTs)
balance := s.nftKeeper.GetBalance(s.ctx, classID, receiver)
s.Require().EqualValues(len(tokens), balance)
supply := s.nftKeeper.GetTotalSupply(s.ctx, classID)
s.Require().EqualValues(len(tokens), supply)
}
return
}
s.Require().Error(err)
})
}
}
func (s *TestSuite) TestBatchBurn() {
receiver := s.addrs[0]
tokens := []nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID2"},
{ClassId: "classID2", Id: "nftID1"},
{ClassId: "classID2", Id: "nftID2"},
}
testCases := []struct {
msg string
malleate func()
classID string
nftIDs []string
expPass bool
}{
{
"success",
func() {
s.saveClass(tokens)
s.nftKeeper.BatchMint(s.ctx, tokens, receiver)
},
"classID1",
[]string{"nftID1", "nftID2"},
true,
},
{
"failed with not exist classID",
func() {},
"classID1",
[]string{"nftID1", "nftID2"},
false,
},
{
"failed with not exist nftID",
func() {
s.saveClass(tokens)
},
"classID1",
[]string{"nftID1", "nftID2"},
false,
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.msg), func() {
s.SetupTest() // reset
tc.malleate()
err := s.nftKeeper.BatchBurn(s.ctx, tc.classID, tc.nftIDs)
if tc.expPass {
s.Require().NoError(err)
for _, nftID := range tc.nftIDs {
s.Require().False(s.nftKeeper.HasNFT(s.ctx, tc.classID, nftID))
}
return
}
s.Require().Error(err)
})
}
}
func (s *TestSuite) TestBatchUpdate() {
receiver := s.addrs[0]
tokens := []nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID2"},
{ClassId: "classID2", Id: "nftID1"},
{ClassId: "classID2", Id: "nftID2"},
}
testCases := []struct {
msg string
malleate func()
tokens []nft.NFT
expPass bool
}{
{
"success",
func() {
s.saveClass(tokens)
s.nftKeeper.BatchMint(s.ctx, tokens, receiver)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1", Uri: "nftID1_URI"},
{ClassId: "classID2", Id: "nftID2", Uri: "nftID2_URI"},
},
true,
},
{
"failed with not exist classID",
func() {},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1", Uri: "nftID1_URI"},
{ClassId: "classID2", Id: "nftID2", Uri: "nftID2_URI"},
},
false,
},
{
"failed with not exist nftID",
func() {
s.saveClass(tokens)
},
[]nft.NFT{
{ClassId: "classID1", Id: "nftID1", Uri: "nftID1_URI"},
{ClassId: "classID2", Id: "nftID2", Uri: "nftID2_URI"},
},
false,
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.msg), func() {
s.SetupTest() // reset
tc.malleate()
err := s.nftKeeper.BatchUpdate(s.ctx, tc.tokens)
if tc.expPass {
s.Require().NoError(err)
for _, token := range tc.tokens {
actToken, found := s.nftKeeper.GetNFT(s.ctx, token.ClassId, token.Id)
s.Require().True(found)
s.Require().EqualValues(token, actToken)
}
return
}
s.Require().Error(err)
})
}
}
func (s *TestSuite) TestBatchTransfer() {
owner := s.addrs[0]
receiver := s.addrs[1]
tokens := []nft.NFT{
{ClassId: "classID1", Id: "nftID1"},
{ClassId: "classID1", Id: "nftID2"},
{ClassId: "classID2", Id: "nftID1"},
{ClassId: "classID2", Id: "nftID2"},
}
testCases := []struct {
msg string
malleate func()
classID string
nftIDs []string
expPass bool
}{
{
"success",
func() {
s.saveClass(tokens)
s.nftKeeper.BatchMint(s.ctx, tokens, owner)
},
"classID1",
[]string{"nftID1", "nftID2"},
true,
},
{
"failed with not exist classID",
func() {
s.saveClass(tokens)
s.nftKeeper.BatchMint(s.ctx, tokens, receiver)
},
"classID3",
[]string{"nftID1", "nftID2"},
false,
},
{
"failed with not exist nftID",
func() {
s.saveClass(tokens)
},
"classID1",
[]string{"nftID1", "nftID2"},
false,
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.msg), func() {
s.SetupTest() // reset
tc.malleate()
err := s.nftKeeper.BatchTransfer(s.ctx, tc.classID, tc.nftIDs, receiver)
if tc.expPass {
s.Require().NoError(err)
for _, nftID := range tc.nftIDs {
actOwner := s.nftKeeper.GetOwner(s.ctx, tc.classID, nftID)
s.Require().EqualValues(receiver, actOwner)
}
return
}
s.Require().Error(err)
})
}
}
func groupByClassID(tokens []nft.NFT) map[string][]nft.NFT {
classMap := make(map[string][]nft.NFT, len(tokens))
for _, token := range tokens {
if _, ok := classMap[token.ClassId]; !ok {
classMap[token.ClassId] = make([]nft.NFT, 0)
}
classMap[token.ClassId] = append(classMap[token.ClassId], token)
}
return classMap
}
func (s *TestSuite) saveClass(tokens []nft.NFT) {
classMap := groupByClassID(tokens)
for classID := range classMap {
err := s.nftKeeper.SaveClass(s.ctx, nft.Class{Id: classID})
s.Require().NoError(err)
}
}
func (s *TestSuite) mintNFT(tokens []nft.NFT, receiver sdk.AccAddress) {
for _, token := range tokens {
err := s.nftKeeper.Mint(s.ctx, token, receiver)
s.Require().NoError(err)
}
}