diff --git a/types/tx/msgs_test.go b/types/tx/msgs_test.go new file mode 100644 index 0000000000..4765f82d7a --- /dev/null +++ b/types/tx/msgs_test.go @@ -0,0 +1,182 @@ +package tx_test + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" +) + +func Test_SetMsg(t *testing.T) { + cases := map[string]struct { + msg sdk.Msg + msgTypeURL string + expErr bool + }{ + "Set nil Msg": { + msg: nil, + expErr: true, + }, + "Set empty message": { + msg: &DummyProtoMessage1{}, + msgTypeURL: "/dummy.proto.message1", + expErr: false, + }, + "Set a valid message": { + msg: &DummyProtoMessage1{Name: "some-name"}, + msgTypeURL: "/dummy.proto.message1", + expErr: false, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + actual, err := tx.SetMsg(tc.msg) + if tc.expErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + b, err := json.Marshal(tc.msg) + require.NoError(t, err) + + require.Equal(t, tc.msgTypeURL, actual.TypeUrl) + require.Equal(t, b, actual.GetValue()) + require.Equal(t, tc.msg, actual.GetCachedValue()) + }) + } +} + +func Test_SetMsgs(t *testing.T) { + cases := map[string]struct { + msgs []sdk.Msg + msgTypeURL []string + expErr bool + }{ + "Set nil slice of messages": { + msgs: nil, + expErr: false, + }, + "Set empty slice of messages": { + msgs: []sdk.Msg{}, + expErr: false, + }, + "Set nil message inside the slice of messages": { + msgs: []sdk.Msg{nil}, + expErr: true, + }, + "Set valid messages": { + msgs: []sdk.Msg{&DummyProtoMessage1{Name: "name1"}, &DummyProtoMessage2{}}, + msgTypeURL: []string{"/dummy.proto.message1", "/dummy.proto.message2"}, + expErr: false, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + actual, err := tx.SetMsgs(tc.msgs) + if tc.expErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, len(tc.msgs), len(actual)) + + for i, msg := range tc.msgs { + b, err := json.Marshal(msg) + require.NoError(t, err) + + require.Equal(t, msg, actual[i].GetCachedValue()) + require.Equal(t, tc.msgTypeURL[i], actual[i].GetTypeUrl()) + require.Equal(t, b, actual[i].GetValue()) + } + }) + } +} + +func Test_GetMsgs(t *testing.T) { + sdkMsgs := []sdk.Msg{&DummyProtoMessage1{}, &DummyProtoMessage2{}} + anyMsg, err := tx.SetMsgs(sdkMsgs) + require.NoError(t, err) + + cases := map[string]struct { + msgs []*types.Any + expected []sdk.Msg + expErr bool + }{ + "GetMsgs from a nil slice of Any messages": { + msgs: nil, + expected: []sdk.Msg{}, + expErr: false, + }, + "GetMsgs from empty slice of Any messages": { + msgs: []*types.Any{}, + expected: []sdk.Msg{}, + expErr: false, + }, + "GetMsgs from a slice with valid Any messages": { + msgs: anyMsg, + expected: sdkMsgs, + expErr: false, + }, + "GetMsgs from a slice that contains uncached Any message": { + msgs: []*types.Any{{}}, + expErr: true, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + actual, err := tx.GetMsgs(tc.msgs, "dummy") + if tc.expErr { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tc.expected, actual) + }) + } +} + +func TestTx_UnpackInterfaces(t *testing.T) { + unpacker := codec.NewProtoCodec(types.NewInterfaceRegistry()) + sdkMsgs := []sdk.Msg{&DummyProtoMessage1{}, &DummyProtoMessage2{}} + anyMsg, err := tx.SetMsgs(sdkMsgs) + require.NoError(t, err) + + cases := map[string]struct { + msgs []*types.Any + expErr bool + }{ + "Unpack nil slice messages": { + msgs: nil, + expErr: false, + }, + "Unpack empty slice of messages": { + msgs: []*types.Any{}, + expErr: false, + }, + "Unpack valid messages": { + msgs: anyMsg, + expErr: false, + }, + "Unpack uncashed message": { + msgs: []*types.Any{{TypeUrl: "uncached"}}, + expErr: true, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + err = tx.UnpackInterfaces(unpacker, tc.msgs) + require.Equal(t, tc.expErr, err != nil) + }) + } +} diff --git a/types/tx/types_test.go b/types/tx/types_test.go index 14b6274f27..f417b36cc7 100644 --- a/types/tx/types_test.go +++ b/types/tx/types_test.go @@ -1,7 +1,8 @@ -package tx +package tx_test import ( "encoding/hex" + "encoding/json" "testing" "github.com/cosmos/gogoproto/proto" @@ -15,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/address" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" ) func TestTx_GetMsgs(t *testing.T) { @@ -56,8 +58,8 @@ func TestTx_GetMsgs(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - transaction := Tx{ - Body: &TxBody{ + transaction := tx.Tx{ + Body: &tx.TxBody{ Messages: tc.msgs, }, } @@ -77,7 +79,7 @@ func TestTx_GetMsgs(t *testing.T) { func TestTx_ValidateBasic(t *testing.T) { cases := []struct { name string - transaction *Tx + transaction *tx.Tx expErr bool }{ { @@ -87,46 +89,46 @@ func TestTx_ValidateBasic(t *testing.T) { }, { name: "Tx without body", - transaction: &Tx{}, + transaction: &tx.Tx{}, expErr: true, }, { name: "Tx without AuthInfo", - transaction: &Tx{Body: &TxBody{}}, + transaction: &tx.Tx{Body: &tx.TxBody{}}, expErr: true, }, { name: "Tx without Fee", - transaction: &Tx{Body: &TxBody{}, AuthInfo: &AuthInfo{}}, + transaction: &tx.Tx{Body: &tx.TxBody{}, AuthInfo: &tx.AuthInfo{}}, expErr: true, }, { name: "Tx with gas limit greater than Max gas wanted", - transaction: &Tx{Body: &TxBody{}, AuthInfo: &AuthInfo{Fee: &Fee{GasLimit: MaxGasWanted + 1}}}, + transaction: &tx.Tx{Body: &tx.TxBody{}, AuthInfo: &tx.AuthInfo{Fee: &tx.Fee{GasLimit: tx.MaxGasWanted + 1}}}, expErr: true, }, { name: "Tx without Fee Amount", - transaction: &Tx{Body: &TxBody{}, AuthInfo: &AuthInfo{Fee: &Fee{GasLimit: MaxGasWanted}}}, + transaction: &tx.Tx{Body: &tx.TxBody{}, AuthInfo: &tx.AuthInfo{Fee: &tx.Fee{GasLimit: tx.MaxGasWanted}}}, expErr: true, }, { name: "Tx with negative Fee Amount", - transaction: &Tx{ - Body: &TxBody{}, - AuthInfo: &AuthInfo{ - Fee: &Fee{GasLimit: MaxGasWanted, Amount: sdk.Coins{sdk.Coin{Amount: math.NewInt(-1)}}}, + transaction: &tx.Tx{ + Body: &tx.TxBody{}, + AuthInfo: &tx.AuthInfo{ + Fee: &tx.Fee{GasLimit: tx.MaxGasWanted, Amount: sdk.Coins{sdk.Coin{Amount: math.NewInt(-1)}}}, }, }, expErr: true, }, { name: "Tx with invalid fee payer address", - transaction: &Tx{ - Body: &TxBody{}, - AuthInfo: &AuthInfo{ - Fee: &Fee{ - GasLimit: MaxGasWanted, + transaction: &tx.Tx{ + Body: &tx.TxBody{}, + AuthInfo: &tx.AuthInfo{ + Fee: &tx.Fee{ + GasLimit: tx.MaxGasWanted, Payer: "invalidPayerAddress", Amount: sdk.Coins{sdk.NewCoin("aaa", math.NewInt(10))}, }, @@ -136,11 +138,11 @@ func TestTx_ValidateBasic(t *testing.T) { }, { name: "Tx without signature", - transaction: &Tx{ - Body: &TxBody{}, - AuthInfo: &AuthInfo{ - Fee: &Fee{ - GasLimit: MaxGasWanted, + transaction: &tx.Tx{ + Body: &tx.TxBody{}, + AuthInfo: &tx.AuthInfo{ + Fee: &tx.Fee{ + GasLimit: tx.MaxGasWanted, Payer: "cosmos1ulav3hsenupswqfkw2y3sup5kgtqwnvqa8eyhs", Amount: sdk.Coins{sdk.NewCoin("aaa", math.NewInt(11))}, }, @@ -150,11 +152,11 @@ func TestTx_ValidateBasic(t *testing.T) { }, { name: "Tx is valid", - transaction: &Tx{ - Body: &TxBody{}, - AuthInfo: &AuthInfo{ - Fee: &Fee{ - GasLimit: MaxGasWanted, + transaction: &tx.Tx{ + Body: &tx.TxBody{}, + AuthInfo: &tx.AuthInfo{ + Fee: &tx.Fee{ + GasLimit: tx.MaxGasWanted, Payer: "cosmos1ulav3hsenupswqfkw2y3sup5kgtqwnvqa8eyhs", Amount: sdk.Coins{sdk.NewCoin("aaa", math.NewInt(11))}, }, @@ -174,11 +176,11 @@ func TestTx_ValidateBasic(t *testing.T) { } func TestTx_GetSigners(t *testing.T) { - transaction := &Tx{ - Body: &TxBody{}, - AuthInfo: &AuthInfo{ - Fee: &Fee{ - GasLimit: MaxGasWanted, + transaction := &tx.Tx{ + Body: &tx.TxBody{}, + AuthInfo: &tx.AuthInfo{ + Fee: &tx.Fee{ + GasLimit: tx.MaxGasWanted, Payer: "cosmos1ulav3hsenupswqfkw2y3sup5kgtqwnvqa8eyhs", Amount: sdk.Coins{sdk.NewCoin("aaa", math.NewInt(11))}, }, @@ -206,17 +208,23 @@ func TestTx_GetSigners(t *testing.T) { require.Nil(t, err) } -type DummyProtoMessage1 struct{} +type DummyProtoMessage1 struct { + Name string +} -func (d *DummyProtoMessage1) Reset() {} -func (d *DummyProtoMessage1) String() string { return "/dummy.proto.message1" } -func (d *DummyProtoMessage1) ProtoMessage() {} +func (d *DummyProtoMessage1) Reset() {} +func (d *DummyProtoMessage1) String() string { return "/dummy.proto.message1" } +func (d *DummyProtoMessage1) ProtoMessage() {} +func (d *DummyProtoMessage1) Marshal() ([]byte, error) { return json.Marshal(d) } +func (d *DummyProtoMessage1) XXX_MessageName() string { return "dummy.proto.message1" } type DummyProtoMessage2 struct{} -func (d *DummyProtoMessage2) Reset() {} -func (d *DummyProtoMessage2) String() string { return "/dummy.proto.message2" } -func (d *DummyProtoMessage2) ProtoMessage() {} +func (d *DummyProtoMessage2) Reset() {} +func (d *DummyProtoMessage2) String() string { return "/dummy.proto.message2" } +func (d *DummyProtoMessage2) ProtoMessage() {} +func (d *DummyProtoMessage2) Marshal() ([]byte, error) { return json.Marshal(d) } +func (d *DummyProtoMessage2) XXX_MessageName() string { return "dummy.proto.message2" } type dummyAddressCodec struct{}