Switch Amount to contain big.Rat instead of being a typedef

This commit is contained in:
Aaron Lindsay 2017-04-03 21:15:08 -04:00
parent 9b03829645
commit 7f5ef5751d
6 changed files with 80 additions and 90 deletions

View File

@ -2,7 +2,6 @@ package ofxgo_test
import (
"github.com/aclindsa/ofxgo"
"math/big"
"strings"
"testing"
"time"
@ -153,7 +152,7 @@ func TestUnmarshalBankStatementResponse(t *testing.T) {
expected.Signon.Org = "BNK"
expected.Signon.Fid = "1987"
var trnamt1, trnamt2 big.Rat
var trnamt1, trnamt2 ofxgo.Amount
trnamt1.SetFrac64(-20000, 100)
trnamt2.SetFrac64(-30000, 100)
dtuser2 := ofxgo.Date(time.Date(2006, 1, 12, 0, 0, 0, 0, GMT))
@ -165,7 +164,7 @@ func TestUnmarshalBankStatementResponse(t *testing.T) {
{
TrnType: "CHECK",
DtPosted: ofxgo.Date(time.Date(2006, 1, 4, 0, 0, 0, 0, GMT)),
TrnAmt: ofxgo.Amount(trnamt1),
TrnAmt: trnamt1,
FiTId: "00592",
CheckNum: "2002",
},
@ -173,13 +172,13 @@ func TestUnmarshalBankStatementResponse(t *testing.T) {
TrnType: "ATM",
DtPosted: ofxgo.Date(time.Date(2006, 1, 12, 0, 0, 0, 0, GMT)),
DtUser: &dtuser2,
TrnAmt: ofxgo.Amount(trnamt2),
TrnAmt: trnamt2,
FiTId: "00679",
},
},
}
var balamt, availbalamt big.Rat
var balamt, availbalamt ofxgo.Amount
balamt.SetFrac64(20029, 100)
availbalamt.SetFrac64(20029, 100)
@ -198,9 +197,9 @@ func TestUnmarshalBankStatementResponse(t *testing.T) {
AcctType: "CHECKING",
},
BankTranList: &banktranlist,
BalAmt: ofxgo.Amount(balamt),
BalAmt: balamt,
DtAsOf: ofxgo.Date(time.Date(2006, 1, 14, 16, 0, 0, 0, GMT)),
AvailBalAmt: (*ofxgo.Amount)(&availbalamt),
AvailBalAmt: &availbalamt,
AvailDtAsOf: &availdtasof,
}
expected.Bank = append(expected.Bank, &statementResponse)

View File

@ -4,7 +4,6 @@ import (
"flag"
"fmt"
"github.com/aclindsa/ofxgo"
"math/big"
"os"
)
@ -65,7 +64,7 @@ func invTransactions() {
}
if stmt, ok := response.InvStmt[0].(*ofxgo.InvStatementResponse); ok {
availCash := big.Rat(stmt.InvBal.AvailCash)
availCash := stmt.InvBal.AvailCash
if availCash.IsInt() && availCash.Num().Int64() != 0 {
fmt.Printf("Balance: %s %s (as of %s)\n", stmt.InvBal.AvailCash, stmt.CurDef, stmt.DtAsOf)
}

View File

@ -2,7 +2,6 @@ package ofxgo_test
import (
"github.com/aclindsa/ofxgo"
"math/big"
"strings"
"testing"
"time"
@ -99,7 +98,7 @@ NEWFILEUID:NONE
expected.Signon.Org = "01"
expected.Signon.Fid = "81729"
var trnamt1, trnamt2, trnamt3 big.Rat
var trnamt1, trnamt2, trnamt3 ofxgo.Amount
trnamt1.SetFrac64(-796, 100)
trnamt2.SetFrac64(383046, 100)
trnamt3.SetFrac64(-1770, 100)
@ -111,28 +110,28 @@ NEWFILEUID:NONE
{
TrnType: "DEBIT",
DtPosted: ofxgo.Date(time.Date(2017, 2, 9, 12, 0, 0, 0, GMT)),
TrnAmt: ofxgo.Amount(trnamt1),
TrnAmt: trnamt1,
FiTId: "2017020924435657040207171600195",
Name: "SLICE OF NY",
},
{
TrnType: "CREDIT",
DtPosted: ofxgo.Date(time.Date(2016, 12, 28, 12, 0, 0, 0, GMT)),
TrnAmt: ofxgo.Amount(trnamt2),
TrnAmt: trnamt2,
FiTId: "2016122823633637200000258482730",
Name: "Payment Thank You Electro",
},
{
TrnType: "DEBIT",
DtPosted: ofxgo.Date(time.Date(2017, 3, 27, 12, 0, 0, 0, GMT)),
TrnAmt: ofxgo.Amount(trnamt3),
TrnAmt: trnamt3,
FiTId: "2017032724445727085300442885680",
Name: "KROGER FUEL #9999",
},
},
}
var balamt, availbalamt big.Rat
var balamt, availbalamt ofxgo.Amount
balamt.SetFrac64(-933400, 100)
availbalamt.SetFrac64(763017, 100)
@ -149,9 +148,9 @@ NEWFILEUID:NONE
AcctId: "9283744488463775",
},
BankTranList: &banktranlist,
BalAmt: ofxgo.Amount(balamt),
BalAmt: balamt,
DtAsOf: ofxgo.Date(time.Date(2017, 3, 31, 8, 0, 0, 0, EDT)),
AvailBalAmt: (*ofxgo.Amount)(&availbalamt),
AvailBalAmt: &availbalamt,
AvailDtAsOf: &availdtasof,
}
expected.CreditCard = append(expected.CreditCard, &statementResponse)

