Merge PR #3607: Reconcile DecCoin/s API with Coin/s API

This commit is contained in:
Alexander Bezobchuk
2019-02-15 16:33:23 +01:00
committed by Christopher Goes
parent 1aa6c197ff
commit 26c13b28cd
15 changed files with 456 additions and 291 deletions
+35 -24
View File
@@ -27,12 +27,11 @@ type Coin struct {
// NewCoin returns a new coin with a denomination and amount. It will panic if
// the amount is negative.
func NewCoin(denom string, amount Int) Coin {
validateDenom(denom)
if amount.LT(ZeroInt()) {
panic(fmt.Sprintf("negative coin amount: %v\n", amount))
}
if strings.ToLower(denom) != denom {
panic(fmt.Sprintf("denom cannot contain upper case characters: %s\n", denom))
}
return Coin{
Denom: denom,
@@ -51,11 +50,6 @@ func (coin Coin) String() string {
return fmt.Sprintf("%v%v", coin.Amount, coin.Denom)
}
// SameDenomAs returns true if the two coins are the same denom
func (coin Coin) SameDenomAs(other Coin) bool {
return (coin.Denom == other.Denom)
}
// IsZero returns if this represents no money
func (coin Coin) IsZero() bool {
return coin.Amount.IsZero()
@@ -64,24 +58,36 @@ func (coin Coin) IsZero() bool {
// IsGTE returns true if they are the same type and the receiver is
// an equal or greater value
func (coin Coin) IsGTE(other Coin) bool {
return coin.SameDenomAs(other) && (!coin.Amount.LT(other.Amount))
if coin.Denom != other.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
}
return !coin.Amount.LT(other.Amount)
}
// IsLT returns true if they are the same type and the receiver is
// a smaller value
func (coin Coin) IsLT(other Coin) bool {
return coin.SameDenomAs(other) && coin.Amount.LT(other.Amount)
if coin.Denom != other.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
}
return coin.Amount.LT(other.Amount)
}
// IsEqual returns true if the two sets of Coins have the same value
func (coin Coin) IsEqual(other Coin) bool {
return coin.SameDenomAs(other) && (coin.Amount.Equal(other.Amount))
if coin.Denom != other.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
}
return coin.Amount.Equal(other.Amount)
}
// Adds amounts of two coins with same denom. If the coins differ in denom then
// it panics.
func (coin Coin) Plus(coinB Coin) Coin {
if !coin.SameDenomAs(coinB) {
if coin.Denom != coinB.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom))
}
@@ -91,7 +97,7 @@ func (coin Coin) Plus(coinB Coin) Coin {
// Subtracts amounts of two coins with same denom. If the coins differ in denom
// then it panics.
func (coin Coin) Minus(coinB Coin) Coin {
if !coin.SameDenomAs(coinB) {
if coin.Denom != coinB.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom))
}
@@ -273,7 +279,7 @@ func (coins Coins) IsAllGT(coinsB Coins) bool {
return false
}
return diff.IsPositive()
return diff.IsAllPositive()
}
// IsAllGTE returns true iff for every denom in coins, the denom is present at
@@ -339,7 +345,7 @@ func (coins Coins) IsEqual(coinsB Coins) bool {
coinsB = coinsB.Sort()
for i := 0; i < len(coins); i++ {
if coins[i].Denom != coinsB[i].Denom || !coins[i].Amount.Equal(coinsB[i].Amount) {
if !coins[i].IsEqual(coinsB[i]) {
return false
}
}
@@ -354,9 +360,8 @@ func (coins Coins) Empty() bool {
// Returns the amount of a denom from coins
func (coins Coins) AmountOf(denom string) Int {
if strings.ToLower(denom) != denom {
panic(fmt.Sprintf("denom cannot contain upper case characters: %s\n", denom))
}
validateDenom(denom)
switch len(coins) {
case 0:
return ZeroInt()
@@ -382,11 +387,11 @@ func (coins Coins) AmountOf(denom string) Int {
}
}
// IsPositive returns true if there is at least one coin and all currencies
// IsAllPositive returns true if there is at least one coin and all currencies
// have a positive value.
//
// TODO: Remove once unsigned integers are used.
func (coins Coins) IsPositive() bool {
func (coins Coins) IsAllPositive() bool {
if len(coins) == 0 {
return false
}
@@ -403,12 +408,9 @@ func (coins Coins) IsPositive() bool {
// IsAnyNegative returns true if there is at least one coin whose amount
// is negative; returns false otherwise. It returns false if the coin set
// is empty too.
//
// TODO: Remove once unsigned integers are used.
func (coins Coins) IsAnyNegative() bool {
if len(coins) == 0 {
return false
}
for _, coin := range coins {
if coin.IsNegative() {
return true
@@ -485,6 +487,15 @@ var (
reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, reDnm))
)
func validateDenom(denom string) {
if len(denom) < 3 || len(denom) > 16 {
panic(fmt.Sprintf("invalid denom length: %s", denom))
}
if strings.ToLower(denom) != denom {
panic(fmt.Sprintf("denom cannot contain upper case characters: %s", denom))
}
}
// ParseCoin parses a cli input for one coin type, returning errors if invalid.
// This returns an error on an empty string as well.
func ParseCoin(coinStr string) (coin Coin, err error) {
+131 -140
View File
@@ -1,39 +1,28 @@
package types
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
testDenom1 = "atom"
testDenom2 = "muon"
)
// ----------------------------------------------------------------------------
// Coin tests
func TestCoin(t *testing.T) {
require.Panics(t, func() { NewInt64Coin("a", -1) })
require.Panics(t, func() { NewCoin("a", NewInt(-1)) })
require.Panics(t, func() { NewInt64Coin("Atom", 10) })
require.Panics(t, func() { NewCoin("Atom", NewInt(10)) })
require.Equal(t, NewInt(5), NewInt64Coin("a", 5).Amount)
require.Equal(t, NewInt(5), NewCoin("a", NewInt(5)).Amount)
}
func TestSameDenomAsCoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), true},
}
for tcIndex, tc := range cases {
res := tc.inputOne.SameDenomAs(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin denominations didn't match, tc #%d", tcIndex)
}
require.Panics(t, func() { NewInt64Coin(testDenom1, -1) })
require.Panics(t, func() { NewCoin(testDenom1, NewInt(-1)) })
require.Panics(t, func() { NewInt64Coin(strings.ToUpper(testDenom1), 10) })
require.Panics(t, func() { NewCoin(strings.ToUpper(testDenom1), NewInt(10)) })
require.Equal(t, NewInt(5), NewInt64Coin(testDenom1, 5).Amount)
require.Equal(t, NewInt(5), NewCoin(testDenom1, NewInt(5)).Amount)
}
func TestIsEqualCoin(t *testing.T) {
@@ -41,15 +30,20 @@ func TestIsEqualCoin(t *testing.T) {
inputOne Coin
inputTwo Coin
expected bool
panics bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), true, false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom2, 1), false, true},
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), false, false},
}
for tcIndex, tc := range cases {
res := tc.inputOne.IsEqual(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
if tc.panics {
require.Panics(t, func() { tc.inputOne.IsEqual(tc.inputTwo) })
} else {
res := tc.inputOne.IsEqual(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
}
}
}
@@ -60,9 +54,9 @@ func TestPlusCoin(t *testing.T) {
expected Coin
shouldPanic bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), NewInt64Coin("a", 2), false},
{NewInt64Coin("a", 1), NewInt64Coin("a", 0), NewInt64Coin("a", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), NewInt64Coin("a", 1), true},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 2), false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom1, 1), false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom2, 1), NewInt64Coin(testDenom1, 1), true},
}
for tcIndex, tc := range cases {
@@ -82,11 +76,11 @@ func TestMinusCoin(t *testing.T) {
expected Coin
shouldPanic bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 10), NewInt64Coin("a", 1), NewInt64Coin("a", 9), false},
{NewInt64Coin("a", 5), NewInt64Coin("a", 3), NewInt64Coin("a", 2), false},
{NewInt64Coin("a", 5), NewInt64Coin("a", 0), NewInt64Coin("a", 5), false},
{NewInt64Coin("a", 1), NewInt64Coin("a", 5), Coin{}, true},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom2, 1), NewInt64Coin(testDenom1, 1), true},
{NewInt64Coin(testDenom1, 10), NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 9), false},
{NewInt64Coin(testDenom1, 5), NewInt64Coin(testDenom1, 3), NewInt64Coin(testDenom1, 2), false},
{NewInt64Coin(testDenom1, 5), NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom1, 5), false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 5), Coin{}, true},
}
for tcIndex, tc := range cases {
@@ -102,7 +96,7 @@ func TestMinusCoin(t *testing.T) {
inputOne Coin
inputTwo Coin
expected int64
}{NewInt64Coin("a", 1), NewInt64Coin("a", 1), 0}
}{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), 0}
res := tc.inputOne.Minus(tc.inputTwo)
require.Equal(t, tc.expected, res.Amount.Int64())
}
@@ -112,15 +106,20 @@ func TestIsGTECoin(t *testing.T) {
inputOne Coin
inputTwo Coin
expected bool
panics bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 2), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), true, false},
{NewInt64Coin(testDenom1, 2), NewInt64Coin(testDenom1, 1), true, false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom2, 1), false, true},
}
for tcIndex, tc := range cases {
res := tc.inputOne.IsGTE(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin GTE relation is incorrect, tc #%d", tcIndex)
if tc.panics {
require.Panics(t, func() { tc.inputOne.IsGTE(tc.inputTwo) })
} else {
res := tc.inputOne.IsGTE(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin GTE relation is incorrect, tc #%d", tcIndex)
}
}
}
@@ -129,27 +128,32 @@ func TestIsLTCoin(t *testing.T) {
inputOne Coin
inputTwo Coin
expected bool
panics bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
{NewInt64Coin("a", 2), NewInt64Coin("a", 1), false},
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
{NewInt64Coin("a", 1), NewInt64Coin("a", 2), true},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), false, false},
{NewInt64Coin(testDenom1, 2), NewInt64Coin(testDenom1, 1), false, false},
{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1), false, true},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom2, 1), false, true},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), false, false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 2), true, false},
}
for tcIndex, tc := range cases {
res := tc.inputOne.IsLT(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin LT relation is incorrect, tc #%d", tcIndex)
if tc.panics {
require.Panics(t, func() { tc.inputOne.IsLT(tc.inputTwo) })
} else {
res := tc.inputOne.IsLT(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin LT relation is incorrect, tc #%d", tcIndex)
}
}
}
func TestCoinIsZero(t *testing.T) {
coin := NewInt64Coin("a", 0)
coin := NewInt64Coin(testDenom1, 0)
res := coin.IsZero()
require.True(t, res)
coin = NewInt64Coin("a", 1)
coin = NewInt64Coin(testDenom1, 1)
res = coin.IsZero()
require.False(t, res)
}
@@ -163,10 +167,10 @@ func TestIsZeroCoins(t *testing.T) {
expected bool
}{
{Coins{}, true},
{Coins{NewInt64Coin("a", 0)}, true},
{Coins{NewInt64Coin("a", 0), NewInt64Coin("b", 0)}, true},
{Coins{NewInt64Coin("a", 1)}, false},
{Coins{NewInt64Coin("a", 0), NewInt64Coin("b", 1)}, false},
{Coins{NewInt64Coin(testDenom1, 0)}, true},
{Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 0)}, true},
{Coins{NewInt64Coin(testDenom1, 1)}, false},
{Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1)}, false},
}
for _, tc := range cases {
@@ -180,19 +184,24 @@ func TestEqualCoins(t *testing.T) {
inputOne Coins
inputTwo Coins
expected bool
panics bool
}{
{Coins{}, Coins{}, true},
{Coins{NewInt64Coin("a", 0)}, Coins{NewInt64Coin("a", 0)}, true},
{Coins{NewInt64Coin("a", 0), NewInt64Coin("b", 1)}, Coins{NewInt64Coin("a", 0), NewInt64Coin("b", 1)}, true},
{Coins{NewInt64Coin("a", 0)}, Coins{NewInt64Coin("b", 0)}, false},
{Coins{NewInt64Coin("a", 0)}, Coins{NewInt64Coin("a", 1)}, false},
{Coins{NewInt64Coin("a", 0)}, Coins{NewInt64Coin("a", 0), NewInt64Coin("b", 1)}, false},
{Coins{NewInt64Coin("a", 0), NewInt64Coin("b", 1)}, Coins{NewInt64Coin("b", 1), NewInt64Coin("a", 0)}, true},
{Coins{}, Coins{}, true, false},
{Coins{NewInt64Coin(testDenom1, 0)}, Coins{NewInt64Coin(testDenom1, 0)}, true, false},
{Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1)}, Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1)}, true, false},
{Coins{NewInt64Coin(testDenom1, 0)}, Coins{NewInt64Coin(testDenom2, 0)}, false, true},
{Coins{NewInt64Coin(testDenom1, 0)}, Coins{NewInt64Coin(testDenom1, 1)}, false, false},
{Coins{NewInt64Coin(testDenom1, 0)}, Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1)}, false, false},
{Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1)}, Coins{NewInt64Coin(testDenom1, 0), NewInt64Coin(testDenom2, 1)}, true, false},
}
for tcnum, tc := range cases {
res := tc.inputOne.IsEqual(tc.inputTwo)
require.Equal(t, tc.expected, res, "Equality is differed from expected. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res)
if tc.panics {
require.Panics(t, func() { tc.inputOne.IsEqual(tc.inputTwo) })
} else {
res := tc.inputOne.IsEqual(tc.inputTwo)
require.Equal(t, tc.expected, res, "Equality is differed from expected. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res)
}
}
}
@@ -206,11 +215,11 @@ func TestPlusCoins(t *testing.T) {
inputTwo Coins
expected Coins
}{
{Coins{{"a", one}, {"b", one}}, Coins{{"a", one}, {"b", one}}, Coins{{"a", two}, {"b", two}}},
{Coins{{"a", zero}, {"b", one}}, Coins{{"a", zero}, {"b", zero}}, Coins{{"b", one}}},
{Coins{{"a", two}}, Coins{{"b", zero}}, Coins{{"a", two}}},
{Coins{{"a", one}}, Coins{{"a", one}, {"b", two}}, Coins{{"a", two}, {"b", two}}},
{Coins{{"a", zero}, {"b", zero}}, Coins{{"a", zero}, {"b", zero}}, Coins(nil)},
{Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, two}, {testDenom2, two}}},
{Coins{{testDenom1, zero}, {testDenom2, one}}, Coins{{testDenom1, zero}, {testDenom2, zero}}, Coins{{testDenom2, one}}},
{Coins{{testDenom1, two}}, Coins{{testDenom2, zero}}, Coins{{testDenom1, two}}},
{Coins{{testDenom1, one}}, Coins{{testDenom1, one}, {testDenom2, two}}, Coins{{testDenom1, two}, {testDenom2, two}}},
{Coins{{testDenom1, zero}, {testDenom2, zero}}, Coins{{testDenom1, zero}, {testDenom2, zero}}, Coins(nil)},
}
for tcIndex, tc := range cases {
@@ -231,11 +240,11 @@ func TestMinusCoins(t *testing.T) {
expected Coins
shouldPanic bool
}{
{Coins{{"a", two}}, Coins{{"a", one}, {"b", two}}, Coins{{"a", one}, {"b", two}}, true},
{Coins{{"a", two}}, Coins{{"b", zero}}, Coins{{"a", two}}, false},
{Coins{{"a", one}}, Coins{{"b", zero}}, Coins{{"a", one}}, false},
{Coins{{"a", one}, {"b", one}}, Coins{{"a", one}}, Coins{{"b", one}}, false},
{Coins{{"a", one}, {"b", one}}, Coins{{"a", two}}, Coins{}, true},
{Coins{{testDenom1, two}}, Coins{{testDenom1, one}, {testDenom2, two}}, Coins{{testDenom1, one}, {testDenom2, two}}, true},
{Coins{{testDenom1, two}}, Coins{{testDenom2, zero}}, Coins{{testDenom1, two}}, false},
{Coins{{testDenom1, one}}, Coins{{testDenom2, zero}}, Coins{{testDenom1, one}}, false},
{Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, one}}, Coins{{testDenom2, one}}, false},
{Coins{{testDenom1, one}, {testDenom2, one}}, Coins{{testDenom1, two}}, Coins{}, true},
}
for i, tc := range testCases {
@@ -302,8 +311,8 @@ func TestCoins(t *testing.T) {
assert.False(t, mixedCase1.IsValid(), "Coins denoms contain upper case characters")
assert.False(t, mixedCase2.IsValid(), "First Coins denoms contain upper case characters")
assert.False(t, mixedCase3.IsValid(), "Single denom in Coins contains upper case characters")
assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good)
assert.False(t, null.IsPositive(), "Expected coins to not be positive: %v", null)
assert.True(t, good.IsAllPositive(), "Expected coins to be positive: %v", good)
assert.False(t, null.IsAllPositive(), "Expected coins to not be positive: %v", null)
assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty)
assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty)
assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good)
@@ -319,11 +328,11 @@ func TestCoinsGT(t *testing.T) {
two := NewInt(2)
assert.False(t, Coins{}.IsAllGT(Coins{}))
assert.True(t, Coins{{"a", one}}.IsAllGT(Coins{}))
assert.False(t, Coins{{"a", one}}.IsAllGT(Coins{{"a", one}}))
assert.False(t, Coins{{"a", one}}.IsAllGT(Coins{{"b", one}}))
assert.True(t, Coins{{"a", one}, {"b", one}}.IsAllGT(Coins{{"b", one}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllGT(Coins{{"b", two}}))
assert.True(t, Coins{{testDenom1, one}}.IsAllGT(Coins{}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom2, two}}))
}
func TestCoinsGTE(t *testing.T) {
@@ -331,11 +340,11 @@ func TestCoinsGTE(t *testing.T) {
two := NewInt(2)
assert.True(t, Coins{}.IsAllGTE(Coins{}))
assert.True(t, Coins{{"a", one}}.IsAllGTE(Coins{}))
assert.True(t, Coins{{"a", one}}.IsAllGTE(Coins{{"a", one}}))
assert.False(t, Coins{{"a", one}}.IsAllGTE(Coins{{"b", one}}))
assert.True(t, Coins{{"a", one}, {"b", one}}.IsAllGTE(Coins{{"b", one}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllGTE(Coins{{"b", two}}))
assert.True(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{}))
assert.True(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom2, two}}))
}
func TestCoinsLT(t *testing.T) {
@@ -343,14 +352,14 @@ func TestCoinsLT(t *testing.T) {
two := NewInt(2)
assert.False(t, Coins{}.IsAllLT(Coins{}))
assert.False(t, Coins{{"a", one}}.IsAllLT(Coins{}))
assert.False(t, Coins{{"a", one}}.IsAllLT(Coins{{"a", one}}))
assert.False(t, Coins{{"a", one}}.IsAllLT(Coins{{"b", one}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllLT(Coins{{"b", one}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllLT(Coins{{"b", two}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllLT(Coins{{"a", one}, {"b", one}}))
assert.True(t, Coins{{"a", one}, {"b", one}}.IsAllLT(Coins{{"a", one}, {"b", two}}))
assert.True(t, Coins{}.IsAllLT(Coins{{"a", one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllLT(Coins{}))
assert.False(t, Coins{{testDenom1, one}}.IsAllLT(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllLT(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom2, two}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, one}, {testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLT(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.True(t, Coins{}.IsAllLT(Coins{{testDenom1, one}}))
}
func TestCoinsLTE(t *testing.T) {
@@ -358,14 +367,14 @@ func TestCoinsLTE(t *testing.T) {
two := NewInt(2)
assert.True(t, Coins{}.IsAllLTE(Coins{}))
assert.False(t, Coins{{"a", one}}.IsAllLTE(Coins{}))
assert.True(t, Coins{{"a", one}}.IsAllLTE(Coins{{"a", one}}))
assert.False(t, Coins{{"a", one}}.IsAllLTE(Coins{{"b", one}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllLTE(Coins{{"b", one}}))
assert.False(t, Coins{{"a", one}, {"b", one}}.IsAllLTE(Coins{{"b", two}}))
assert.True(t, Coins{{"a", one}, {"b", one}}.IsAllLTE(Coins{{"a", one}, {"b", one}}))
assert.True(t, Coins{{"a", one}, {"b", one}}.IsAllLTE(Coins{{"a", one}, {"b", two}}))
assert.True(t, Coins{}.IsAllLTE(Coins{{"a", one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllLTE(Coins{}))
assert.True(t, Coins{{testDenom1, one}}.IsAllLTE(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllLTE(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom2, two}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom1, one}, {testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllLTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.True(t, Coins{}.IsAllLTE(Coins{{testDenom1, one}}))
}
func TestParse(t *testing.T) {
@@ -452,30 +461,18 @@ func TestSortCoins(t *testing.T) {
func TestAmountOf(t *testing.T) {
case0 := Coins{}
case1 := Coins{
NewInt64Coin("", 0),
}
case2 := Coins{
NewInt64Coin(" ", 0),
}
case3 := Coins{
NewInt64Coin("gold", 0),
}
case4 := Coins{
case2 := Coins{
NewInt64Coin("gas", 1),
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
}
case5 := Coins{
case3 := Coins{
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
}
case6 := Coins{
NewInt64Coin("", 6),
}
case7 := Coins{
NewInt64Coin(" ", 7),
}
case8 := Coins{
case4 := Coins{
NewInt64Coin("gas", 8),
}
@@ -489,18 +486,12 @@ func TestAmountOf(t *testing.T) {
}{
{case0, 0, 0, 0, 0, 0},
{case1, 0, 0, 0, 0, 0},
{case2, 0, 0, 0, 0, 0},
{case3, 0, 0, 0, 0, 0},
{case4, 0, 0, 1, 1, 1},
{case5, 0, 0, 0, 1, 1},
{case6, 6, 0, 0, 0, 0},
{case7, 0, 7, 0, 0, 0},
{case8, 0, 0, 8, 0, 0},
{case2, 0, 0, 1, 1, 1},
{case3, 0, 0, 0, 1, 1},
{case4, 0, 0, 8, 0, 0},
}
for _, tc := range cases {
assert.Equal(t, NewInt(tc.amountOf), tc.coins.AmountOf(""))
assert.Equal(t, NewInt(tc.amountOfSpace), tc.coins.AmountOf(" "))
assert.Equal(t, NewInt(tc.amountOfGAS), tc.coins.AmountOf("gas"))
assert.Equal(t, NewInt(tc.amountOfMINERAL), tc.coins.AmountOf("mineral"))
assert.Equal(t, NewInt(tc.amountOfTREE), tc.coins.AmountOf("tree"))
@@ -514,17 +505,17 @@ func TestCoinsIsAnyGTE(t *testing.T) {
two := NewInt(2)
assert.False(t, Coins{}.IsAnyGTE(Coins{}))
assert.False(t, Coins{{"a", one}}.IsAnyGTE(Coins{}))
assert.False(t, Coins{}.IsAnyGTE(Coins{{"a", one}}))
assert.False(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"a", two}}))
assert.False(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"b", one}}))
assert.True(t, Coins{{"a", one}, {"b", two}}.IsAnyGTE(Coins{{"a", two}, {"b", one}}))
assert.True(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"a", one}}))
assert.True(t, Coins{{"a", two}}.IsAnyGTE(Coins{{"a", one}}))
assert.True(t, Coins{{"a", one}}.IsAnyGTE(Coins{{"a", one}, {"b", two}}))
assert.True(t, Coins{{"b", two}}.IsAnyGTE(Coins{{"a", one}, {"b", two}}))
assert.False(t, Coins{{"b", one}}.IsAnyGTE(Coins{{"a", one}, {"b", two}}))
assert.True(t, Coins{{"a", one}, {"b", two}}.IsAnyGTE(Coins{{"a", one}, {"b", one}}))
assert.True(t, Coins{{"a", one}, {"b", one}}.IsAnyGTE(Coins{{"a", one}, {"b", two}}))
assert.True(t, Coins{{"x", one}, {"y", one}}.IsAnyGTE(Coins{{"b", one}, {"c", one}, {"y", one}, {"z", one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{}))
assert.False(t, Coins{}.IsAnyGTE(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom1, two}}))
assert.False(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(Coins{{testDenom1, two}, {testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom1, one}}))
assert.True(t, Coins{{testDenom1, two}}.IsAnyGTE(Coins{{testDenom1, one}}))
assert.True(t, Coins{{testDenom1, one}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.True(t, Coins{{testDenom2, two}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{testDenom2, one}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAnyGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.True(t, Coins{{"xxx", one}, {"yyy", one}}.IsAnyGTE(Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
}
+1 -1
View File
@@ -163,7 +163,7 @@ func TestContextWithCustom(t *testing.T) {
logger := NewMockLogger()
voteinfos := []abci.VoteInfo{{}}
meter := types.NewGasMeter(10000)
minGasPrices := types.DecCoins{types.NewDecCoin("feetoken", 1)}
minGasPrices := types.DecCoins{types.NewInt64DecCoin("feetoken", 1)}
ctx = types.NewContext(nil, header, ischeck, logger)
require.Equal(t, header, ctx.BlockHeader())
+191 -36
View File
@@ -18,27 +18,25 @@ type DecCoin struct {
Amount Dec `json:"amount"`
}
func NewDecCoin(denom string, amount int64) DecCoin {
if amount < 0 {
panic(fmt.Sprintf("negative decimal coin amount: %v\n", amount))
}
if strings.ToLower(denom) != denom {
panic(fmt.Sprintf("denom cannot contain upper case characters: %s\n", denom))
func NewDecCoin(denom string, amount Int) DecCoin {
validateDenom(denom)
if amount.LT(ZeroInt()) {
panic(fmt.Sprintf("negative coin amount: %v\n", amount))
}
return DecCoin{
Denom: denom,
Amount: NewDec(amount),
Amount: NewDecFromInt(amount),
}
}
func NewDecCoinFromDec(denom string, amount Dec) DecCoin {
validateDenom(denom)
if amount.LT(ZeroDec()) {
panic(fmt.Sprintf("negative decimal coin amount: %v\n", amount))
}
if strings.ToLower(denom) != denom {
panic(fmt.Sprintf("denom cannot contain upper case characters: %s\n", denom))
}
return DecCoin{
Denom: denom,
@@ -60,6 +58,46 @@ func NewDecCoinFromCoin(coin Coin) DecCoin {
}
}
// NewInt64DecCoin returns a new DecCoin with a denomination and amount. It will
// panic if the amount is negative or denom is invalid.
func NewInt64DecCoin(denom string, amount int64) DecCoin {
return NewDecCoin(denom, NewInt(amount))
}
// IsZero returns if the DecCoin amount is zero.
func (coin DecCoin) IsZero() bool {
return coin.Amount.IsZero()
}
// IsGTE returns true if they are the same type and the receiver is
// an equal or greater value.
func (coin DecCoin) IsGTE(other DecCoin) bool {
if coin.Denom != other.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
}
return !coin.Amount.LT(other.Amount)
}
// IsLT returns true if they are the same type and the receiver is
// a smaller value.
func (coin DecCoin) IsLT(other DecCoin) bool {
if coin.Denom != other.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
}
return coin.Amount.LT(other.Amount)
}
// IsEqual returns true if the two sets of Coins have the same value.
func (coin DecCoin) IsEqual(other DecCoin) bool {
if coin.Denom != other.Denom {
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
}
return coin.Amount.Equal(other.Amount)
}
// Adds amounts of two coins with same denom
func (coin DecCoin) Plus(coinB DecCoin) DecCoin {
if coin.Denom != coinB.Denom {
@@ -90,6 +128,13 @@ func (coin DecCoin) IsPositive() bool {
return coin.Amount.IsPositive()
}
// IsNegative returns true if the coin amount is negative and false otherwise.
//
// TODO: Remove once unsigned integers are used.
func (coin DecCoin) IsNegative() bool {
return coin.Amount.Sign() == -1
}
// String implements the Stringer interface for DecCoin. It returns a
// human-readable representation of a decimal coin.
func (coin DecCoin) String() string {
@@ -125,55 +170,87 @@ func (coins DecCoins) String() string {
return out[:len(out)-1]
}
// return the coins with trunctated decimals, and return the change
// TruncateDecimal returns the coins with truncated decimals and returns the
// change.
func (coins DecCoins) TruncateDecimal() (Coins, DecCoins) {
changeSum := DecCoins{}
out := make(Coins, len(coins))
for i, coin := range coins {
truncated, change := coin.TruncateDecimal()
out[i] = truncated
changeSum = changeSum.Plus(DecCoins{change})
}
return out, changeSum
}
// Plus combines two sets of coins
// CONTRACT: Plus will never return Coins where one Coin has a 0 amount.
// Plus adds two sets of DecCoins.
//
// NOTE: Plus operates under the invariant that coins are sorted by
// denominations.
//
// CONTRACT: Plus will never return Coins where one Coin has a non-positive
// amount. In otherwords, IsValid will always return true.
func (coins DecCoins) Plus(coinsB DecCoins) DecCoins {
return coins.safePlus(coinsB)
}
// safePlus will perform addition of two DecCoins sets. If both coin sets are
// empty, then an empty set is returned. If only a single set is empty, the
// other set is returned. Otherwise, the coins are compared in order of their
// denomination and addition only occurs when the denominations match, otherwise
// the coin is simply added to the sum assuming it's not zero.
func (coins DecCoins) safePlus(coinsB DecCoins) DecCoins {
sum := ([]DecCoin)(nil)
indexA, indexB := 0, 0
lenA, lenB := len(coins), len(coinsB)
for {
if indexA == lenA {
if indexB == lenB {
// return nil coins if both sets are empty
return sum
}
return append(sum, coinsB[indexB:]...)
// return set B (excluding zero coins) if set A is empty
return append(sum, removeZeroDecCoins(coinsB[indexB:])...)
} else if indexB == lenB {
return append(sum, coins[indexA:]...)
// return set A (excluding zero coins) if set B is empty
return append(sum, removeZeroDecCoins(coins[indexA:])...)
}
coinA, coinB := coins[indexA], coinsB[indexB]
switch strings.Compare(coinA.Denom, coinB.Denom) {
case -1:
sum = append(sum, coinA)
indexA++
case 0:
if coinA.Amount.Add(coinB.Amount).IsZero() {
// ignore 0 sum coin type
} else {
sum = append(sum, coinA.Plus(coinB))
case -1: // coin A denom < coin B denom
if !coinA.IsZero() {
sum = append(sum, coinA)
}
indexA++
case 0: // coin A denom == coin B denom
res := coinA.Plus(coinB)
if !res.IsZero() {
sum = append(sum, res)
}
indexA++
indexB++
case 1:
sum = append(sum, coinB)
case 1: // coin A denom > coin B denom
if !coinB.IsZero() {
sum = append(sum, coinB)
}
indexB++
}
}
}
// Negative returns a set of coins with all amount negative
func (coins DecCoins) Negative() DecCoins {
// negative returns a set of coins with all amount negative.
func (coins DecCoins) negative() DecCoins {
res := make([]DecCoin, 0, len(coins))
for _, coin := range coins {
res = append(res, DecCoin{
@@ -184,9 +261,36 @@ func (coins DecCoins) Negative() DecCoins {
return res
}
// Minus subtracts a set of coins from another (adds the inverse)
// Minus subtracts a set of DecCoins from another (adds the inverse).
func (coins DecCoins) Minus(coinsB DecCoins) DecCoins {
return coins.Plus(coinsB.Negative())
diff, hasNeg := coins.SafeMinus(coinsB)
if hasNeg {
panic("negative coin amount")
}
return diff
}
// SafeMinus performs the same arithmetic as Minus but returns a boolean if any
// negative coin amount was returned.
func (coins DecCoins) SafeMinus(coinsB DecCoins) (DecCoins, bool) {
diff := coins.safePlus(coinsB.negative())
return diff, diff.IsAnyNegative()
}
// IsAnyNegative returns true if there is at least one coin whose amount
// is negative; returns false otherwise. It returns false if the DecCoins set
// is empty too.
//
// TODO: Remove once unsigned integers are used.
func (coins DecCoins) IsAnyNegative() bool {
for _, coin := range coins {
if coin.IsNegative() {
return true
}
}
return false
}
// multiply all the coins by a decimal
@@ -241,20 +345,30 @@ func (coins DecCoins) QuoDecTruncate(d Dec) DecCoins {
return res
}
// Empty returns true if there are no coins and false otherwise.
func (coins DecCoins) Empty() bool {
return len(coins) == 0
}
// returns the amount of a denom from deccoins
func (coins DecCoins) AmountOf(denom string) Dec {
validateDenom(denom)
switch len(coins) {
case 0:
return ZeroDec()
case 1:
coin := coins[0]
if coin.Denom == denom {
return coin.Amount
}
return ZeroDec()
default:
midIdx := len(coins) / 2 // binary search
midIdx := len(coins) / 2 // 2:1, 3:1, 4:2
coin := coins[midIdx]
if denom < coin.Denom {
return coins[:midIdx].AmountOf(denom)
} else if denom == coin.Denom {
@@ -265,14 +379,22 @@ func (coins DecCoins) AmountOf(denom string) Dec {
}
}
// has a negative DecCoin amount
func (coins DecCoins) HasNegative() bool {
for _, coin := range coins {
if coin.Amount.IsNegative() {
return true
// IsEqual returns true if the two sets of DecCoins have the same value.
func (coins DecCoins) IsEqual(coinsB DecCoins) bool {
if len(coins) != len(coinsB) {
return false
}
coins = coins.Sort()
coinsB = coinsB.Sort()
for i := 0; i < len(coins); i++ {
if !coins[i].IsEqual(coinsB[i]) {
return false
}
}
return false
return true
}
// return whether all coins are zero
@@ -324,6 +446,39 @@ func (coins DecCoins) IsValid() bool {
}
}
// IsAllPositive returns true if there is at least one coin and all currencies
// have a positive value.
//
// TODO: Remove once unsigned integers are used.
func (coins DecCoins) IsAllPositive() bool {
if len(coins) == 0 {
return false
}
for _, coin := range coins {
if !coin.IsPositive() {
return false
}
}
return true
}
func removeZeroDecCoins(coins DecCoins) DecCoins {
i, l := 0, len(coins)
for i < l {
if coins[i].IsZero() {
// remove coin
coins = append(coins[:i], coins[i+1:]...)
l--
} else {
i++
}
}
return coins[:i]
}
//-----------------------------------------------------------------------------
// Sorting
+45 -44
View File
@@ -1,6 +1,7 @@
package types
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
@@ -8,61 +9,61 @@ import (
func TestNewDecCoin(t *testing.T) {
require.NotPanics(t, func() {
NewDecCoin("a", 5)
NewInt64DecCoin(testDenom1, 5)
})
require.NotPanics(t, func() {
NewDecCoin("a", 0)
NewInt64DecCoin(testDenom1, 0)
})
require.Panics(t, func() {
NewDecCoin("A", 5)
NewInt64DecCoin(strings.ToUpper(testDenom1), 5)
})
require.Panics(t, func() {
NewDecCoin("a", -5)
NewInt64DecCoin(testDenom1, -5)
})
}
func TestNewDecCoinFromDec(t *testing.T) {
require.NotPanics(t, func() {
NewDecCoinFromDec("a", NewDec(5))
NewDecCoinFromDec(testDenom1, NewDec(5))
})
require.NotPanics(t, func() {
NewDecCoinFromDec("a", ZeroDec())
NewDecCoinFromDec(testDenom1, ZeroDec())
})
require.Panics(t, func() {
NewDecCoinFromDec("A", NewDec(5))
NewDecCoinFromDec(strings.ToUpper(testDenom1), NewDec(5))
})
require.Panics(t, func() {
NewDecCoinFromDec("a", NewDec(-5))
NewDecCoinFromDec(testDenom1, NewDec(-5))
})
}
func TestNewDecCoinFromCoin(t *testing.T) {
require.NotPanics(t, func() {
NewDecCoinFromCoin(Coin{"a", NewInt(5)})
NewDecCoinFromCoin(Coin{testDenom1, NewInt(5)})
})
require.NotPanics(t, func() {
NewDecCoinFromCoin(Coin{"a", NewInt(0)})
NewDecCoinFromCoin(Coin{testDenom1, NewInt(0)})
})
require.Panics(t, func() {
NewDecCoinFromCoin(Coin{"A", NewInt(5)})
NewDecCoinFromCoin(Coin{strings.ToUpper(testDenom1), NewInt(5)})
})
require.Panics(t, func() {
NewDecCoinFromCoin(Coin{"a", NewInt(-5)})
NewDecCoinFromCoin(Coin{testDenom1, NewInt(-5)})
})
}
func TestDecCoinIsPositive(t *testing.T) {
dc := NewDecCoin("a", 5)
dc := NewInt64DecCoin(testDenom1, 5)
require.True(t, dc.IsPositive())
dc = NewDecCoin("a", 0)
dc = NewInt64DecCoin(testDenom1, 0)
require.False(t, dc.IsPositive())
}
func TestPlusDecCoin(t *testing.T) {
decCoinA1 := NewDecCoinFromDec("a", NewDecWithPrec(11, 1))
decCoinA2 := NewDecCoinFromDec("a", NewDecWithPrec(22, 1))
decCoinB1 := NewDecCoinFromDec("b", NewDecWithPrec(11, 1))
decCoinA1 := NewDecCoinFromDec(testDenom1, NewDecWithPrec(11, 1))
decCoinA2 := NewDecCoinFromDec(testDenom1, NewDecWithPrec(22, 1))
decCoinB1 := NewDecCoinFromDec(testDenom2, NewDecWithPrec(11, 1))
// regular add
res := decCoinA1.Plus(decCoinA1)
@@ -84,9 +85,9 @@ func TestPlusDecCoins(t *testing.T) {
inputTwo DecCoins
expected DecCoins
}{
{DecCoins{{"a", one}, {"b", one}}, DecCoins{{"a", one}, {"b", one}}, DecCoins{{"a", two}, {"b", two}}},
{DecCoins{{"a", zero}, {"b", one}}, DecCoins{{"a", zero}, {"b", zero}}, DecCoins{{"b", one}}},
{DecCoins{{"a", zero}, {"b", zero}}, DecCoins{{"a", zero}, {"b", zero}}, DecCoins(nil)},
{DecCoins{{testDenom1, one}, {testDenom2, one}}, DecCoins{{testDenom1, one}, {testDenom2, one}}, DecCoins{{testDenom1, two}, {testDenom2, two}}},
{DecCoins{{testDenom1, zero}, {testDenom2, one}}, DecCoins{{testDenom1, zero}, {testDenom2, zero}}, DecCoins{{testDenom2, one}}},
{DecCoins{{testDenom1, zero}, {testDenom2, zero}}, DecCoins{{testDenom1, zero}, {testDenom2, zero}}, DecCoins(nil)},
}
for tcIndex, tc := range cases {
@@ -97,32 +98,32 @@ func TestPlusDecCoins(t *testing.T) {
func TestSortDecCoins(t *testing.T) {
good := DecCoins{
NewDecCoin("gas", 1),
NewDecCoin("mineral", 1),
NewDecCoin("tree", 1),
NewInt64DecCoin("gas", 1),
NewInt64DecCoin("mineral", 1),
NewInt64DecCoin("tree", 1),
}
empty := DecCoins{
NewDecCoin("gold", 0),
NewInt64DecCoin("gold", 0),
}
badSort1 := DecCoins{
NewDecCoin("tree", 1),
NewDecCoin("gas", 1),
NewDecCoin("mineral", 1),
NewInt64DecCoin("tree", 1),
NewInt64DecCoin("gas", 1),
NewInt64DecCoin("mineral", 1),
}
badSort2 := DecCoins{ // both are after the first one, but the second and third are in the wrong order
NewDecCoin("gas", 1),
NewDecCoin("tree", 1),
NewDecCoin("mineral", 1),
NewInt64DecCoin("gas", 1),
NewInt64DecCoin("tree", 1),
NewInt64DecCoin("mineral", 1),
}
badAmt := DecCoins{
NewDecCoin("gas", 1),
NewDecCoin("tree", 0),
NewDecCoin("mineral", 1),
NewInt64DecCoin("gas", 1),
NewInt64DecCoin("tree", 0),
NewInt64DecCoin("mineral", 1),
}
dup := DecCoins{
NewDecCoin("gas", 1),
NewDecCoin("gas", 1),
NewDecCoin("mineral", 1),
NewInt64DecCoin("gas", 1),
NewInt64DecCoin("gas", 1),
NewInt64DecCoin("mineral", 1),
}
cases := []struct {
@@ -150,14 +151,14 @@ func TestDecCoinsIsValid(t *testing.T) {
expected bool
}{
{DecCoins{}, true},
{DecCoins{DecCoin{"a", NewDec(5)}}, true},
{DecCoins{DecCoin{"a", NewDec(5)}, DecCoin{"b", NewDec(100000)}}, true},
{DecCoins{DecCoin{"a", NewDec(-5)}}, false},
{DecCoins{DecCoin{"A", NewDec(5)}}, false},
{DecCoins{DecCoin{"a", NewDec(5)}, DecCoin{"B", NewDec(100000)}}, false},
{DecCoins{DecCoin{"a", NewDec(5)}, DecCoin{"b", NewDec(-100000)}}, false},
{DecCoins{DecCoin{"a", NewDec(-5)}, DecCoin{"b", NewDec(100000)}}, false},
{DecCoins{DecCoin{"A", NewDec(5)}, DecCoin{"b", NewDec(100000)}}, false},
{DecCoins{DecCoin{testDenom1, NewDec(5)}}, true},
{DecCoins{DecCoin{testDenom1, NewDec(5)}, DecCoin{testDenom2, NewDec(100000)}}, true},
{DecCoins{DecCoin{testDenom1, NewDec(-5)}}, false},
{DecCoins{DecCoin{"AAA", NewDec(5)}}, false},
{DecCoins{DecCoin{testDenom1, NewDec(5)}, DecCoin{"B", NewDec(100000)}}, false},
{DecCoins{DecCoin{testDenom1, NewDec(5)}, DecCoin{testDenom2, NewDec(-100000)}}, false},
{DecCoins{DecCoin{testDenom1, NewDec(-5)}, DecCoin{testDenom2, NewDec(100000)}}, false},
{DecCoins{DecCoin{"AAA", NewDec(5)}, DecCoin{testDenom2, NewDec(100000)}}, false},
}
for i, tc := range testCases {