cosmos-sdk/types/coin_test.go

502 lines
15 KiB
Go
Raw Normal View History

2018-01-10 20:11:44 -08:00
package types
2016-04-01 15:19:07 -07:00
import (
"testing"
2017-02-22 14:30:50 -08:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2016-04-01 15:19:07 -07:00
)
// ----------------------------------------------------------------------------
// Coin tests
2018-03-25 10:35:45 -07:00
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)
2018-03-25 10:35:45 -07:00
}
func TestSameDenomAsCoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), true},
2018-07-30 17:09:50 -07:00
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), true},
2018-03-25 10:35:45 -07:00
}
for tcIndex, tc := range cases {
2018-03-25 10:35:45 -07:00
res := tc.inputOne.SameDenomAs(tc.inputTwo)
require.Equal(t, tc.expected, res, "coin denominations didn't match, tc #%d", tcIndex)
2018-03-25 10:35:45 -07:00
}
}
func TestIsEqualCoin(t *testing.T) {
2018-03-25 10:35:45 -07:00
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), true},
2018-07-30 17:09:50 -07:00
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), false},
2018-03-25 10:35:45 -07:00
}
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)
2018-03-25 10:35:45 -07:00
}
}
func TestPlusCoin(t *testing.T) {
cases := []struct {
inputOne Coin
inputTwo Coin
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},
}
for tcIndex, tc := range cases {
if tc.shouldPanic {
require.Panics(t, func() { tc.inputOne.Plus(tc.inputTwo) })
} else {
res := tc.inputOne.Plus(tc.inputTwo)
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
}
}
}
func TestMinusCoin(t *testing.T) {
2018-03-25 10:35:45 -07:00
cases := []struct {
inputOne Coin
inputTwo Coin
expected Coin
shouldPanic bool
2018-03-25 10:35:45 -07:00
}{
{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},
2018-03-25 10:35:45 -07:00
}
for tcIndex, tc := range cases {
if tc.shouldPanic {
require.Panics(t, func() { tc.inputOne.Minus(tc.inputTwo) })
} else {
res := tc.inputOne.Minus(tc.inputTwo)
require.Equal(t, tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
}
2018-03-25 10:35:45 -07:00
}
tc := struct {
inputOne Coin
inputTwo Coin
expected int64
}{NewInt64Coin("a", 1), NewInt64Coin("a", 1), 0}
res := tc.inputOne.Minus(tc.inputTwo)
require.Equal(t, tc.expected, res.Amount.Int64())
2018-03-25 10:35:45 -07:00
}
func TestIsGTECoin(t *testing.T) {
2018-03-25 10:35:45 -07:00
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
2018-03-25 10:35:45 -07:00
}{
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 2), NewInt64Coin("a", 1), true},
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
2018-03-25 10:35:45 -07:00
}
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)
2018-03-25 10:35:45 -07:00
}
}
func TestIsLTCoin(t *testing.T) {
2018-03-25 10:35:45 -07:00
cases := []struct {
inputOne Coin
inputTwo Coin
expected bool
2018-03-25 10:35:45 -07:00
}{
{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},
2018-03-25 10:35:45 -07:00
}
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)
2018-03-25 10:35:45 -07:00
}
}
func TestCoinIsZero(t *testing.T) {
coin := NewInt64Coin("a", 0)
res := coin.IsZero()
require.True(t, res)
coin = NewInt64Coin("a", 1)
res = coin.IsZero()
require.False(t, res)
2018-03-25 10:35:45 -07:00
}
// ----------------------------------------------------------------------------
// Coins tests
func TestIsZeroCoins(t *testing.T) {
cases := []struct {
inputOne Coins
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},
}
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
}{
{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},
}
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)
}
}
func TestPlusCoins(t *testing.T) {
zero := NewInt(0)
one := NewInt(1)
two := NewInt(2)
cases := []struct {
inputOne Coins
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)},
}
for tcIndex, tc := range cases {
res := tc.inputOne.Plus(tc.inputTwo)
assert.True(t, res.IsValid())
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
}
}
func TestMinusCoins(t *testing.T) {
zero := NewInt(0)
one := NewInt(1)
two := NewInt(2)
testCases := []struct {
inputOne Coins
inputTwo Coins
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},
}
for i, tc := range testCases {
if tc.shouldPanic {
require.Panics(t, func() { tc.inputOne.Minus(tc.inputTwo) })
} else {
res := tc.inputOne.Minus(tc.inputTwo)
assert.True(t, res.IsValid())
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", i)
}
}
}
2017-02-22 14:30:50 -08:00
func TestCoins(t *testing.T) {
2017-02-22 14:30:50 -08:00
good := Coins{
{"gas", NewInt(1)},
{"mineral", NewInt(1)},
{"tree", NewInt(1)},
}
mixedCase := Coins{
{"gAs", NewInt(1)},
{"MineraL", NewInt(1)},
{"TREE", NewInt(1)},
2016-04-01 15:19:07 -07:00
}
2017-02-22 14:30:50 -08:00
empty := Coins{
{"gold", NewInt(0)},
2016-04-01 15:19:07 -07:00
}
null := Coins{}
2017-02-22 14:30:50 -08:00
badSort1 := Coins{
{"tree", NewInt(1)},
{"gas", NewInt(1)},
{"mineral", NewInt(1)},
2016-04-01 15:19:07 -07:00
}
2018-01-23 10:22:56 -08:00
// 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)},
2017-01-31 03:24:49 -08:00
}
2017-02-22 14:30:50 -08:00
badAmt := Coins{
{"gas", NewInt(1)},
{"tree", NewInt(0)},
{"mineral", NewInt(1)},
2016-04-01 15:19:07 -07:00
}
2017-02-22 14:30:50 -08:00
dup := Coins{
{"gas", NewInt(1)},
{"gas", NewInt(1)},
{"mineral", NewInt(1)},
2016-04-01 15:19:07 -07:00
}
neg := Coins{
{"gas", NewInt(-1)},
{"mineral", NewInt(1)},
}
2016-04-01 15:19:07 -07:00
2018-01-25 16:30:49 -08:00
assert.True(t, good.IsValid(), "Coins are valid")
assert.False(t, mixedCase.IsValid(), "Coins denoms contain upper case characters")
2018-01-25 16:30:49 -08:00
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.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)
2018-01-25 16:30:49 -08:00
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")
2016-04-01 15:19:07 -07:00
}
2017-03-28 13:32:55 -07:00
func TestCoinsGT(t *testing.T) {
one := NewInt(1)
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}}))
}
func TestCoinsGTE(t *testing.T) {
one := NewInt(1)
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}}))
}
func TestCoinsLT(t *testing.T) {
one := NewInt(1)
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}}))
}
func TestCoinsLTE(t *testing.T) {
one := NewInt(1)
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}}))
}
2017-03-28 13:32:55 -07:00
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)}}},
2017-05-24 08:15:42 -07:00
{"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
}
2017-03-28 13:32:55 -07:00
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)
2018-01-25 16:30:49 -08:00
} else if assert.Nil(t, err, "%s: %+v", tc.input, err) {
require.Equal(t, tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
}
2017-03-28 13:32:55 -07:00
}
}
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),
2017-03-28 13:32:55 -07:00
}
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},
}
2017-03-28 13:32:55 -07:00
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)
2018-01-25 16:30:49 -08:00
}
}
func TestAmountOf(t *testing.T) {
case0 := Coins{}
case1 := Coins{
2018-07-30 17:09:50 -07:00
NewInt64Coin("", 0),
2018-01-25 16:30:49 -08:00
}
case2 := Coins{
2018-07-30 17:09:50 -07:00
NewInt64Coin(" ", 0),
2018-01-25 16:30:49 -08:00
}
case3 := Coins{
NewInt64Coin("gold", 0),
2018-01-25 16:30:49 -08:00
}
case4 := Coins{
NewInt64Coin("gas", 1),
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
2018-01-25 16:30:49 -08:00
}
case5 := Coins{
NewInt64Coin("mineral", 1),
NewInt64Coin("tree", 1),
2018-01-25 16:30:49 -08:00
}
case6 := Coins{
2018-07-30 17:09:50 -07:00
NewInt64Coin("", 6),
2018-01-25 16:30:49 -08:00
}
case7 := Coins{
2018-07-30 17:09:50 -07:00
NewInt64Coin(" ", 7),
2018-01-25 16:30:49 -08:00
}
case8 := Coins{
NewInt64Coin("gas", 8),
2018-01-25 16:30:49 -08:00
}
cases := []struct {
coins Coins
amountOf int64
2018-02-04 16:59:11 -08:00
amountOfSpace int64
2018-01-25 16:30:49 -08:00
amountOfGAS int64
amountOfMINERAL int64
amountOfTREE int64
}{
{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},
}
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"))
}
assert.Panics(t, func() { cases[0].coins.AmountOf("Invalid") })
2017-03-28 13:32:55 -07:00
}