View File

@ -2,7 +2,6 @@ package ofxgo_test
import (
"github.com/aclindsa/ofxgo"
"math/big"
"strings"
"testing"
"time"
@ -308,7 +307,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
expected.Signon.Org = "INVSTRUS"
expected.Signon.Fid = "9999"
var units1, unitprice1, commission1, total1, amount2 big.Rat
var units1, unitprice1, commission1, total1, amount2 ofxgo.Amount
units1.SetFrac64(100, 1)
unitprice1.SetFrac64(229, 1)
commission1.SetFrac64(9, 1)
@ -334,10 +333,10 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
UniqueId: "78462F103",
UniqueIdType: "CUSIP",
},
Units: ofxgo.Amount(units1),
UnitPrice: ofxgo.Amount(unitprice1),
Commission: ofxgo.Amount(commission1),
Total: ofxgo.Amount(total1),
Units: units1,
UnitPrice: unitprice1,
Commission: commission1,
Total: total1,
SubAcctSec: "CASH",
SubAcctFund: "CASH",
},
@ -352,7 +351,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
DtPosted: ofxgo.Date(time.Date(2017, 1, 20, 0, 0, 0, 0, GMT)),
DtUser: &dtuser,
DtAvail: &dtavail,
TrnAmt: ofxgo.Amount(amount2),
TrnAmt: amount2,
FiTId: "993838",
Name: "DEPOSIT",
Memo: "CHECK 19980",
@ -363,7 +362,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
},
}
var availcash, marginbalance, shortbalance, balvalue big.Rat
var availcash, marginbalance, shortbalance, balvalue ofxgo.Amount
availcash.SetFrac64(1673, 100)
marginbalance.SetFrac64(-8192, 10)
shortbalance.SetFrac64(0, 1)
@ -372,21 +371,21 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
baldtasof := ofxgo.Date(time.Date(2017, 4, 1, 0, 0, 0, 0, GMT))
invbalance := ofxgo.InvBalance{
AvailCash: ofxgo.Amount(availcash),
MarginBalance: ofxgo.Amount(marginbalance),
ShortBalance: ofxgo.Amount(shortbalance),
AvailCash: availcash,
MarginBalance: marginbalance,
ShortBalance: shortbalance,
BalList: []ofxgo.Balance{
ofxgo.Balance{
Name: "Sweep Int Rate",
Desc: "Current interest rate for sweep account balances",
BalType: "PERCENT",
Value: ofxgo.Amount(balvalue),
Value: balvalue,
DtAsOf: &baldtasof,
},
},
}
var balamt, availbalamt, posunits1, posunitprice1, posmktval1, posunits2, posunitprice2, posmktval2, oounits1, oolimitprice1, oounits2, oolimitprice2 big.Rat
var balamt, availbalamt, posunits1, posunitprice1, posmktval1, posunits2, posunitprice2, posmktval2, oounits1, oolimitprice1, oounits2, oolimitprice2 ofxgo.Amount
balamt.SetFrac64(20029, 100)
availbalamt.SetFrac64(20029, 100)
posunits1.SetFrac64(200, 1)
@ -422,9 +421,9 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
},
HeldInAcct: "CASH",
PosType: "LONG",
Units: ofxgo.Amount(posunits1),
UnitPrice: ofxgo.Amount(posunitprice1),
MktVal: ofxgo.Amount(posmktval1),
Units: posunits1,
UnitPrice: posunitprice1,
MktVal: posmktval1,
DtPriceAsOf: ofxgo.Date(time.Date(2017, 3, 31, 16, 0, 0, 0, GMT)),
Memo: "Price as of previous close",
},
@ -437,9 +436,9 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
},
HeldInAcct: "CASH",
PosType: "LONG",
Units: ofxgo.Amount(posunits2),
UnitPrice: ofxgo.Amount(posunitprice2),
MktVal: ofxgo.Amount(posmktval2),
Units: posunits2,
UnitPrice: posunitprice2,
MktVal: posmktval2,
DtPriceAsOf: ofxgo.Date(time.Date(2017, 3, 31, 16, 0, 0, 0, GMT)),
},
},
@ -454,11 +453,11 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
UniqueIdType: "CUSIP",
},
DtPlaced: ofxgo.Date(time.Date(2017, 3, 10, 12, 44, 45, 0, GMT)),
Units: ofxgo.Amount(oounits1),
Units: oounits1,
SubAcct: "CASH",
Duration: "GOODTILCANCEL",
Restriction: "NONE",
LimitPrice: ofxgo.Amount(oolimitprice1),
LimitPrice: oolimitprice1,
},
BuyType: "BUY",
UnitType: "SHARES",
@ -471,11 +470,11 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
UniqueIdType: "CUSIP",
},
DtPlaced: ofxgo.Date(time.Date(2017, 3, 24, 3, 19, 0, 0, GMT)),
Units: ofxgo.Amount(oounits2),
Units: oounits2,
SubAcct: "CASH",
Duration: "GOODTILCANCEL",
Restriction: "ALLORNONE",
LimitPrice: ofxgo.Amount(oolimitprice2),
LimitPrice: oolimitprice2,
},
BuyType: "BUY",
},
@ -483,7 +482,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
}
expected.InvStmt = append(expected.InvStmt, &statementResponse)
var yield1, yield2, strikeprice big.Rat
var yield1, yield2, strikeprice ofxgo.Amount
yield1.SetFrac64(192, 100)
yield2.SetFrac64(17, 1)
strikeprice.SetFrac64(79, 1)
@ -500,7 +499,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
Ticker: "SPY",
FiId: "99184",
},
Yield: ofxgo.Amount(yield1),
Yield: yield1,
AssetClass: "OTHER",
},
ofxgo.OptInfo{
@ -514,7 +513,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
FiId: "882919",
},
OptType: "PUT",
StrikePrice: ofxgo.Amount(strikeprice),
StrikePrice: strikeprice,
DtExpire: ofxgo.Date(time.Date(2017, 9, 1, 0, 0, 0, 0, GMT)),
ShPerCtrct: 100,
SecId: &ofxgo.SecurityId{
@ -533,7 +532,7 @@ func TestUnmarshalInvStatementResponse(t *testing.T) {
Ticker: "WHAT",
FiId: "883897",
},
Yield: ofxgo.Amount(yield2),
Yield: yield2,
AssetClass: "SMALLSTOCK",
},
ofxgo.MFInfo{
@ -734,7 +733,7 @@ NEWFILEUID: NONE
expected.Signon.Fid = "1000"
// Ignored <INTU.BID>1000
var units1, unitprice1, commission1, fees1, total1, units2, units3 big.Rat
var units1, unitprice1, commission1, fees1, total1, units2, units3 ofxgo.Amount
units1.SetFrac64(-1, 1)
unitprice1.SetFrac64(35, 100)
commission1.SetFrac64(885, 100)
@ -762,11 +761,11 @@ NEWFILEUID: NONE
UniqueId: "SPY161216C00226000",
UniqueIdType: "CUSIP",
},
Units: ofxgo.Amount(units1),
UnitPrice: ofxgo.Amount(unitprice1),
Commission: ofxgo.Amount(commission1),
Fees: ofxgo.Amount(fees1),
Total: ofxgo.Amount(total1),
Units: units1,
UnitPrice: unitprice1,
Commission: commission1,
Fees: fees1,
Total: total1,
SubAcctSec: "CASH",
SubAcctFund: "CASH",
},
@ -784,7 +783,7 @@ NEWFILEUID: NONE
UniqueIdType: "CUSIP",
},
OptAction: "ASSIGN",
Units: ofxgo.Amount(units2),
Units: units2,
ShPerCtrct: 100,
SubAcctSec: "CASH",
},
@ -799,25 +798,25 @@ NEWFILEUID: NONE
UniqueIdType: "CUSIP",
},
OptAction: "ASSIGN",
Units: ofxgo.Amount(units3),
Units: units3,
ShPerCtrct: 100,
SubAcctSec: "CASH",
},
},
}
var availcash, marginbalance, shortbalance big.Rat
var availcash, marginbalance, shortbalance ofxgo.Amount
availcash.SetFrac64(0, 1)
marginbalance.SetFrac64(-0, 1)
shortbalance.SetFrac64(0, 1)
invbalance := ofxgo.InvBalance{
AvailCash: ofxgo.Amount(availcash),
MarginBalance: ofxgo.Amount(marginbalance),
ShortBalance: ofxgo.Amount(shortbalance),
AvailCash: availcash,
MarginBalance: marginbalance,
ShortBalance: shortbalance,
}
var posunits1, posunitprice1, posmktval1, posunits2, posunitprice2, posmktval2 big.Rat
var posunits1, posunitprice1, posmktval1, posunits2, posunitprice2, posmktval2 ofxgo.Amount
posunits1.SetFrac64(100, 1)
posunitprice1.SetFrac64(79, 1)
posmktval1.SetFrac64(79000, 1)
@ -847,9 +846,9 @@ NEWFILEUID: NONE
},
HeldInAcct: "CASH",
PosType: "LONG",
Units: ofxgo.Amount(posunits1),
UnitPrice: ofxgo.Amount(posunitprice1),
MktVal: ofxgo.Amount(posmktval1),
Units: posunits1,
UnitPrice: posunitprice1,
MktVal: posmktval1,
DtPriceAsOf: ofxgo.Date(time.Date(2017, 4, 3, 12, 0, 0, 0, GMT)),
},
},
@ -861,9 +860,9 @@ NEWFILEUID: NONE
},
HeldInAcct: "CASH",
PosType: "LONG",
Units: ofxgo.Amount(posunits2),
UnitPrice: ofxgo.Amount(posunitprice2),
MktVal: ofxgo.Amount(posmktval2),
Units: posunits2,
UnitPrice: posunitprice2,
MktVal: posmktval2,
DtPriceAsOf: ofxgo.Date(time.Date(2017, 4, 3, 12, 0, 0, 0, GMT)),
},
},
@ -872,7 +871,7 @@ NEWFILEUID: NONE
}
expected.InvStmt = append(expected.InvStmt, &statementResponse)
var strikeprice big.Rat
var strikeprice ofxgo.Amount
strikeprice.SetFrac64(226, 1)
seclist := ofxgo.SecurityList{
@ -897,7 +896,7 @@ NEWFILEUID: NONE
Ticker: "SPY 161216C00226000",
},
OptType: "CALL",
StrikePrice: ofxgo.Amount(strikeprice),
StrikePrice: strikeprice,
DtExpire: ofxgo.Date(time.Date(2016, 12, 16, 12, 0, 0, 0, GMT)),
ShPerCtrct: 100,
},

