From b34ceecd8a235e5f49223fd056f9d233056223d8 Mon Sep 17 00:00:00 2001 From: Spoorthi Satheesha <9302666+spoo-bar@users.noreply.github.com> Date: Mon, 26 Jul 2021 22:51:22 +0200 Subject: [PATCH] test: Added tests for DecCoins to increase code coverage (#9752) ## Description Ref: #7031 Note/todo : 1. Not sure if [this](https://github.com/cosmos/cosmos-sdk/blob/spoorthi/7031-deccoins-adding-tests/types/dec_coin.go#L631) line is reachable. The condition is already checked in [this ](https://github.com/cosmos/cosmos-sdk/blob/spoorthi/7031-deccoins-adding-tests/types/dec_coin.go#L618) line. Therefore, 100% coverage for `ParseDecCoin` function likely not possible 2. Clarification needed [here](https://github.com/cosmos/cosmos-sdk/blob/spoorthi/7031-deccoins-adding-tests/types/dec_coin_test.go#L883-L884) 3. Clarification needed [here](https://github.com/cosmos/cosmos-sdk/blob/spoorthi/7031-deccoins-adding-tests/types/dec_coin_test.go#L1124-L1125) --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- container/option_test.go | 1 + types/dec_coin_test.go | 568 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 566 insertions(+), 3 deletions(-) create mode 100644 container/option_test.go diff --git a/container/option_test.go b/container/option_test.go new file mode 100644 index 000000000000..f447afa5a964 --- /dev/null +++ b/container/option_test.go @@ -0,0 +1 @@ +package container_test diff --git a/types/dec_coin_test.go b/types/dec_coin_test.go index 938f7dddffb4..c0cf44cd60d4 100644 --- a/types/dec_coin_test.go +++ b/types/dec_coin_test.go @@ -112,6 +112,7 @@ func (s *decCoinTestSuite) TestFilteredZeroDecCoins() { input sdk.DecCoins original string expected string + panic bool }{ { name: "all greater than zero", @@ -124,6 +125,7 @@ func (s *decCoinTestSuite) TestFilteredZeroDecCoins() { }, original: "1.000000000000000000testa,2.000000000000000000testb,3.000000000000000000testc,4.000000000000000000testd,5.000000000000000000teste", expected: "1.000000000000000000testa,2.000000000000000000testb,3.000000000000000000testc,4.000000000000000000testd,5.000000000000000000teste", + panic: false, }, { name: "zero coin in middle", @@ -136,6 +138,7 @@ func (s *decCoinTestSuite) TestFilteredZeroDecCoins() { }, original: "1.000000000000000000testa,2.000000000000000000testb,0.000000000000000000testc,4.000000000000000000testd,5.000000000000000000teste", expected: "1.000000000000000000testa,2.000000000000000000testb,4.000000000000000000testd,5.000000000000000000teste", + panic: false, }, { name: "zero coin end (unordered)", @@ -148,13 +151,32 @@ func (s *decCoinTestSuite) TestFilteredZeroDecCoins() { }, original: "5.000000000000000000teste,3.000000000000000000testc,1.000000000000000000testa,4.000000000000000000testd,0.000000000000000000testb", expected: "1.000000000000000000testa,3.000000000000000000testc,4.000000000000000000testd,5.000000000000000000teste", + panic: false, + }, + + { + name: "panic when same denoms in multiple coins", + input: sdk.DecCoins{ + {"testa", sdk.NewDec(5)}, + {"testa", sdk.NewDec(3)}, + {"testa", sdk.NewDec(1)}, + {"testd", sdk.NewDec(4)}, + {"testb", sdk.NewDec(2)}, + }, + original: "5.000000000000000000teste,3.000000000000000000testc,1.000000000000000000testa,4.000000000000000000testd,0.000000000000000000testb", + expected: "1.000000000000000000testa,3.000000000000000000testc,4.000000000000000000testd,5.000000000000000000teste", + panic: true, }, } for _, tt := range cases { - undertest := sdk.NewDecCoins(tt.input...) - s.Require().Equal(tt.expected, undertest.String(), "NewDecCoins must return expected results") - s.Require().Equal(tt.original, tt.input.String(), "input must be unmodified and match original") + if tt.panic { + s.Require().Panics(func() { sdk.NewDecCoins(tt.input...) }, "Should panic due to multiple coins with same denom") + } else { + undertest := sdk.NewDecCoins(tt.input...) + s.Require().Equal(tt.expected, undertest.String(), "NewDecCoins must return expected results") + s.Require().Equal(tt.original, tt.input.String(), "input must be unmodified and match original") + } } } @@ -580,3 +602,543 @@ func (s *decCoinTestSuite) TestDecCoins_AddDecCoinWithIsValid() { } } } + +func (s *decCoinTestSuite) TestDecCoins_Empty() { + testCases := []struct { + input sdk.DecCoins + expectedResult bool + msg string + }{ + {sdk.DecCoins{}, true, "No coins as expected."}, + {sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(5)}}, false, "DecCoins is not empty"}, + } + + for _, tc := range testCases { + if tc.expectedResult { + s.Require().True(tc.input.Empty(), tc.msg) + } else { + s.Require().False(tc.input.Empty(), tc.msg) + } + } +} + +func (s *decCoinTestSuite) TestDecCoins_GetDenomByIndex() { + testCases := []struct { + name string + input sdk.DecCoins + index int + expectedResult string + expectedErr bool + }{ + { + "No DecCoins in Slice", + sdk.DecCoins{}, + 0, + "", + true, + }, + {"When index out of bounds", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(5)}}, 2, "", true}, + {"When negative index", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(5)}}, -1, "", true}, + { + "Appropriate index case", + sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(5)}, + sdk.DecCoin{testDenom2, sdk.NewDec(57)}, + }, 1, testDenom2, false, + }, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedErr { + s.Require().Panics(func() { tc.input.GetDenomByIndex(tc.index) }, "Test should have panicked") + } else { + res := tc.input.GetDenomByIndex(tc.index) + s.Require().Equal(tc.expectedResult, res, "Unexpected result for test case #%d, expected output: %s, input: %v", i, tc.expectedResult, tc.input) + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoins_IsAllPositive() { + testCases := []struct { + name string + input sdk.DecCoins + expectedResult bool + }{ + {"No Coins", sdk.DecCoins{}, false}, + + {"One Coin - Zero value", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(0)}}, false}, + + {"One Coin - Postive value", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(5)}}, true}, + + {"One Coin - Negative value", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(-15)}}, false}, + + {"Multiple Coins - All positive value", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(51)}, + sdk.DecCoin{testDenom1, sdk.NewDec(123)}, + sdk.DecCoin{testDenom1, sdk.NewDec(50)}, + sdk.DecCoin{testDenom1, sdk.NewDec(92233720)}, + }, true}, + + {"Multiple Coins - Some negative value", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(51)}, + sdk.DecCoin{testDenom1, sdk.NewDec(-123)}, + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(92233720)}, + }, false}, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedResult { + s.Require().True(tc.input.IsAllPositive(), "Test case #%d: %s", i, tc.name) + } else { + s.Require().False(tc.input.IsAllPositive(), "Test case #%d: %s", i, tc.name) + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoin_IsLT() { + testCases := []struct { + name string + coin sdk.DecCoin + otherCoin sdk.DecCoin + expectedResult bool + expectedPanic bool + }{ + + {"Same Denom - Less than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(3)}, sdk.DecCoin{testDenom1, sdk.NewDec(19)}, true, false}, + + {"Same Denom - Greater than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(343340)}, sdk.DecCoin{testDenom1, sdk.NewDec(14)}, false, false}, + + {"Same Denom - Same as other coin", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, sdk.DecCoin{testDenom1, sdk.NewDec(20)}, false, false}, + + {"Different Denom - Less than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(3)}, sdk.DecCoin{testDenom2, sdk.NewDec(19)}, true, true}, + + {"Different Denom - Greater than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(343340)}, sdk.DecCoin{testDenom2, sdk.NewDec(14)}, true, true}, + + {"Different Denom - Same as other coin", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, sdk.DecCoin{testDenom2, sdk.NewDec(20)}, true, true}, + } + + for i, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedPanic { + s.Require().Panics(func() { tc.coin.IsLT(tc.otherCoin) }, "Test case #%d: %s", i, tc.name) + } else { + res := tc.coin.IsLT(tc.otherCoin) + if tc.expectedResult { + s.Require().True(res, "Test case #%d: %s", i, tc.name) + } else { + s.Require().False(res, "Test case #%d: %s", i, tc.name) + } + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoin_IsGTE() { + testCases := []struct { + name string + coin sdk.DecCoin + otherCoin sdk.DecCoin + expectedResult bool + expectedPanic bool + }{ + + {"Same Denom - Less than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(3)}, sdk.DecCoin{testDenom1, sdk.NewDec(19)}, false, false}, + + {"Same Denom - Greater than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(343340)}, sdk.DecCoin{testDenom1, sdk.NewDec(14)}, true, false}, + + {"Same Denom - Same as other coin", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, sdk.DecCoin{testDenom1, sdk.NewDec(20)}, true, false}, + + {"Different Denom - Less than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(3)}, sdk.DecCoin{testDenom2, sdk.NewDec(19)}, true, true}, + + {"Different Denom - Greater than other coin", sdk.DecCoin{testDenom1, sdk.NewDec(343340)}, sdk.DecCoin{testDenom2, sdk.NewDec(14)}, true, true}, + + {"Different Denom - Same as other coin", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, sdk.DecCoin{testDenom2, sdk.NewDec(20)}, true, true}, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedPanic { + s.Require().Panics(func() { tc.coin.IsGTE(tc.otherCoin) }, "Test case #%d: %s", i, tc.name) + } else { + res := tc.coin.IsGTE(tc.otherCoin) + if tc.expectedResult { + s.Require().True(res, "Test case #%d: %s", i, tc.name) + } else { + s.Require().False(res, "Test case #%d: %s", i, tc.name) + } + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoins_IsZero() { + testCases := []struct { + name string + coins sdk.DecCoins + expectedResult bool + }{ + {"No Coins", sdk.DecCoins{}, true}, + + {"One Coin - Zero value", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(0)}}, true}, + + {"One Coin - Postive value", sdk.DecCoins{sdk.DecCoin{testDenom1, sdk.NewDec(5)}}, false}, + + {"Multiple Coins - All zero value", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + }, true}, + + {"Multiple Coins - Some positive value", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(0)}, + sdk.DecCoin{testDenom1, sdk.NewDec(92233720)}, + }, false}, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedResult { + s.Require().True(tc.coins.IsZero(), "Test case #%d: %s", i, tc.name) + } else { + s.Require().False(tc.coins.IsZero(), "Test case #%d: %s", i, tc.name) + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoins_MulDec() { + testCases := []struct { + name string + coins sdk.DecCoins + multiplier sdk.Dec + expectedResult sdk.DecCoins + }{ + {"No Coins", sdk.DecCoins{}, sdk.NewDec(1), sdk.DecCoins(nil)}, + + {"Multiple coins - zero multiplier", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(10)}, + sdk.DecCoin{testDenom1, sdk.NewDec(30)}, + }, sdk.NewDec(0), sdk.DecCoins(nil)}, + + {"Multiple coins - positive multiplier", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(1)}, + sdk.DecCoin{testDenom1, sdk.NewDec(2)}, + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.NewDec(2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(20)}, + }}, + + {"Multiple coins - negative multiplier", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(1)}, + sdk.DecCoin{testDenom1, sdk.NewDec(2)}, + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.NewDec(-2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(-20)}, + }}, + + {"Multiple coins - Different denom", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(1)}, + sdk.DecCoin{testDenom2, sdk.NewDec(2)}, + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom2, sdk.NewDec(4)}, + }, sdk.NewDec(2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(8)}, + sdk.DecCoin{testDenom2, sdk.NewDec(12)}, + }}, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + res := tc.coins.MulDec(tc.multiplier) + s.Require().Equal(tc.expectedResult, res, "Test case #%d: %s", i, tc.name) + }) + } +} + +func (s *decCoinTestSuite) TestDecCoins_MulDecTruncate() { + testCases := []struct { + name string + coins sdk.DecCoins + multiplier sdk.Dec + expectedResult sdk.DecCoins + expectedPanic bool + }{ + {"No Coins", sdk.DecCoins{}, sdk.NewDec(1), sdk.DecCoins(nil), false}, + + // TODO - Fix test - Function comment documentation for MulDecTruncate says if multiplier d is zero, it should panic. + // However, that is not the observed behaviour. Currently nil is returned. + {"Multiple coins - zero multiplier", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(10, 3)}, + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(30, 2)}, + }, sdk.NewDec(0), sdk.DecCoins(nil), false}, + + {"Multiple coins - positive multiplier", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(15, 1)}, + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(15, 1)}, + }, sdk.NewDec(1), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(3, 0)}, + }, false}, + + {"Multiple coins - positive multiplier", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(15, 1)}, + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(15, 1)}, + }, sdk.NewDec(-2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(-6, 0)}, + }, false}, + + {"Multiple coins - Different denom", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(15, 1)}, + sdk.DecCoin{testDenom2, sdk.NewDecWithPrec(3333, 4)}, + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(15, 1)}, + sdk.DecCoin{testDenom2, sdk.NewDecWithPrec(333, 4)}, + }, sdk.NewDec(10), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(30, 0)}, + sdk.DecCoin{testDenom2, sdk.NewDecWithPrec(3666, 3)}, + }, false}, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedPanic { + s.Require().Panics(func() { tc.coins.MulDecTruncate(tc.multiplier) }, "Test case #%d: %s", i, tc.name) + } else { + res := tc.coins.MulDecTruncate(tc.multiplier) + s.Require().Equal(tc.expectedResult, res, "Test case #%d: %s", i, tc.name) + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoins_QuoDec() { + + testCases := []struct { + name string + coins sdk.DecCoins + input sdk.Dec + expectedResult sdk.DecCoins + panics bool + }{ + {"No Coins", sdk.DecCoins{}, sdk.NewDec(1), sdk.DecCoins(nil), false}, + + {"Multiple coins - zero input", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(10)}, + sdk.DecCoin{testDenom1, sdk.NewDec(30)}, + }, sdk.NewDec(0), sdk.DecCoins(nil), true}, + + {"Multiple coins - positive input", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.NewDec(2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(35, 1)}, + }, false}, + + {"Multiple coins - negative input", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.NewDec(-2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDecWithPrec(-35, 1)}, + }, false}, + + {"Multiple coins - Different input", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(1)}, + sdk.DecCoin{testDenom2, sdk.NewDec(2)}, + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom2, sdk.NewDec(4)}, + }, sdk.NewDec(2), sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(2)}, + sdk.DecCoin{testDenom2, sdk.NewDec(3)}, + }, false}, + } + + for i, tc := range testCases { + tc := tc + s.T().Run(tc.name, func(t *testing.T) { + if tc.panics { + s.Require().Panics(func() { tc.coins.QuoDec(tc.input) }, "Test case #%d: %s", i, tc.name) + } else { + res := tc.coins.QuoDec(tc.input) + s.Require().Equal(tc.expectedResult, res, "Test case #%d: %s", i, tc.name) + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoin_IsEqual() { + testCases := []struct { + name string + coin sdk.DecCoin + otherCoin sdk.DecCoin + expectedResult bool + expectedPanic bool + }{ + + {"Different Denom Same Amount", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, + sdk.DecCoin{testDenom2, sdk.NewDec(20)}, + false, true}, + + {"Different Denom Different Amount", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, + sdk.DecCoin{testDenom2, sdk.NewDec(10)}, + false, true}, + + {"Same Denom Different Amount", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, + sdk.DecCoin{testDenom1, sdk.NewDec(10)}, + false, false}, + + {"Same Denom Same Amount", sdk.DecCoin{testDenom1, sdk.NewDec(20)}, + sdk.DecCoin{testDenom1, sdk.NewDec(20)}, + true, false}, + } + + for i, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedPanic { + s.Require().Panics(func() { tc.coin.IsEqual(tc.otherCoin) }, "Test case #%d: %s", i, tc.name) + } else { + res := tc.coin.IsEqual(tc.otherCoin) + if tc.expectedResult { + s.Require().True(res, "Test case #%d: %s", i, tc.name) + } else { + s.Require().False(res, "Test case #%d: %s", i, tc.name) + } + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoins_IsEqual() { + testCases := []struct { + name string + coinsA sdk.DecCoins + coinsB sdk.DecCoins + expectedResult bool + expectedPanic bool + }{ + {"Different length sets", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(35)}, + }, false, false}, + + {"Same length - different denoms", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.DecCoins{ + sdk.DecCoin{testDenom2, sdk.NewDec(3)}, + sdk.DecCoin{testDenom2, sdk.NewDec(4)}, + }, false, true}, + + {"Same length - different amounts", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(3)}, + sdk.DecCoin{testDenom1, sdk.NewDec(4)}, + }, sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(41)}, + sdk.DecCoin{testDenom1, sdk.NewDec(343)}, + }, false, false}, + + {"Same length - same amounts", sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(33)}, + sdk.DecCoin{testDenom1, sdk.NewDec(344)}, + }, sdk.DecCoins{ + sdk.DecCoin{testDenom1, sdk.NewDec(33)}, + sdk.DecCoin{testDenom1, sdk.NewDec(344)}, + }, true, false}, + } + + for i, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + if tc.expectedPanic { + s.Require().Panics(func() { tc.coinsA.IsEqual(tc.coinsB) }, "Test case #%d: %s", i, tc.name) + } else { + res := tc.coinsA.IsEqual(tc.coinsB) + if tc.expectedResult { + s.Require().True(res, "Test case #%d: %s", i, tc.name) + } else { + s.Require().False(res, "Test case #%d: %s", i, tc.name) + } + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoin_Validate() { + var empty sdk.DecCoin + testCases := []struct { + name string + input sdk.DecCoin + expectedPass bool + }{ + {"Uninitalized deccoin", empty, false}, + + {"Invalid denom string", sdk.DecCoin{"(){9**&})", sdk.NewDec(33)}, false}, + + {"Negative coin amount", sdk.DecCoin{testDenom1, sdk.NewDec(-33)}, false}, + + {"Valid coin", sdk.DecCoin{testDenom1, sdk.NewDec(33)}, true}, + } + + for i, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + err := tc.input.Validate() + if tc.expectedPass { + s.Require().NoError(err, "unexpected result for test case #%d %s, input: %v", i, tc.name, tc.input) + } else { + s.Require().Error(err, "unexpected result for test case #%d %s, input: %v", i, tc.name, tc.input) + } + }) + } +} + +func (s *decCoinTestSuite) TestDecCoin_ParseDecCoin() { + var empty sdk.DecCoin + testCases := []struct { + name string + input string + expectedResult sdk.DecCoin + expectedErr bool + }{ + {"Empty input", "", empty, true}, + + {"Bad input", "✨🌟⭐", empty, true}, + + {"Invalid decimal coin", "9.3.0stake", empty, true}, + + {"Precision over limit", "9.11111111111111111111stake", empty, true}, + + // TODO - Clarify - According to error message for ValidateDenom call, supposed to + // throw error when upper case characters are used. Currently uppercase denoms are allowed. + {"Invalid denom", "9.3STAKE", sdk.DecCoin{"STAKE", sdk.NewDecWithPrec(93, 1)}, false}, + + {"Valid input - amount and denom seperated by space", "9.3 stake", sdk.DecCoin{"stake", sdk.NewDecWithPrec(93, 1)}, false}, + + {"Valid input - amount and denom concatenated", "9.3stake", sdk.DecCoin{"stake", sdk.NewDecWithPrec(93, 1)}, false}, + } + + for i, tc := range testCases { + s.T().Run(tc.name, func(t *testing.T) { + res, err := sdk.ParseDecCoin(tc.input) + if tc.expectedErr { + s.Require().Error(err, "expected error for test case #%d %s, input: %v", i, tc.name, tc.input) + } else { + s.Require().NoError(err, "unexpected error for test case #%d %s, input: %v", i, tc.name, tc.input) + s.Require().Equal(tc.expectedResult, res, "unexpected result for test case #%d %s, input: %v", i, tc.name, tc.input) + } + }) + } +}