cosmos-sdk/types/coin_test.go

678 lines
23 KiB
Go

package types
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
)
var (
testDenom1 = "atom"
testDenom2 = "muon"
)
// ----------------------------------------------------------------------------
// Coin tests
func TestCoin(t *testing.T) {
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) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
panics bool
}{
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), true, false},
{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom2, 1), false, true},
{NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), false, false},
}
for tcIndex, tc := range cases {
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)
}
}
}
func TestCoinIsValid(t *testing.T) {
cases := []struct {
coin Coin
expectPass bool
}{
{Coin{testDenom1, NewInt(-1)}, false},
{Coin{testDenom1, NewInt(0)}, true},
{Coin{testDenom1, NewInt(1)}, true},
{Coin{"Atom", NewInt(1)}, false},
{Coin{"a", NewInt(1)}, false},
{Coin{"a very long coin denom", NewInt(1)}, false},
{Coin{"atOm", NewInt(1)}, false},
{Coin{" ", NewInt(1)}, false},
}
for i, tc := range cases {
require.Equal(t, tc.expectPass, tc.coin.IsValid(), "unexpected result for IsValid, tc #%d", i)
}
}
func TestAddCoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected Coin
shouldPanic bool
}{
{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 {
if tc.shouldPanic {
require.Panics(t, func() { tc.inputOne.Add(tc.inputTwo) })
} else {
res := tc.inputOne.Add(tc.inputTwo)
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
}
}
}
func TestSubCoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected Coin
shouldPanic bool
}{
{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 {
if tc.shouldPanic {
require.Panics(t, func() { tc.inputOne.Sub(tc.inputTwo) })
} else {
res := tc.inputOne.Sub(tc.inputTwo)
require.Equal(t, tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
}
}
tc := struct {
inputOne Coin
inputTwo Coin
expected int64
}{NewInt64Coin(testDenom1, 1), NewInt64Coin(testDenom1, 1), 0}
res := tc.inputOne.Sub(tc.inputTwo)
require.Equal(t, tc.expected, res.Amount.Int64())
}
func TestIsGTECoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
panics bool
}{
{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 {
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)
}
}
}
func TestIsLTCoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
panics bool
}{
{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 {
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(testDenom1, 0)
res := coin.IsZero()
require.True(t, res)
coin = NewInt64Coin(testDenom1, 1)
res = coin.IsZero()
require.False(t, res)
}
// ----------------------------------------------------------------------------
// Coins tests
func TestIsZeroCoins(t *testing.T) {
cases := []struct {
inputOne Coins
expected bool
}{
{Coins{}, true},
{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 {
res := tc.inputOne.IsZero()
require.Equal(t, tc.expected, res)
}
}
func TestEqualCoins(t *testing.T) {
cases := []struct {
inputOne Coins
inputTwo Coins
expected bool
panics bool
}{
{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 {
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 exported. tc #%d, expected %b, actual %b.", tcnum, tc.expected, res)
}
}
}
func TestAddCoins(t *testing.T) {
zero := NewInt(0)
one := NewInt(1)
two := NewInt(2)
cases := []struct {
inputOne Coins
inputTwo Coins
expected Coins
}{
{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 {
res := tc.inputOne.Add(tc.inputTwo)
assert.True(t, res.IsValid())
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
}
}
func TestSubCoins(t *testing.T) {
zero := NewInt(0)
one := NewInt(1)
two := NewInt(2)
testCases := []struct {
inputOne Coins
inputTwo Coins
expected Coins
shouldPanic bool
}{
{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 {
if tc.shouldPanic {
require.Panics(t, func() { tc.inputOne.Sub(tc.inputTwo) })
} else {
res := tc.inputOne.Sub(tc.inputTwo)
assert.True(t, res.IsValid())
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", i)
}
}
}
func TestCoins(t *testing.T) {
good := Coins{
{"gas", NewInt(1)},
{"mineral", NewInt(1)},
{"tree", NewInt(1)},
}
mixedCase1 := Coins{
{"gAs", NewInt(1)},
{"MineraL", NewInt(1)},
{"TREE", NewInt(1)},
}
mixedCase2 := Coins{
{"gAs", NewInt(1)},
{"mineral", NewInt(1)},
}
mixedCase3 := Coins{
{"gAs", NewInt(1)},
}
empty := NewCoins()
badSort1 := Coins{
{"tree", NewInt(1)},
{"gas", NewInt(1)},
{"mineral", NewInt(1)},
}
// both are after the first one, but the second and third are in the wrong order
badSort2 := Coins{
{"gas", NewInt(1)},
{"tree", NewInt(1)},
{"mineral", NewInt(1)},
}
badAmt := Coins{
{"gas", NewInt(1)},
{"tree", NewInt(0)},
{"mineral", NewInt(1)},
}
dup := Coins{
{"gas", NewInt(1)},
{"gas", NewInt(1)},
{"mineral", NewInt(1)},
}
neg := Coins{
{"gas", NewInt(-1)},
{"mineral", NewInt(1)},
}
assert.True(t, good.IsValid(), "Coins are valid")
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.IsAllPositive(), "Expected coins to be positive: %v", good)
assert.False(t, empty.IsAllPositive(), "Expected coins to not be positive: %v", empty)
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)
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
assert.False(t, badSort2.IsValid(), "Coins are not sorted")
assert.False(t, badAmt.IsValid(), "Coins cannot include 0 amounts")
assert.False(t, dup.IsValid(), "Duplicate coin")
assert.False(t, neg.IsValid(), "Negative first-denom coin")
}
func TestCoinsGT(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.False(t, Coins{}.IsAllGT(Coins{}))
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, two}}.IsAllGT(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom2, two}}))
}
func TestCoinsLT(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.False(t, Coins{}.IsAllLT(Coins{}))
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, two}, {testDenom2, two}}))
assert.True(t, Coins{}.IsAllLT(Coins{{testDenom1, one}}))
}
func TestCoinsLTE(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.True(t, Coins{}.IsAllLTE(Coins{}))
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) {
one := NewInt(1)
cases := []struct {
input string
valid bool // if false, we expect an error on parse
expected Coins // if valid is true, make sure this is returned
}{
{"", true, nil},
{"1foo", true, Coins{{"foo", one}}},
{"10bar", true, Coins{{"bar", NewInt(10)}}},
{"99bar,1foo", true, Coins{{"bar", NewInt(99)}, {"foo", one}}},
{"98 bar , 1 foo ", true, Coins{{"bar", NewInt(98)}, {"foo", one}}},
{" 55\t \t bling\n", true, Coins{{"bling", NewInt(55)}}},
{"2foo, 97 bar", true, Coins{{"bar", NewInt(97)}, {"foo", NewInt(2)}}},
{"5 mycoin,", false, nil}, // no empty coins in a list
{"2 3foo, 97 bar", false, nil}, // 3foo is invalid coin name
{"11me coin, 12you coin", false, nil}, // no spaces in coin names
{"1.2btc", false, nil}, // amount must be integer
{"5foo-bar", false, nil}, // once more, only letters in coin name
}
for tcIndex, tc := range cases {
res, err := ParseCoins(tc.input)
if !tc.valid {
require.NotNil(t, err, "%s: %#v. tc #%d", tc.input, res, tcIndex)
} else if assert.Nil(t, err, "%s: %+v", tc.input, err) {
require.Equal(t, tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
}
}
}
func TestSortCoins(t *testing.T) {
good := Coins{
NewInt64Coin("gas", 1),
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
}
empty := Coins{
NewInt64Coin("gold", 0),
}
badSort1 := Coins{
NewInt64Coin("tree", 1),
NewInt64Coin("gas", 1),
NewInt64Coin("mineral", 1),
}
badSort2 := Coins{ // both are after the first one, but the second and third are in the wrong order
NewInt64Coin("gas", 1),
NewInt64Coin("tree", 1),
NewInt64Coin("mineral", 1),
}
badAmt := Coins{
NewInt64Coin("gas", 1),
NewInt64Coin("tree", 0),
NewInt64Coin("mineral", 1),
}
dup := Coins{
NewInt64Coin("gas", 1),
NewInt64Coin("gas", 1),
NewInt64Coin("mineral", 1),
}
cases := []struct {
coins Coins
before, after bool // valid before/after sort
}{
{good, true, true},
{empty, false, false},
{badSort1, false, true},
{badSort2, false, true},
{badAmt, false, false},
{dup, false, false},
}
for tcIndex, tc := range cases {
require.Equal(t, tc.before, tc.coins.IsValid(), "coin validity is incorrect before sorting, tc #%d", tcIndex)
tc.coins.Sort()
require.Equal(t, tc.after, tc.coins.IsValid(), "coin validity is incorrect after sorting, tc #%d", tcIndex)
}
}
func TestAmountOf(t *testing.T) {
case0 := Coins{}
case1 := Coins{
NewInt64Coin("gold", 0),
}
case2 := Coins{
NewInt64Coin("gas", 1),
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
}
case3 := Coins{
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
}
case4 := Coins{
NewInt64Coin("gas", 8),
}
cases := []struct {
coins Coins
amountOf int64
amountOfSpace int64
amountOfGAS int64
amountOfMINERAL int64
amountOfTREE int64
}{
{case0, 0, 0, 0, 0, 0},
{case1, 0, 0, 0, 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.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"))
}
assert.Panics(t, func() { cases[0].coins.AmountOf("Invalid") })
}
func TestCoinsIsAnyGTE(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.False(t, Coins{}.IsAnyGTE(Coins{}))
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}}))
}
func TestCoinsIsAllGT(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.False(t, Coins{}.IsAllGT(Coins{}))
assert.True(t, Coins{{testDenom1, one}}.IsAllGT(Coins{}))
assert.False(t, Coins{}.IsAllGT(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, two}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(Coins{{testDenom1, two}, {testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}}))
assert.True(t, Coins{{testDenom1, two}}.IsAllGT(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{testDenom2, two}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{testDenom2, one}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGT(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{"xxx", one}, {"yyy", one}}.IsAllGT(Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
}
func TestCoinsIsAllGTE(t *testing.T) {
one := NewInt(1)
two := NewInt(2)
assert.True(t, Coins{}.IsAllGTE(Coins{}))
assert.True(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom2, two}}))
assert.False(t, Coins{}.IsAllGTE(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, two}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(Coins{{testDenom1, two}, {testDenom2, one}}))
assert.True(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, one}}))
assert.True(t, Coins{{testDenom1, two}}.IsAllGTE(Coins{{testDenom1, one}}))
assert.False(t, Coins{{testDenom1, one}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{testDenom2, two}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{testDenom2, one}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.True(t, Coins{{testDenom1, one}, {testDenom2, two}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, one}}))
assert.False(t, Coins{{testDenom1, one}, {testDenom2, one}}.IsAllGTE(Coins{{testDenom1, one}, {testDenom2, two}}))
assert.False(t, Coins{{"xxx", one}, {"yyy", one}}.IsAllGTE(Coins{{testDenom2, one}, {"ccc", one}, {"yyy", one}, {"zzz", one}}))
}
func TestNewCoins(t *testing.T) {
tenatom := NewInt64Coin("atom", 10)
tenbtc := NewInt64Coin("btc", 10)
zeroeth := NewInt64Coin("eth", 0)
tests := []struct {
name string
coins Coins
want Coins
wantPanic bool
}{
{"empty args", []Coin{}, Coins{}, false},
{"one coin", []Coin{tenatom}, Coins{tenatom}, false},
{"sort after create", []Coin{tenbtc, tenatom}, Coins{tenatom, tenbtc}, false},
{"sort and remove zeroes", []Coin{zeroeth, tenbtc, tenatom}, Coins{tenatom, tenbtc}, false},
{"panic on dups", []Coin{tenatom, tenatom}, Coins{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.wantPanic {
require.Panics(t, func() { NewCoins(tt.coins...) })
return
}
got := NewCoins(tt.coins...)
require.True(t, got.IsEqual(tt.want))
})
}
}
func TestCoinsIsAnyGT(t *testing.T) {
twoAtom := NewInt64Coin("atom", 2)
fiveAtom := NewInt64Coin("atom", 5)
threeEth := NewInt64Coin("eth", 3)
sixEth := NewInt64Coin("eth", 6)
twoBtc := NewInt64Coin("btc", 2)
require.False(t, Coins{}.IsAnyGT(Coins{}))
require.False(t, Coins{fiveAtom}.IsAnyGT(Coins{}))
require.False(t, Coins{}.IsAnyGT(Coins{fiveAtom}))
require.True(t, Coins{fiveAtom}.IsAnyGT(Coins{twoAtom}))
require.False(t, Coins{twoAtom}.IsAnyGT(Coins{fiveAtom}))
require.True(t, Coins{twoAtom, sixEth}.IsAnyGT(Coins{twoBtc, fiveAtom, threeEth}))
require.False(t, Coins{twoBtc, twoAtom, threeEth}.IsAnyGT(Coins{fiveAtom, sixEth}))
require.False(t, Coins{twoAtom, sixEth}.IsAnyGT(Coins{twoBtc, fiveAtom}))
}
func TestFindDup(t *testing.T) {
abc := NewInt64Coin("abc", 10)
def := NewInt64Coin("def", 10)
ghi := NewInt64Coin("ghi", 10)
type args struct {
coins Coins
}
tests := []struct {
name string
args args
want int
}{
{"empty", args{NewCoins()}, -1},
{"one coin", args{NewCoins(NewInt64Coin("xyz", 10))}, -1},
{"no dups", args{Coins{abc, def, ghi}}, -1},
{"dup at first position", args{Coins{abc, abc, def}}, 1},
{"dup after first position", args{Coins{abc, def, def}}, 2},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := findDup(tt.args.coins); got != tt.want {
t.Errorf("findDup() = %v, want %v", got, tt.want)
}
})
}
}
func TestMarshalJSONCoins(t *testing.T) {
cdc := codec.New()
RegisterCodec(cdc)
testCases := []struct {
name string
input Coins
strOutput string
}{
{"nil coins", nil, `[]`},
{"empty coins", Coins{}, `[]`},
{"non-empty coins", NewCoins(NewInt64Coin("foo", 50)), `[{"denom":"foo","amount":"50"}]`},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
bz, err := cdc.MarshalJSON(tc.input)
require.NoError(t, err)
require.Equal(t, tc.strOutput, string(bz))
var newCoins Coins
require.NoError(t, cdc.UnmarshalJSON(bz, &newCoins))
if tc.input.Empty() {
require.Nil(t, newCoins)
} else {
require.Equal(t, tc.input, newCoins)
}
})
}
}