View File

@ -37,11 +37,12 @@ func (i Int) Equal(o Int) bool {
return i == o
}
type Amount big.Rat
type Amount struct {
big.Rat
}
func (a *Amount) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var value string
var b big.Rat
err := d.DecodeElement(&value, &start)
if err != nil {
@ -54,16 +55,14 @@ func (a *Amount) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// by a comma, so fix that up before attempting to parse it into big.Rat
value = strings.Replace(value, ",", ".", 1)
if _, ok := b.SetString(value); !ok {
return errors.New("Failed to parse OFX amount into big.Rat")
if _, ok := a.SetString(value); !ok {
return errors.New("Failed to parse OFX amount")
}
*a = Amount(b)
return nil
}
func (a Amount) String() string {
var b big.Rat = big.Rat(a)
return strings.TrimRight(strings.TrimRight(b.FloatString(100), "0"), ".")
return strings.TrimRight(strings.TrimRight(a.FloatString(100), "0"), ".")
}
func (a *Amount) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
@ -71,8 +70,7 @@ func (a *Amount) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
}
func (a Amount) Equal(o Amount) bool {
ratA := (*big.Rat)(&a)
return ratA.Cmp((*big.Rat)(&o)) == 0
return (&a).Cmp(&o.Rat) == 0
}
type Date time.Time

