e622fde7e7
Amount should still be a usable type even if the monetary amount being described is not an amount at a single instance in time, for example, the total of all BTC received by an address. Therefore, the bounds checks that the amount is within the total amount of bitcoin ever producable have been removed. The checks for NaN and +-Infinity remain.
194 lines
4 KiB
Go
194 lines
4 KiB
Go
// Copyright (c) 2013, 2014 Conformal Systems LLC.
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package btcutil_test
|
|
|
|
import (
|
|
. "github.com/conformal/btcutil"
|
|
"math"
|
|
"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: Amount(MaxSatoshi),
|
|
},
|
|
{
|
|
name: "min producable",
|
|
amount: -21e6,
|
|
valid: true,
|
|
expected: Amount(-MaxSatoshi),
|
|
},
|
|
{
|
|
name: "exceeds max producable",
|
|
amount: 21e6 + 1e-8,
|
|
valid: true,
|
|
expected: Amount(MaxSatoshi + 1),
|
|
},
|
|
{
|
|
name: "exceeds min producable",
|
|
amount: -21e6 - 1e-8,
|
|
valid: true,
|
|
expected: Amount(-MaxSatoshi - 1),
|
|
},
|
|
{
|
|
name: "one hundred",
|
|
amount: 100,
|
|
valid: true,
|
|
expected: Amount(100 * SatoshiPerBitcoin),
|
|
},
|
|
{
|
|
name: "fraction",
|
|
amount: 0.01234567,
|
|
valid: true,
|
|
expected: Amount(1234567),
|
|
},
|
|
{
|
|
name: "rounding up",
|
|
amount: 54.999999999999943157,
|
|
valid: true,
|
|
expected: Amount(55 * SatoshiPerBitcoin),
|
|
},
|
|
{
|
|
name: "rounding down",
|
|
amount: 55.000000000000056843,
|
|
valid: true,
|
|
expected: Amount(55 * SatoshiPerBitcoin),
|
|
},
|
|
|
|
// 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: "MBTC",
|
|
amount: Amount(MaxSatoshi),
|
|
unit: AmountMegaBTC,
|
|
converted: 21,
|
|
s: "21 MBTC",
|
|
},
|
|
{
|
|
name: "kBTC",
|
|
amount: Amount(44433322211100),
|
|
unit: AmountKiloBTC,
|
|
converted: 444.33322211100,
|
|
s: "444.333222111 kBTC",
|
|
},
|
|
{
|
|
name: "BTC",
|
|
amount: Amount(44433322211100),
|
|
unit: AmountBTC,
|
|
converted: 444333.22211100,
|
|
s: "444333.222111 BTC",
|
|
},
|
|
{
|
|
name: "mBTC",
|
|
amount: Amount(44433322211100),
|
|
unit: AmountMilliBTC,
|
|
converted: 444333222.11100,
|
|
s: "444333222.111 mBTC",
|
|
},
|
|
{
|
|
|
|
name: "μBTC",
|
|
amount: Amount(44433322211100),
|
|
unit: AmountMicroBTC,
|
|
converted: 444333222111.00,
|
|
s: "444333222111 μBTC",
|
|
},
|
|
{
|
|
|
|
name: "satoshi",
|
|
amount: Amount(44433322211100),
|
|
unit: AmountSatoshi,
|
|
converted: 44433322211100,
|
|
s: "44433322211100 Satoshi",
|
|
},
|
|
{
|
|
|
|
name: "non-standard unit",
|
|
amount: Amount(44433322211100),
|
|
unit: AmountUnit(-1),
|
|
converted: 4443332.2211100,
|
|
s: "4443332.22111 1e-1 BTC",
|
|
},
|
|
}
|
|
|
|
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.String works as advertised.
|
|
s1 := test.amount.Format(AmountBTC)
|
|
s2 := test.amount.String()
|
|
if s1 != s2 {
|
|
t.Errorf("%v: String does not match Format(AmountBitcoin): %v != %v", test.name, s1, s2)
|
|
}
|
|
}
|
|
}
|