Add Coins.AmountOf

This commit is contained in:
Jae Kwon 2018-01-25 16:30:49 -08:00
parent ac7fa3f59f
commit de5bf2ebc6
3 changed files with 130 additions and 50 deletions

View File

@ -187,6 +187,30 @@ func (coins Coins) IsNotNegative() bool {
return true
}
func (coins Coins) AmountOf(denom string) int64 {
switch len(coins) {
case 0:
return 0
case 1:
coin := coins[0]
if coin.Denom == denom {
return coin.Amount
} else {
return 0
}
default:
midIdx := len(coins) / 2 // 2:1, 3:1, 4:2
coin := coins[midIdx]
if denom < coin.Denom {
return Coins(coins[:midIdx]).AmountOf(denom)
} else if denom == coin.Denom {
return coin.Amount
} else {
return Coins(coins[midIdx+1:]).AmountOf(denom)
}
}
}
//----------------------------------------
// Sort interface

View File

@ -7,55 +7,53 @@ import (
)
func TestCoins(t *testing.T) {
assert := assert.New(t)
//Define the coins to be used in tests
good := Coins{
Coin{"GAS", 1},
Coin{"MINERAL", 1},
Coin{"TREE", 1},
{"GAS", 1},
{"MINERAL", 1},
{"TREE", 1},
}
neg := good.Negative()
sum := good.Plus(neg)
empty := Coins{
Coin{"GOLD", 0},
{"GOLD", 0},
}
badSort1 := Coins{
Coin{"TREE", 1},
Coin{"GAS", 1},
Coin{"MINERAL", 1},
{"TREE", 1},
{"GAS", 1},
{"MINERAL", 1},
}
badSort2 := Coins{ // both are after the first one, but the second and third are in the wrong order
Coin{"GAS", 1},
Coin{"TREE", 1},
Coin{"MINERAL", 1},
{"GAS", 1},
{"TREE", 1},
{"MINERAL", 1},
}
badAmt := Coins{
Coin{"GAS", 1},
Coin{"TREE", 0},
Coin{"MINERAL", 1},
{"GAS", 1},
{"TREE", 0},
{"MINERAL", 1},
}
dup := Coins{
Coin{"GAS", 1},
Coin{"GAS", 1},
Coin{"MINERAL", 1},
{"GAS", 1},
{"GAS", 1},
{"MINERAL", 1},
}
assert.True(good.IsValid(), "Coins are valid")
assert.True(good.IsPositive(), "Expected coins to be positive: %v", good)
assert.True(good.IsGTE(empty), "Expected %v to be >= %v", good, empty)
assert.False(neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
assert.Zero(len(sum), "Expected 0 coins")
assert.False(badSort1.IsValid(), "Coins are not sorted")
assert.False(badSort2.IsValid(), "Coins are not sorted")
assert.False(badAmt.IsValid(), "Coins cannot include 0 amounts")
assert.False(dup.IsValid(), "Duplicate coin")
assert.True(t, good.IsValid(), "Coins are valid")
assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good)
assert.True(t, good.IsGTE(empty), "Expected %v to be >= %v", good, empty)
assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
assert.Zero(t, len(sum), "Expected 0 coins")
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")
}
//Test the parse coin and parse coins functionality
func TestParse(t *testing.T) {
assert := assert.New(t)
cases := []struct {
input string
@ -79,44 +77,43 @@ func TestParse(t *testing.T) {
for _, tc := range cases {
res, err := ParseCoins(tc.input)
if !tc.valid {
assert.NotNil(err, "%s: %#v", tc.input, res)
} else if assert.Nil(err, "%s: %+v", tc.input, err) {
assert.Equal(tc.expected, res)
assert.NotNil(t, err, "%s: %#v", tc.input, res)
} else if assert.Nil(t, err, "%s: %+v", tc.input, err) {
assert.Equal(t, tc.expected, res)
}
}
}
func TestSortCoins(t *testing.T) {
assert := assert.New(t)
good := Coins{
Coin{"GAS", 1},
Coin{"MINERAL", 1},
Coin{"TREE", 1},
{"GAS", 1},
{"MINERAL", 1},
{"TREE", 1},
}
empty := Coins{
Coin{"GOLD", 0},
{"GOLD", 0},
}
badSort1 := Coins{
Coin{"TREE", 1},
Coin{"GAS", 1},
Coin{"MINERAL", 1},
{"TREE", 1},
{"GAS", 1},
{"MINERAL", 1},
}
badSort2 := Coins{ // both are after the first one, but the second and third are in the wrong order
Coin{"GAS", 1},
Coin{"TREE", 1},
Coin{"MINERAL", 1},
{"GAS", 1},
{"TREE", 1},
{"MINERAL", 1},
}
badAmt := Coins{
Coin{"GAS", 1},
Coin{"TREE", 0},
Coin{"MINERAL", 1},
{"GAS", 1},
{"TREE", 0},
{"MINERAL", 1},
}
dup := Coins{
Coin{"GAS", 1},
Coin{"GAS", 1},
Coin{"MINERAL", 1},
{"GAS", 1},
{"GAS", 1},
{"MINERAL", 1},
}
cases := []struct {
@ -132,8 +129,67 @@ func TestSortCoins(t *testing.T) {
}
for _, tc := range cases {
assert.Equal(tc.before, tc.coins.IsValid())
assert.Equal(t, tc.before, tc.coins.IsValid())
tc.coins.Sort()
assert.Equal(tc.after, tc.coins.IsValid())
assert.Equal(t, tc.after, tc.coins.IsValid())
}
}
func TestAmountOf(t *testing.T) {
case0 := Coins{}
case1 := Coins{
{"", 0},
}
case2 := Coins{
{" ", 0},
}
case3 := Coins{
{"GOLD", 0},
}
case4 := Coins{
{"GAS", 1},
{"MINERAL", 1},
{"TREE", 1},
}
case5 := Coins{
{"MINERAL", 1},
{"TREE", 1},
}
case6 := Coins{
{"", 6},
}
case7 := Coins{
{" ", 7},
}
case8 := Coins{
{"GAS", 8},
}
cases := []struct {
coins Coins
amountOf int64
amountOf_ int64
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, tc.amountOf, tc.coins.AmountOf(""))
assert.Equal(t, tc.amountOf_, tc.coins.AmountOf(" "))
assert.Equal(t, tc.amountOfGAS, tc.coins.AmountOf("GAS"))
assert.Equal(t, tc.amountOfMINERAL, tc.coins.AmountOf("MINERAL"))
assert.Equal(t, tc.amountOfTREE, tc.coins.AmountOf("TREE"))
}
}