2015-05-01 19:41:58 +02:00
|
|
|
// Copyright (c) 2013, 2014 The btcsuite developers
|
2014-04-12 05:03:00 +02:00
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package btcutil_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
"testing"
|
2014-07-03 02:29:48 +02:00
|
|
|
|
2015-01-15 22:13:38 +01:00
|
|
|
. "github.com/btcsuite/btcutil"
|
2014-04-12 05:03:00 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
{
|
2014-04-12 23:20:11 +02:00
|
|
|
name: "max producable",
|
2014-04-12 05:03:00 +02:00
|
|
|
amount: 21e6,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: MaxSatoshi,
|
2014-04-12 05:03:00 +02:00
|
|
|
},
|
|
|
|
{
|
2014-04-12 23:20:11 +02:00
|
|
|
name: "min producable",
|
2014-04-12 05:03:00 +02:00
|
|
|
amount: -21e6,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: -MaxSatoshi,
|
2014-04-12 05:03:00 +02:00
|
|
|
},
|
2014-04-12 23:20:11 +02:00
|
|
|
{
|
|
|
|
name: "exceeds max producable",
|
|
|
|
amount: 21e6 + 1e-8,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: MaxSatoshi + 1,
|
2014-04-12 23:20:11 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "exceeds min producable",
|
|
|
|
amount: -21e6 - 1e-8,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: -MaxSatoshi - 1,
|
2014-04-12 23:20:11 +02:00
|
|
|
},
|
2014-04-12 05:03:00 +02:00
|
|
|
{
|
|
|
|
name: "one hundred",
|
|
|
|
amount: 100,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: 100 * SatoshiPerBitcoin,
|
2014-04-12 05:03:00 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "fraction",
|
|
|
|
amount: 0.01234567,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: 1234567,
|
2014-04-12 05:03:00 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "rounding up",
|
|
|
|
amount: 54.999999999999943157,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: 55 * SatoshiPerBitcoin,
|
2014-04-12 05:03:00 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "rounding down",
|
|
|
|
amount: 55.000000000000056843,
|
|
|
|
valid: true,
|
2014-07-07 15:55:44 +02:00
|
|
|
expected: 55 * SatoshiPerBitcoin,
|
2014-04-12 05:03:00 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// 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)
|
2014-04-12 06:16:41 +02:00
|
|
|
continue
|
2014-04-12 05:03:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAmountUnitConversions(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
amount Amount
|
|
|
|
unit AmountUnit
|
|
|
|
converted float64
|
|
|
|
s string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "MBTC",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: MaxSatoshi,
|
2014-04-12 06:23:27 +02:00
|
|
|
unit: AmountMegaBTC,
|
2014-04-12 05:03:00 +02:00
|
|
|
converted: 21,
|
|
|
|
s: "21 MBTC",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "kBTC",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: 44433322211100,
|
2014-04-12 06:23:27 +02:00
|
|
|
unit: AmountKiloBTC,
|
2014-04-12 05:03:00 +02:00
|
|
|
converted: 444.33322211100,
|
|
|
|
s: "444.333222111 kBTC",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "BTC",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: 44433322211100,
|
2014-04-12 06:23:27 +02:00
|
|
|
unit: AmountBTC,
|
2014-04-12 05:03:00 +02:00
|
|
|
converted: 444333.22211100,
|
|
|
|
s: "444333.222111 BTC",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "mBTC",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: 44433322211100,
|
2014-04-12 06:23:27 +02:00
|
|
|
unit: AmountMilliBTC,
|
2014-04-12 05:03:00 +02:00
|
|
|
converted: 444333222.11100,
|
|
|
|
s: "444333222.111 mBTC",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
|
|
|
|
name: "μBTC",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: 44433322211100,
|
2014-04-12 06:23:27 +02:00
|
|
|
unit: AmountMicroBTC,
|
2014-04-12 05:03:00 +02:00
|
|
|
converted: 444333222111.00,
|
|
|
|
s: "444333222111 μBTC",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
|
|
|
|
name: "satoshi",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: 44433322211100,
|
2014-04-12 06:23:27 +02:00
|
|
|
unit: AmountSatoshi,
|
2014-04-12 05:03:00 +02:00
|
|
|
converted: 44433322211100,
|
|
|
|
s: "44433322211100 Satoshi",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
|
|
|
|
name: "non-standard unit",
|
2014-07-07 15:55:44 +02:00
|
|
|
amount: 44433322211100,
|
2014-04-12 05:03:00 +02:00
|
|
|
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)
|
2014-04-12 06:16:41 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-01-02 15:19:16 +01:00
|
|
|
// Verify that Amount.ToBTC works as advertised.
|
|
|
|
f1 := test.amount.ToUnit(AmountBTC)
|
|
|
|
f2 := test.amount.ToBTC()
|
|
|
|
if f1 != f2 {
|
|
|
|
t.Errorf("%v: ToBTC does not match ToUnit(AmountBTC): %v != %v", test.name, f1, f2)
|
|
|
|
}
|
|
|
|
|
2014-04-12 06:16:41 +02:00
|
|
|
// Verify that Amount.String works as advertised.
|
2014-04-12 06:23:27 +02:00
|
|
|
s1 := test.amount.Format(AmountBTC)
|
2014-04-12 06:16:41 +02:00
|
|
|
s2 := test.amount.String()
|
|
|
|
if s1 != s2 {
|
|
|
|
t.Errorf("%v: String does not match Format(AmountBitcoin): %v != %v", test.name, s1, s2)
|
2014-04-12 05:03:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-06-20 22:17:48 +02:00
|
|
|
|
|
|
|
func TestAmountMulF64(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
amt Amount
|
|
|
|
mul float64
|
|
|
|
res Amount
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Multiply 0.1 BTC by 2",
|
|
|
|
amt: 100e5, // 0.1 BTC
|
|
|
|
mul: 2,
|
|
|
|
res: 200e5, // 0.2 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 0.2 BTC by 0.02",
|
|
|
|
amt: 200e5, // 0.2 BTC
|
|
|
|
mul: 1.02,
|
|
|
|
res: 204e5, // 0.204 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 0.1 BTC by -2",
|
|
|
|
amt: 100e5, // 0.1 BTC
|
|
|
|
mul: -2,
|
|
|
|
res: -200e5, // -0.2 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 0.2 BTC by -0.02",
|
|
|
|
amt: 200e5, // 0.2 BTC
|
|
|
|
mul: -1.02,
|
|
|
|
res: -204e5, // -0.204 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply -0.1 BTC by 2",
|
|
|
|
amt: -100e5, // -0.1 BTC
|
|
|
|
mul: 2,
|
|
|
|
res: -200e5, // -0.2 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply -0.2 BTC by 0.02",
|
|
|
|
amt: -200e5, // -0.2 BTC
|
|
|
|
mul: 1.02,
|
|
|
|
res: -204e5, // -0.204 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply -0.1 BTC by -2",
|
|
|
|
amt: -100e5, // -0.1 BTC
|
|
|
|
mul: -2,
|
|
|
|
res: 200e5, // 0.2 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply -0.2 BTC by -0.02",
|
|
|
|
amt: -200e5, // -0.2 BTC
|
|
|
|
mul: -1.02,
|
|
|
|
res: 204e5, // 0.204 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Round down",
|
|
|
|
amt: 49, // 49 Satoshis
|
|
|
|
mul: 0.01,
|
|
|
|
res: 0,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Round up",
|
|
|
|
amt: 50, // 50 Satoshis
|
|
|
|
mul: 0.01,
|
|
|
|
res: 1, // 1 Satoshi
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply by 0.",
|
|
|
|
amt: 1e8, // 1 BTC
|
|
|
|
mul: 0,
|
|
|
|
res: 0, // 0 BTC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 1 by 0.5.",
|
|
|
|
amt: 1, // 1 Satoshi
|
|
|
|
mul: 0.5,
|
|
|
|
res: 1, // 1 Satoshi
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 100 by 66%.",
|
|
|
|
amt: 100, // 100 Satoshis
|
|
|
|
mul: 0.66,
|
|
|
|
res: 66, // 66 Satoshis
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 100 by 66.6%.",
|
|
|
|
amt: 100, // 100 Satoshis
|
|
|
|
mul: 0.666,
|
|
|
|
res: 67, // 67 Satoshis
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Multiply 100 by 2/3.",
|
|
|
|
amt: 100, // 100 Satoshis
|
|
|
|
mul: 2.0 / 3,
|
|
|
|
res: 67, // 67 Satoshis
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|