526 lines
15 KiB
Go
526 lines
15 KiB
Go
package qif
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
|
)
|
|
|
|
func TestQifDataReaderParse(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{
|
|
"!Type:Bank",
|
|
"D2024/10/9",
|
|
"T-123.45",
|
|
"^",
|
|
"D2024/10/12",
|
|
"T+234.56",
|
|
"^",
|
|
"!Type:Cash",
|
|
"D2024/9/1",
|
|
"T100.00",
|
|
"POpening Balance",
|
|
"L[Wallet]",
|
|
"^",
|
|
"!Type:Memorized",
|
|
"KC",
|
|
"T-123.45",
|
|
"12024/10/13",
|
|
"23",
|
|
"31",
|
|
"42",
|
|
"512.34",
|
|
"6100.45",
|
|
"7234.56",
|
|
"^",
|
|
"!Type:Invst",
|
|
"D2024/10/14",
|
|
"NBuy",
|
|
"YTest",
|
|
"I12.34",
|
|
"Q10",
|
|
"T-123.4",
|
|
"^",
|
|
"!Account",
|
|
"NTest Account",
|
|
"^",
|
|
"NWallet",
|
|
"^",
|
|
"!Type:Cat",
|
|
"NTest Category",
|
|
"I",
|
|
"^",
|
|
"!Type:Class",
|
|
"NTest Class",
|
|
"DFoo Bar",
|
|
"^",
|
|
},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.read(context)
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, 2, len(actualData.BankAccountTransactions))
|
|
assert.Equal(t, "2024/10/9", actualData.BankAccountTransactions[0].Date)
|
|
assert.Equal(t, "-123.45", actualData.BankAccountTransactions[0].Amount)
|
|
assert.Equal(t, "2024/10/12", actualData.BankAccountTransactions[1].Date)
|
|
assert.Equal(t, "+234.56", actualData.BankAccountTransactions[1].Amount)
|
|
|
|
assert.Equal(t, 1, len(actualData.CashAccountTransactions))
|
|
assert.Equal(t, "2024/9/1", actualData.CashAccountTransactions[0].Date)
|
|
assert.Equal(t, "100.00", actualData.CashAccountTransactions[0].Amount)
|
|
assert.Equal(t, "Opening Balance", actualData.CashAccountTransactions[0].Payee)
|
|
assert.Equal(t, "[Wallet]", actualData.CashAccountTransactions[0].Category)
|
|
|
|
assert.Equal(t, 1, len(actualData.MemorizedTransactions))
|
|
assert.Equal(t, qifCheckTransactionType, actualData.MemorizedTransactions[0].TransactionType)
|
|
assert.Equal(t, "-123.45", actualData.MemorizedTransactions[0].Amount)
|
|
assert.Equal(t, "2024/10/13", actualData.MemorizedTransactions[0].Amortization.FirstPaymentDate)
|
|
assert.Equal(t, "3", actualData.MemorizedTransactions[0].Amortization.TotalYearsForLoan)
|
|
assert.Equal(t, "1", actualData.MemorizedTransactions[0].Amortization.NumberOfPayments)
|
|
assert.Equal(t, "2", actualData.MemorizedTransactions[0].Amortization.NumberOfPeriodsPerYear)
|
|
assert.Equal(t, "12.34", actualData.MemorizedTransactions[0].Amortization.InterestRate)
|
|
assert.Equal(t, "100.45", actualData.MemorizedTransactions[0].Amortization.CurrentLoanBalance)
|
|
assert.Equal(t, "234.56", actualData.MemorizedTransactions[0].Amortization.OriginalLoanAmount)
|
|
|
|
assert.Equal(t, 1, len(actualData.InvestmentAccountTransactions))
|
|
assert.Equal(t, "2024/10/14", actualData.InvestmentAccountTransactions[0].Date)
|
|
assert.Equal(t, "Buy", actualData.InvestmentAccountTransactions[0].Action)
|
|
assert.Equal(t, "Test", actualData.InvestmentAccountTransactions[0].Security)
|
|
assert.Equal(t, "12.34", actualData.InvestmentAccountTransactions[0].Price)
|
|
assert.Equal(t, "10", actualData.InvestmentAccountTransactions[0].Quantity)
|
|
assert.Equal(t, "-123.4", actualData.InvestmentAccountTransactions[0].Amount)
|
|
|
|
assert.Equal(t, 2, len(actualData.Accounts))
|
|
assert.Equal(t, "Test Account", actualData.Accounts[0].Name)
|
|
assert.Equal(t, "Wallet", actualData.Accounts[1].Name)
|
|
|
|
assert.Equal(t, 1, len(actualData.Categories))
|
|
assert.Equal(t, "Test Category", actualData.Categories[0].Name)
|
|
assert.Equal(t, qifIncomeTransaction, actualData.Categories[0].CategoryType)
|
|
|
|
assert.Equal(t, 1, len(actualData.Classes))
|
|
assert.Equal(t, "Test Class", actualData.Classes[0].Name)
|
|
assert.Equal(t, "Foo Bar", actualData.Classes[0].Description)
|
|
}
|
|
|
|
func TestQifDataReaderParse_AccountEntryBeforeTransaction(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{
|
|
"!Account",
|
|
"NTest Account",
|
|
"^",
|
|
"!Type:Bank",
|
|
"D2024/10/9",
|
|
"T-123.45",
|
|
"^",
|
|
"D2024/10/12",
|
|
"T+234.56",
|
|
"^",
|
|
"!Account",
|
|
"NWallet",
|
|
"^",
|
|
"!Type:Cash",
|
|
"D2024/9/1",
|
|
"T100.00",
|
|
"POpening Balance",
|
|
"L[Wallet]",
|
|
"^",
|
|
},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.read(context)
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, 2, len(actualData.BankAccountTransactions))
|
|
assert.Equal(t, "2024/10/9", actualData.BankAccountTransactions[0].Date)
|
|
assert.Equal(t, "-123.45", actualData.BankAccountTransactions[0].Amount)
|
|
assert.Equal(t, "2024/10/12", actualData.BankAccountTransactions[1].Date)
|
|
assert.Equal(t, "+234.56", actualData.BankAccountTransactions[1].Amount)
|
|
|
|
assert.Equal(t, 1, len(actualData.CashAccountTransactions))
|
|
assert.Equal(t, "2024/9/1", actualData.CashAccountTransactions[0].Date)
|
|
assert.Equal(t, "100.00", actualData.CashAccountTransactions[0].Amount)
|
|
assert.Equal(t, "Opening Balance", actualData.CashAccountTransactions[0].Payee)
|
|
assert.Equal(t, "[Wallet]", actualData.CashAccountTransactions[0].Category)
|
|
|
|
assert.Equal(t, 2, len(actualData.Accounts))
|
|
assert.Equal(t, "Test Account", actualData.Accounts[0].Name)
|
|
assert.Equal(t, "Wallet", actualData.Accounts[1].Name)
|
|
}
|
|
|
|
func TestQifDataReaderParse_EmptyContent(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
_, err := reader.read(context)
|
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
|
}
|
|
|
|
func TestQifDataReaderParse_EmptyEntry(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{
|
|
"!Type:Bank",
|
|
"^",
|
|
"!Type:Cash",
|
|
"^",
|
|
"!Type:Memorized",
|
|
"^",
|
|
"!Type:Invst",
|
|
"^",
|
|
"!Account",
|
|
"^",
|
|
"!Type:Cat",
|
|
"^",
|
|
"!Type:Class",
|
|
"^",
|
|
},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.read(context)
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, 0, len(actualData.BankAccountTransactions))
|
|
assert.Equal(t, 0, len(actualData.CashAccountTransactions))
|
|
assert.Equal(t, 0, len(actualData.MemorizedTransactions))
|
|
assert.Equal(t, 0, len(actualData.InvestmentAccountTransactions))
|
|
assert.Equal(t, 0, len(actualData.Accounts))
|
|
assert.Equal(t, 0, len(actualData.Categories))
|
|
assert.Equal(t, 0, len(actualData.Classes))
|
|
}
|
|
|
|
func TestQifDataReaderParse_UnsupportedEntryHeader(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{
|
|
"!Type:Bank",
|
|
"D2024/10/9",
|
|
"T-123.45",
|
|
"^",
|
|
"!Type:Unknown",
|
|
"D2024/10/11",
|
|
"T100.00",
|
|
"^",
|
|
},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.read(context)
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, 1, len(actualData.BankAccountTransactions))
|
|
assert.Equal(t, "2024/10/9", actualData.BankAccountTransactions[0].Date)
|
|
assert.Equal(t, "-123.45", actualData.BankAccountTransactions[0].Amount)
|
|
}
|
|
|
|
func TestQifDataReaderParse_UnsupportedLine(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{
|
|
"!Type:Bank",
|
|
"D2024/10/9",
|
|
"T-123.45",
|
|
"^",
|
|
"!Option:Unknown",
|
|
"D2024/10/11",
|
|
"T100.00",
|
|
"^",
|
|
},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.read(context)
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, 2, len(actualData.BankAccountTransactions))
|
|
assert.Equal(t, "2024/10/9", actualData.BankAccountTransactions[0].Date)
|
|
assert.Equal(t, "-123.45", actualData.BankAccountTransactions[0].Amount)
|
|
assert.Equal(t, "2024/10/11", actualData.BankAccountTransactions[1].Date)
|
|
assert.Equal(t, "100.00", actualData.BankAccountTransactions[1].Amount)
|
|
}
|
|
|
|
func TestQifDataReaderParse_NewEntryHeaderAfterUnclosedEntry(t *testing.T) {
|
|
reader := &qifDataReader{
|
|
allLines: []string{
|
|
"!Type:Bank",
|
|
"D2024/10/9",
|
|
"T-123.45",
|
|
"!Type:Cash",
|
|
"D2024/9/1",
|
|
"T100.00",
|
|
"POpening Balance",
|
|
"L[Wallet]",
|
|
"^",
|
|
},
|
|
}
|
|
context := core.NewNullContext()
|
|
|
|
_, err := reader.read(context)
|
|
assert.EqualError(t, err, errs.ErrInvalidQIFFile.Message)
|
|
}
|
|
|
|
func TestQifDataReaderParseTransaction_SupportedFields(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.parseTransaction(context, []string{
|
|
"D2024/10/12",
|
|
"T-123.45",
|
|
"C",
|
|
"N100",
|
|
"PFoo",
|
|
"MBar",
|
|
"AAddress 1",
|
|
"AAddress 2",
|
|
"AAddress 3",
|
|
"LTest Category",
|
|
"SPart1 Category",
|
|
"EPart1 Memo",
|
|
"$-100.00",
|
|
"SPart2 Category",
|
|
"EPart2 Memo",
|
|
"$-23.45",
|
|
}, false)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "2024/10/12", actualData.Date)
|
|
assert.Equal(t, "-123.45", actualData.Amount)
|
|
assert.Equal(t, qifClearedStatusUnreconciled, actualData.ClearedStatus)
|
|
assert.Equal(t, "100", actualData.Num)
|
|
assert.Equal(t, "Foo", actualData.Payee)
|
|
assert.Equal(t, "Bar", actualData.Memo)
|
|
assert.Equal(t, 3, len(actualData.Addresses))
|
|
assert.Equal(t, "Address 1", actualData.Addresses[0])
|
|
assert.Equal(t, "Address 2", actualData.Addresses[1])
|
|
assert.Equal(t, "Address 3", actualData.Addresses[2])
|
|
assert.Equal(t, "Test Category", actualData.Category)
|
|
assert.Equal(t, 2, len(actualData.SubTransactionCategory))
|
|
assert.Equal(t, "Part1 Category", actualData.SubTransactionCategory[0])
|
|
assert.Equal(t, "Part2 Category", actualData.SubTransactionCategory[1])
|
|
assert.Equal(t, 2, len(actualData.SubTransactionMemo))
|
|
assert.Equal(t, "Part1 Memo", actualData.SubTransactionMemo[0])
|
|
assert.Equal(t, "Part2 Memo", actualData.SubTransactionMemo[1])
|
|
assert.Equal(t, 2, len(actualData.SubTransactionAmount))
|
|
assert.Equal(t, "-100.00", actualData.SubTransactionAmount[0])
|
|
assert.Equal(t, "-23.45", actualData.SubTransactionAmount[1])
|
|
}
|
|
|
|
func TestQifDataReaderParseMemorizedTransaction_SupportedFields(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.parseMemorizedTransaction(context, []string{
|
|
"KC",
|
|
"D2024/10/12",
|
|
"T-123.45",
|
|
"C*",
|
|
"N100",
|
|
"PFoo",
|
|
"MBar",
|
|
"12024/10/13",
|
|
"23",
|
|
"31",
|
|
"42",
|
|
"512.34",
|
|
"6100.45",
|
|
"7234.56",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifCheckTransactionType, actualData.TransactionType)
|
|
assert.Equal(t, "2024/10/12", actualData.Date)
|
|
assert.Equal(t, "-123.45", actualData.Amount)
|
|
assert.Equal(t, qifClearedStatusCleared, actualData.ClearedStatus)
|
|
assert.Equal(t, "100", actualData.Num)
|
|
assert.Equal(t, "Foo", actualData.Payee)
|
|
assert.Equal(t, "Bar", actualData.Memo)
|
|
assert.Equal(t, "2024/10/13", actualData.Amortization.FirstPaymentDate)
|
|
assert.Equal(t, "3", actualData.Amortization.TotalYearsForLoan)
|
|
assert.Equal(t, "1", actualData.Amortization.NumberOfPayments)
|
|
assert.Equal(t, "2", actualData.Amortization.NumberOfPeriodsPerYear)
|
|
assert.Equal(t, "12.34", actualData.Amortization.InterestRate)
|
|
assert.Equal(t, "100.45", actualData.Amortization.CurrentLoanBalance)
|
|
assert.Equal(t, "234.56", actualData.Amortization.OriginalLoanAmount)
|
|
|
|
actualData, err = reader.parseMemorizedTransaction(context, []string{"KD"})
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifDepositTransactionType, actualData.TransactionType)
|
|
|
|
actualData, err = reader.parseMemorizedTransaction(context, []string{"KP"})
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifPaymentTransactionType, actualData.TransactionType)
|
|
|
|
actualData, err = reader.parseMemorizedTransaction(context, []string{"KI"})
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifInvestmentTransactionType, actualData.TransactionType)
|
|
|
|
actualData, err = reader.parseMemorizedTransaction(context, []string{"KE"})
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifElectronicPayeeTransactionType, actualData.TransactionType)
|
|
}
|
|
|
|
func TestQifDataReaderParseInvestmentTransaction_SupportedFields(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.parseInvestmentTransaction(context, []string{
|
|
"D2024/10/12",
|
|
"NBuy",
|
|
"YTest",
|
|
"I12.34",
|
|
"Q10",
|
|
"T-123.4",
|
|
"CR",
|
|
"PFoo",
|
|
"MBar",
|
|
"OTest2",
|
|
"LAccount Name",
|
|
"$100",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "2024/10/12", actualData.Date)
|
|
assert.Equal(t, "Buy", actualData.Action)
|
|
assert.Equal(t, "Test", actualData.Security)
|
|
assert.Equal(t, "12.34", actualData.Price)
|
|
assert.Equal(t, "10", actualData.Quantity)
|
|
assert.Equal(t, "-123.4", actualData.Amount)
|
|
assert.Equal(t, qifClearedStatusReconciled, actualData.ClearedStatus)
|
|
assert.Equal(t, "Foo", actualData.Text)
|
|
assert.Equal(t, "Bar", actualData.Memo)
|
|
assert.Equal(t, "Test2", actualData.Commission)
|
|
assert.Equal(t, "Account Name", actualData.AccountForTransfer)
|
|
assert.Equal(t, "100", actualData.AmountTransferred)
|
|
}
|
|
|
|
func TestQifDataReaderParseAccount_SupportedFields(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.parseAccount(context, []string{
|
|
"NAccount Name",
|
|
"TAccount Type",
|
|
"DSome Text",
|
|
"L1234.56",
|
|
"/2024/10/12",
|
|
"$123.45",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "Account Name", actualData.Name)
|
|
assert.Equal(t, "Account Type", actualData.AccountType)
|
|
assert.Equal(t, "Some Text", actualData.Description)
|
|
assert.Equal(t, "1234.56", actualData.CreditLimit)
|
|
assert.Equal(t, "2024/10/12", actualData.StatementBalanceDate)
|
|
assert.Equal(t, "123.45", actualData.StatementBalanceAmount)
|
|
}
|
|
|
|
func TestQifDataReaderParseCategory_SupportedFields(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.parseCategory(context, []string{
|
|
"NCategory Name:Sub Category Name",
|
|
"DSome Text",
|
|
"T",
|
|
"I",
|
|
"B123.45",
|
|
"RTest",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "Category Name:Sub Category Name", actualData.Name)
|
|
assert.Equal(t, "Some Text", actualData.Description)
|
|
assert.Equal(t, true, actualData.TaxRelated)
|
|
assert.Equal(t, qifIncomeTransaction, actualData.CategoryType)
|
|
assert.Equal(t, "123.45", actualData.BudgetAmount)
|
|
assert.Equal(t, "Test", actualData.TaxScheduleInformation)
|
|
|
|
actualData2, err := reader.parseCategory(context, []string{
|
|
"NCategory Name:Sub Category Name",
|
|
"DSome Text",
|
|
"E",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "Category Name:Sub Category Name", actualData2.Name)
|
|
assert.Equal(t, "Some Text", actualData2.Description)
|
|
assert.Equal(t, false, actualData2.TaxRelated)
|
|
assert.Equal(t, qifExpenseTransaction, actualData2.CategoryType)
|
|
|
|
actualData3, err := reader.parseCategory(context, []string{
|
|
"NCategory Name:Sub Category Name",
|
|
"DSome Text",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "Category Name:Sub Category Name", actualData3.Name)
|
|
assert.Equal(t, "Some Text", actualData3.Description)
|
|
assert.Equal(t, qifExpenseTransaction, actualData3.CategoryType)
|
|
}
|
|
|
|
func TestQifDataReaderParseClass_SupportedFields(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualData, err := reader.parseClass(context, []string{
|
|
"NClass Name",
|
|
"DSome Text",
|
|
})
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, "Class Name", actualData.Name)
|
|
assert.Equal(t, "Some Text", actualData.Description)
|
|
}
|
|
|
|
func TestQifDataReaderParse_UnsupportedFieldsOrValues(t *testing.T) {
|
|
reader := &qifDataReader{}
|
|
context := core.NewNullContext()
|
|
|
|
actualTransactionData, err := reader.parseTransaction(context, []string{
|
|
"ZTest",
|
|
"CZ",
|
|
"",
|
|
}, false)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifClearedStatusUnreconciled, actualTransactionData.ClearedStatus)
|
|
|
|
actualMemorizedTransactionData, err := reader.parseMemorizedTransaction(context, []string{
|
|
"ZTest",
|
|
"KZ",
|
|
"",
|
|
})
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, qifInvalidTransactionType, actualMemorizedTransactionData.TransactionType)
|
|
|
|
_, err = reader.parseInvestmentTransaction(context, []string{
|
|
"ZTest",
|
|
"",
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
_, err = reader.parseAccount(context, []string{
|
|
"ZTest",
|
|
"",
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
_, err = reader.parseCategory(context, []string{
|
|
"ZTest",
|
|
"",
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
_, err = reader.parseClass(context, []string{
|
|
"ZTest",
|
|
"",
|
|
})
|
|
assert.Nil(t, err)
|
|
}
|