Putting the test code in the same package makes it easier for forks since they don't have to change the import paths as much and it also gets rid of the need for internal_test.go to bridge.
351 lines
6.8 KiB
Go
351 lines
6.8 KiB
Go
// Copyright (c) 2013, 2014 The btcsuite developers
|
|
// Copyright (c) 2015-2019 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package dcrutil
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
func TestAmountCreation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
amount float64
|
|
valid bool
|
|
expected Amount
|
|
}{
|
|
// Positive tests.
|
|
{
|
|
name: "zero",
|
|
amount: 0,
|
|
valid: true,
|
|
expected: 0,
|
|
},
|
|
{
|
|
name: "max producable",
|
|
amount: 21e6,
|
|
valid: true,
|
|
expected: MaxAmount,
|
|
},
|
|
{
|
|
name: "min producable",
|
|
amount: -21e6,
|
|
valid: true,
|
|
expected: -MaxAmount,
|
|
},
|
|
{
|
|
name: "exceeds max producable",
|
|
amount: 21e6 + 1e-8,
|
|
valid: true,
|
|
expected: MaxAmount + 1,
|
|
},
|
|
{
|
|
name: "exceeds min producable",
|
|
amount: -21e6 - 1e-8,
|
|
valid: true,
|
|
expected: -MaxAmount - 1,
|
|
},
|
|
{
|
|
name: "one hundred",
|
|
amount: 100,
|
|
valid: true,
|
|
expected: 100 * AtomsPerCoin,
|
|
},
|
|
{
|
|
name: "fraction",
|
|
amount: 0.01234567,
|
|
valid: true,
|
|
expected: 1234567,
|
|
},
|
|
{
|
|
name: "rounding up",
|
|
amount: 54.999999999999943157,
|
|
valid: true,
|
|
expected: 55 * AtomsPerCoin,
|
|
},
|
|
{
|
|
name: "rounding down",
|
|
amount: 55.000000000000056843,
|
|
valid: true,
|
|
expected: 55 * AtomsPerCoin,
|
|
},
|
|
|
|
// Negative tests.
|
|
{
|
|
name: "not-a-number",
|
|
amount: math.NaN(),
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "-infinity",
|
|
amount: math.Inf(-1),
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "+infinity",
|
|
amount: math.Inf(1),
|
|
valid: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
a, err := NewAmount(test.amount)
|
|
switch {
|
|
case test.valid && err != nil:
|
|
t.Errorf("%v: Positive test Amount creation failed with: %v", test.name, err)
|
|
continue
|
|
case !test.valid && err == nil:
|
|
t.Errorf("%v: Negative test Amount creation succeeded (value %v) when should fail", test.name, a)
|
|
continue
|
|
}
|
|
|
|
if a != test.expected {
|
|
t.Errorf("%v: Created amount %v does not match expected %v", test.name, a, test.expected)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAmountUnitConversions(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
amount Amount
|
|
unit AmountUnit
|
|
converted float64
|
|
s string
|
|
}{
|
|
{
|
|
name: "MDCR",
|
|
amount: MaxAmount,
|
|
unit: AmountMegaCoin,
|
|
converted: 21,
|
|
s: "21 MDCR",
|
|
},
|
|
{
|
|
name: "kDCR",
|
|
amount: 44433322211100,
|
|
unit: AmountKiloCoin,
|
|
converted: 444.33322211100,
|
|
s: "444.333222111 kDCR",
|
|
},
|
|
{
|
|
name: "Coin",
|
|
amount: 44433322211100,
|
|
unit: AmountCoin,
|
|
converted: 444333.22211100,
|
|
s: "444333.222111 DCR",
|
|
},
|
|
{
|
|
name: "mDCR",
|
|
amount: 44433322211100,
|
|
unit: AmountMilliCoin,
|
|
converted: 444333222.11100,
|
|
s: "444333222.111 mDCR",
|
|
},
|
|
{
|
|
|
|
name: "μDCR",
|
|
amount: 44433322211100,
|
|
unit: AmountMicroCoin,
|
|
converted: 444333222111.00,
|
|
s: "444333222111 μDCR",
|
|
},
|
|
{
|
|
|
|
name: "atom",
|
|
amount: 44433322211100,
|
|
unit: AmountAtom,
|
|
converted: 44433322211100,
|
|
s: "44433322211100 Atom",
|
|
},
|
|
{
|
|
|
|
name: "non-standard unit",
|
|
amount: 44433322211100,
|
|
unit: AmountUnit(-1),
|
|
converted: 4443332.2211100,
|
|
s: "4443332.22111 1e-1 DCR",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
f := test.amount.ToUnit(test.unit)
|
|
if f != test.converted {
|
|
t.Errorf("%v: converted value %v does not match expected %v", test.name, f, test.converted)
|
|
continue
|
|
}
|
|
|
|
s := test.amount.Format(test.unit)
|
|
if s != test.s {
|
|
t.Errorf("%v: format '%v' does not match expected '%v'", test.name, s, test.s)
|
|
continue
|
|
}
|
|
|
|
// Verify that Amount.ToCoin works as advertised.
|
|
f1 := test.amount.ToUnit(AmountCoin)
|
|
f2 := test.amount.ToCoin()
|
|
if f1 != f2 {
|
|
t.Errorf("%v: ToCoin does not match ToUnit(AmountCoin): %v != %v", test.name, f1, f2)
|
|
}
|
|
|
|
// Verify that Amount.String works as advertised.
|
|
s1 := test.amount.Format(AmountCoin)
|
|
s2 := test.amount.String()
|
|
if s1 != s2 {
|
|
t.Errorf("%v: String does not match Format(AmountCoin): %v != %v", test.name, s1, s2)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAmountMulF64(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
amt Amount
|
|
mul float64
|
|
res Amount
|
|
}{
|
|
{
|
|
name: "Multiply 0.1 DCR by 2",
|
|
amt: 100e5, // 0.1 DCR
|
|
mul: 2,
|
|
res: 200e5, // 0.2 DCR
|
|
},
|
|
{
|
|
name: "Multiply 0.2 DCR by 0.02",
|
|
amt: 200e5, // 0.2 DCR
|
|
mul: 1.02,
|
|
res: 204e5, // 0.204 DCR
|
|
},
|
|
{
|
|
name: "Multiply 0.1 DCR by -2",
|
|
amt: 100e5, // 0.1 DCR
|
|
mul: -2,
|
|
res: -200e5, // -0.2 DCR
|
|
},
|
|
{
|
|
name: "Multiply 0.2 DCR by -0.02",
|
|
amt: 200e5, // 0.2 DCR
|
|
mul: -1.02,
|
|
res: -204e5, // -0.204 DCR
|
|
},
|
|
{
|
|
name: "Multiply -0.1 DCR by 2",
|
|
amt: -100e5, // -0.1 DCR
|
|
mul: 2,
|
|
res: -200e5, // -0.2 DCR
|
|
},
|
|
{
|
|
name: "Multiply -0.2 DCR by 0.02",
|
|
amt: -200e5, // -0.2 DCR
|
|
mul: 1.02,
|
|
res: -204e5, // -0.204 DCR
|
|
},
|
|
{
|
|
name: "Multiply -0.1 DCR by -2",
|
|
amt: -100e5, // -0.1 DCR
|
|
mul: -2,
|
|
res: 200e5, // 0.2 DCR
|
|
},
|
|
{
|
|
name: "Multiply -0.2 DCR by -0.02",
|
|
amt: -200e5, // -0.2 DCR
|
|
mul: -1.02,
|
|
res: 204e5, // 0.204 DCR
|
|
},
|
|
{
|
|
name: "Round down",
|
|
amt: 49, // 49 Atoms
|
|
mul: 0.01,
|
|
res: 0,
|
|
},
|
|
{
|
|
name: "Round up",
|
|
amt: 50, // 50 Atoms
|
|
mul: 0.01,
|
|
res: 1, // 1 Atom
|
|
},
|
|
{
|
|
name: "Multiply by 0.",
|
|
amt: 1e8, // 1 DCR
|
|
mul: 0,
|
|
res: 0, // 0 DCR
|
|
},
|
|
{
|
|
name: "Multiply 1 by 0.5.",
|
|
amt: 1, // 1 Atom
|
|
mul: 0.5,
|
|
res: 1, // 1 Atom
|
|
},
|
|
{
|
|
name: "Multiply 100 by 66%.",
|
|
amt: 100, // 100 Atoms
|
|
mul: 0.66,
|
|
res: 66, // 66 Atoms
|
|
},
|
|
{
|
|
name: "Multiply 100 by 66.6%.",
|
|
amt: 100, // 100 Atoms
|
|
mul: 0.666,
|
|
res: 67, // 67 Atoms
|
|
},
|
|
{
|
|
name: "Multiply 100 by 2/3.",
|
|
amt: 100, // 100 Atoms
|
|
mul: 2.0 / 3,
|
|
res: 67, // 67 Atoms
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
a := test.amt.MulF64(test.mul)
|
|
if a != test.res {
|
|
t.Errorf("%v: expected %v got %v", test.name, test.res, a)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAmountSorter(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
as []Amount
|
|
want []Amount
|
|
}{
|
|
{
|
|
name: "Sort zero length slice of Amounts",
|
|
as: []Amount{},
|
|
want: []Amount{},
|
|
},
|
|
{
|
|
name: "Sort 1-element slice of Amounts",
|
|
as: []Amount{7},
|
|
want: []Amount{7},
|
|
},
|
|
{
|
|
name: "Sort 2-element slice of Amounts",
|
|
as: []Amount{7, 5},
|
|
want: []Amount{5, 7},
|
|
},
|
|
{
|
|
name: "Sort 6-element slice of Amounts",
|
|
as: []Amount{0, 9e8, 4e6, 4e6, 3, 9e12},
|
|
want: []Amount{0, 3, 4e6, 4e6, 9e8, 9e12},
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
result := make([]Amount, len(test.as))
|
|
copy(result, test.as)
|
|
sort.Sort(AmountSorter(result))
|
|
if !reflect.DeepEqual(result, test.want) {
|
|
t.Errorf("AmountSorter #%d got %v want %v", i, result,
|
|
test.want)
|
|
continue
|
|
}
|
|
}
|
|
}
|