View File

@ -4,7 +4,6 @@ import (
"fmt"
"github.com/aclindsa/go/src/encoding/xml"
"github.com/aclindsa/ofxgo"
"math/big"
"reflect"
"testing"
"time"
@ -76,50 +75,47 @@ func TestUnmarshalInt(t *testing.T) {
func TestMarshalAmount(t *testing.T) {
var a ofxgo.Amount
var b *big.Rat = (*big.Rat)(&a)
b.SetFrac64(8, 1)
a.SetFrac64(8, 1)
marshalHelper(t, "8", &a)
b.SetFrac64(1, 8)
a.SetFrac64(1, 8)
marshalHelper(t, "0.125", &a)
b.SetFrac64(-1, 200)
a.SetFrac64(-1, 200)
marshalHelper(t, "-0.005", &a)
b.SetInt64(0)
a.SetInt64(0)
marshalHelper(t, "0", &a)
b.SetInt64(-768276587425)
a.SetInt64(-768276587425)
marshalHelper(t, "-768276587425", &a)
b.SetFrac64(1, 12)
a.SetFrac64(1, 12)
marshalHelper(t, "0.0833333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", &a)
}
func TestUnmarshalAmount(t *testing.T) {
var a, overwritten ofxgo.Amount
var b *big.Rat = (*big.Rat)(&a)
// Amount/big.Rat needs a special equality test because reflect.DeepEqual
// doesn't always return equal for two values that big.Rat.Cmp() does
eq := func(a, b interface{}) bool {
if amountA, ok := a.(*ofxgo.Amount); ok {
if amountB, ok2 := b.(*ofxgo.Amount); ok2 {
ratA := (*big.Rat)(amountA)
return ratA.Cmp((*big.Rat)(amountB)) == 0
return amountA.Cmp(&amountB.Rat) == 0
}
}
return false
}
b.SetFrac64(12, 1)
a.SetFrac64(12, 1)
unmarshalHelper2(t, "12", &a, &overwritten, eq)
b.SetFrac64(-21309, 100)
a.SetFrac64(-21309, 100)
unmarshalHelper2(t, "-213.09", &a, &overwritten, eq)
b.SetFrac64(8192, 1000)
a.SetFrac64(8192, 1000)
unmarshalHelper2(t, "8.192", &a, &overwritten, eq)
unmarshalHelper2(t, "+8.192", &a, &overwritten, eq)
b.SetInt64(0)
a.SetInt64(0)
unmarshalHelper2(t, "0", &a, &overwritten, eq)
unmarshalHelper2(t, "+0", &a, &overwritten, eq)
unmarshalHelper2(t, "-0", &a, &overwritten, eq)
b.SetInt64(-19487135)
a.SetInt64(-19487135)
unmarshalHelper2(t, "-19487135", &a, &overwritten, eq)
// Make sure stray newlines are handled properly
unmarshalHelper2(t, "-19487135\n", &a, &overwritten, eq)