diff --git a/go.mod b/go.mod index a754a90a..f8c4693d 100644 --- a/go.mod +++ b/go.mod @@ -151,7 +151,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/regen-network/cosmos-proto v0.3.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rjeczalik/notify v0.9.1 // indirect + github.com/rjeczalik/notify v0.9.3 // indirect github.com/rs/cors v1.8.3 // indirect github.com/rs/zerolog v1.27.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect diff --git a/go.sum b/go.sum index abae1197..4d24eea1 100644 --- a/go.sum +++ b/go.sum @@ -1042,8 +1042,9 @@ github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1 github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= +github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1402,6 +1403,7 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/x/asset/keeper/keeper_test.go b/x/asset/keeper/keeper_test.go index 51c473de..7fffdad4 100644 --- a/x/asset/keeper/keeper_test.go +++ b/x/asset/keeper/keeper_test.go @@ -1,12 +1,17 @@ package keeper_test import ( + "context" + "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/gogo/protobuf/proto" + "github.com/spf13/cobra" "github.com/stretchr/testify/suite" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/realiotech/realio-network/app" "github.com/realiotech/realio-network/x/asset/keeper" @@ -21,6 +26,7 @@ type KeeperTestSuite struct { assetKeeper *keeper.Keeper govkeeper govkeeper.Keeper msgServer types.MsgServer + bankKeeper bankkeeper.Keeper } func (suite *KeeperTestSuite) SetupTest() { @@ -31,8 +37,79 @@ func (suite *KeeperTestSuite) SetupTest() { suite.assetKeeper = &app.AssetKeeper suite.govkeeper = app.GovKeeper suite.msgServer = keeper.NewMsgServerImpl(app.AssetKeeper) + suite.bankKeeper = app.BankKeeper } func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } + +func init() { + proto.RegisterType((*MockPrivilegeMsg)(nil), "MockPrivilegeMsg") +} + +// MockPrivilegeMsg defines a mock type PrivilegeMsg +type MockPrivilegeMsg struct { + privName string +} + +var _ proto.Message = &MockPrivilegeMsg{} + +func (m *MockPrivilegeMsg) ValidateBasic() error { + if m.privName == "" { + return fmt.Errorf("empty") + } + return nil +} + +func (m *MockPrivilegeMsg) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{userAddr1} +} + +func (m *MockPrivilegeMsg) Reset() { *m = MockPrivilegeMsg{} } +func (m *MockPrivilegeMsg) String() string { return proto.CompactTextString(m) } +func (m *MockPrivilegeMsg) ProtoMessage() {} + +func (m *MockPrivilegeMsg) NeedPrivilege() string { + return m.privName +} +func (m *MockPrivilegeMsg) XXX_MessageName() string { + return "MockPrivilegeMsg" +} + +func (m *MockPrivilegeMsg) XXX_Unmarshal(b []byte) error { + return nil +} + +// // MockPrivilegeI defines a mock type PrivilegeI +type MockPrivilegeI struct { + privName string +} + +var _ types.PrivilegeI = MockPrivilegeI{} + +func (m MockPrivilegeI) Name() string { + return m.privName +} + +func (m MockPrivilegeI) RegisterInterfaces() { + +} + +func (m MockPrivilegeI) MsgHandler() types.MsgHandler { + return func(context context.Context, privMsg proto.Message) (proto.Message, error) { + return nil, nil + } +} + +func (m MockPrivilegeI) QueryHandler() types.QueryHandler { + return func(context context.Context, privQuery proto.Message) (proto.Message, error) { + return nil, nil + } +} + +func (m MockPrivilegeI) CLI() *cobra.Command { + return &cobra.Command{ + Use: "mock", + } +} diff --git a/x/asset/keeper/msg_server_test.go b/x/asset/keeper/msg_server_test.go index 04d89870..71542435 100644 --- a/x/asset/keeper/msg_server_test.go +++ b/x/asset/keeper/msg_server_test.go @@ -1,7 +1,544 @@ package keeper_test -// import ( -// "fmt" -// "testing" +import ( + "fmt" + "slices" + "strings" -// ) + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/gogo/protobuf/proto" + "github.com/tendermint/tendermint/libs/rand" + + "github.com/realiotech/realio-network/x/asset/keeper" + "github.com/realiotech/realio-network/x/asset/types" +) + +var ( + managerAddr = sdk.AccAddress(rand.Bytes(address.Len)) + creatorAddr = sdk.AccAddress(rand.Bytes(address.Len)) + userAddr1 = sdk.AccAddress(rand.Bytes(address.Len)) + userAddr2 = sdk.AccAddress(rand.Bytes(address.Len)) + userAddr3 = sdk.AccAddress(rand.Bytes(address.Len)) + name = "viet nam dong" + symbol = "vnd" + amount = uint64(1000) +) + +func (s *KeeperTestSuite) TestCreateToken() { + tests := []struct { + name string + expectPass bool + setup func() *types.MsgCreateToken + }{ + { + name: "success", + expectPass: true, + setup: func() *types.MsgCreateToken { + return &types.MsgCreateToken{ + Creator: creatorAddr.String(), + Manager: managerAddr.String(), + Name: name, + Symbol: symbol, + Decimal: 2, + Description: "", + ExcludedPrivileges: []string{}, + AddNewPrivilege: true, + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + msg := test.setup() + + _, err := s.msgServer.CreateToken(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + + lowerCaseSymbol := strings.ToLower(msg.Symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, msg.Creator, lowerCaseSymbol) + _, isFound := s.assetKeeper.GetTokenManagement(s.ctx, tokenId) + s.Require().True(isFound) + } + }) + } +} + +func (s *KeeperTestSuite) TestUpdateToken() { + + tests := []struct { + name string + expectPass bool + setup func(keeper.Keeper, sdk.Context) *types.MsgUpdateToken + }{ + { + name: "success", + expectPass: true, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgUpdateToken { + description := "" + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + return &types.MsgUpdateToken{ + Manager: managerAddr.String(), + TokenId: tokenId, + Name: name, + Symbol: "u" + symbol, // old token is symbol + Description: description, + AddNewPrivilege: false, + } + }, + }, + { + name: "token not exists", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgUpdateToken { + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + + return &types.MsgUpdateToken{ + Manager: managerAddr.String(), + TokenId: tokenId, + Name: name, + Symbol: symbol, + Description: "", + AddNewPrivilege: false, + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + msg := test.setup(*s.assetKeeper, s.ctx) + + oldToken, isFound := s.assetKeeper.GetToken(s.ctx, msg.TokenId) + if test.expectPass { + s.Require().True(isFound) + } else { + s.Require().False(isFound) + } + + _, err := s.msgServer.UpdateToken(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + + newToken, isFound := s.assetKeeper.GetToken(s.ctx, msg.TokenId) + s.Require().True(isFound) + s.Require().NotEqual(oldToken.Symbol, newToken.Symbol) + } else { + s.Require().ErrorIs(sdkerrors.ErrNotFound, err) + } + }) + } +} + +func (s *KeeperTestSuite) TestAllocateToken() { + tests := []struct { + name string + expectPass bool + setup func(k keeper.Keeper, ctx sdk.Context) *types.MsgAllocateToken + }{ + { + name: "success", + expectPass: true, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgAllocateToken { + description := "" + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + return &types.MsgAllocateToken{ + Manager: managerAddr.String(), + TokenId: tokenId, + Balances: []types.Balance{ + { + Address: creatorAddr.String(), + Amount: amount, + }, + }, + } + }, + }, + { + name: "token not exists", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgAllocateToken { + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + + return &types.MsgAllocateToken{ + Manager: managerAddr.String(), + TokenId: tokenId, + Balances: []types.Balance{ + { + Address: creatorAddr.String(), + Amount: amount, + }, + }, + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + + msg := test.setup(*s.assetKeeper, s.ctx) + + _, err := s.msgServer.AllocateToken(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + + coin := s.bankKeeper.GetBalance(s.ctx, creatorAddr, msg.TokenId) + s.Require().Equal(amount, coin.Amount.Uint64()) + } else { + s.Require().ErrorIs(sdkerrors.ErrNotFound, err) + } + + }) + } +} + +func (s *KeeperTestSuite) TestAssignPrivilege() { + tests := []struct { + name string + expectPass bool + setup func(k keeper.Keeper, ctx sdk.Context) *types.MsgAssignPrivilege + }{ + { + name: "success", + expectPass: true, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgAssignPrivilege { + description := "" + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + return &types.MsgAssignPrivilege{ + Manager: managerAddr.String(), + TokenId: tokenId, + AssignedTo: []string{ + userAddr1.String(), + userAddr2.String(), + userAddr3.String(), + }, + Privilege: creatorAddr.String(), + } + }, + }, + { + name: "token not exists", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgAssignPrivilege { + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + + return &types.MsgAssignPrivilege{ + Manager: managerAddr.String(), + TokenId: tokenId, + AssignedTo: []string{ + userAddr1.String(), + userAddr2.String(), + userAddr3.String(), + }, + Privilege: creatorAddr.String(), + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + msg := test.setup(*s.assetKeeper, s.ctx) + + _, err := s.msgServer.AssignPrivilege(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + + privList := s.assetKeeper.GetTokenAccountPrivileges(s.ctx, msg.TokenId, userAddr1) + s.Require().True(slices.Contains(privList, msg.Privilege)) + } else { + s.Require().ErrorIs(sdkerrors.ErrNotFound, err) + } + }) + } +} + +func (s *KeeperTestSuite) TestUnassignPrivilege() { + + tests := []struct { + name string + expectPass bool + setup func(k keeper.Keeper, ctx sdk.Context) *types.MsgUnassignPrivilege + }{ + { + name: "success", + expectPass: true, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgUnassignPrivilege { + description := "" + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr1) + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr2) + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr3) + return &types.MsgUnassignPrivilege{ + Manager: managerAddr.String(), + TokenId: tokenId, + UnassignedFrom: []string{ + userAddr1.String(), + userAddr2.String(), + }, + Privilege: creatorAddr.String(), + } + }, + }, + { + name: "token not exists", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgUnassignPrivilege { + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + return &types.MsgUnassignPrivilege{ + Manager: managerAddr.String(), + TokenId: tokenId, + UnassignedFrom: []string{ + userAddr1.String(), + userAddr2.String(), + }, + Privilege: creatorAddr.String(), + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + msg := test.setup(*s.assetKeeper, s.ctx) + + _, err := s.msgServer.UnassignPrivilege(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + + privList := s.assetKeeper.GetTokenAccountPrivileges(s.ctx, msg.TokenId, userAddr1) + s.Require().False(slices.Contains(privList, msg.Privilege)) + + privList = s.assetKeeper.GetTokenAccountPrivileges(s.ctx, msg.TokenId, userAddr3) //user3 not in UnassignedFrom + s.Require().True(slices.Contains(privList, msg.Privilege)) + } else { + s.Require().ErrorIs(sdkerrors.ErrNotFound, err) + } + }) + } +} + +func (s *KeeperTestSuite) TestDisablePrivilege() { + + tests := []struct { + name string + expectPass bool + setup func(k keeper.Keeper, ctx sdk.Context) *types.MsgDisablePrivilege + }{ + { + name: "success", + expectPass: true, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgDisablePrivilege { + description := "" + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + return &types.MsgDisablePrivilege{ + Manager: managerAddr.String(), + TokenId: tokenId, + DisabledPrivilege: userAddr1.String(), + } + }, + }, + { + name: "token not exists", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgDisablePrivilege { + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + + return &types.MsgDisablePrivilege{ + Manager: managerAddr.String(), + TokenId: tokenId, + DisabledPrivilege: userAddr1.String(), + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + msg := test.setup(*s.assetKeeper, s.ctx) + + _, err := s.msgServer.DisablePrivilege(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + + tm, found := s.assetKeeper.GetTokenManagement(s.ctx, msg.TokenId) + s.Require().True(found) + s.Require().True(slices.Contains(tm.ExcludedPrivileges, userAddr1.String())) + } else { + s.Require().ErrorIs(sdkerrors.ErrNotFound, err) + } + }) + } +} + +func (s *KeeperTestSuite) TestExecutePrivilege() { + + tests := []struct { + name string + expectPass bool + setup func(k keeper.Keeper, ctx sdk.Context) *types.MsgExecutePrivilege + }{ + { + name: "success", + expectPass: true, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgExecutePrivilege { + description := "" + privName := creatorAddr.String() + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr1) + + err := k.AddPrivilege(MockPrivilegeI{ + privName: privName, + }) + s.Require().NoError(err) + var newMockMsg proto.Message = &MockPrivilegeMsg{ + privName: privName, + } + + privilegeMsg, err := codectypes.NewAnyWithValue(newMockMsg) + s.Require().NoError(err) + + return &types.MsgExecutePrivilege{ + Address: userAddr1.String(), + TokenId: tokenId, + PrivilegeMsg: privilegeMsg, + } + }, + }, + { + name: "token not exists", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgExecutePrivilege { + privName := creatorAddr.String() + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + + var newMockMsg proto.Message = &MockPrivilegeMsg{ + privName: privName, + } + + privilegeMsg, err := codectypes.NewAnyWithValue(newMockMsg) + s.Require().NoError(err) + + return &types.MsgExecutePrivilege{ + Address: userAddr1.String(), + TokenId: tokenId, + PrivilegeMsg: privilegeMsg, + } + }, + }, + { + name: "privilege name is not registered yet", + expectPass: false, + setup: func(k keeper.Keeper, ctx sdk.Context) *types.MsgExecutePrivilege { + description := "" + privName := creatorAddr.String() + + lowerCaseSymbol := strings.ToLower(symbol) + tokenId := fmt.Sprintf("%s/%s/%s", types.ModuleName, creatorAddr.String(), lowerCaseSymbol) + token := types.NewToken(tokenId, strings.ToLower(name), lowerCaseSymbol, 2, description) + k.SetToken(ctx, tokenId, token) + + tokenManage := types.NewTokenManagement(managerAddr.String(), true, []string{}) + k.SetTokenManagement(ctx, tokenId, tokenManage) + + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr1) + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr2) + k.SetTokenPrivilegeAccount(ctx, tokenId, creatorAddr.String(), userAddr3) + + var newMockMsg proto.Message = &MockPrivilegeMsg{ + privName: privName, + } + + privilegeMsg, err := codectypes.NewAnyWithValue(newMockMsg) + s.Require().NoError(err) + + return &types.MsgExecutePrivilege{ + Address: userAddr1.String(), + TokenId: tokenId, + PrivilegeMsg: privilegeMsg, + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + msg := test.setup(*s.assetKeeper, s.ctx) + + _, err := s.msgServer.ExecutePrivilege(s.ctx, msg) + if test.expectPass { + s.Require().NoError(err) + } else { + s.Require().Error(err) + } + }) + } +}