summaryrefslogtreecommitdiff
path: root/tests/test_parse.py
diff options
context:
space:
mode:
authorAndrew Shadura <andrewsh@debian.org>2016-10-19 18:02:05 +0200
committerAndrew Shadura <andrewsh@debian.org>2016-10-19 18:02:05 +0200
commitd8216aeb9c12ea81d9941edc6eff39be32c24aca (patch)
tree1ad1a1dd693ba915dcda076adf037964c9d6132f /tests/test_parse.py
parentbdbd753fe4ab2de979939bae4caf93b16f6b5efc (diff)
Imported Upstream version 0.15
Diffstat (limited to 'tests/test_parse.py')
-rw-r--r--tests/test_parse.py207
1 files changed, 196 insertions, 11 deletions
diff --git a/tests/test_parse.py b/tests/test_parse.py
index 35260ce..476b28e 100644
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -1,17 +1,18 @@
from __future__ import absolute_import
-from ofxparse.ofxparse import soup_maker
+import os
from datetime import datetime, timedelta
from decimal import Decimal
from unittest import TestCase
import sys
-sys.path.append('..')
+sys.path.insert(0, os.path.abspath('..'))
import six
from .support import open_file
from ofxparse import OfxParser, AccountType, Account, Statement, Transaction
-from ofxparse.ofxparse import OfxFile, OfxPreprocessedFile, OfxParserException
+from ofxparse.ofxparse import OfxFile, OfxPreprocessedFile, OfxParserException, soup_maker
+
class TestOfxPreprocessedFile(TestCase):
@@ -41,8 +42,8 @@ NEWFILEUID:NONE
<OFX><DTASOF><![CDATA[></tricky]]><LEAVE ALONE></DTASOF><VAL.UE>a</VAL.UE><VAL_UE>b</VAL_UE><TE_ST></TE_ST><TE.ST></TE.ST><INVBAL><BALLIST><BAL><NAME>Net</NAME><DTASOF>2222</DTASOF></BAL><BAL><NAME>Gross</NAME><DTASOF>3333</DTASOF></BAL></BALLIST></INVBAL></OFX>
"""
ofx_file = OfxPreprocessedFile(fh)
- data = ofx_file.fh.read()
- self.assertEqual(data,expect)
+ data = ofx_file.fh.read()
+ self.assertEqual(data, expect)
def testHeaders(self):
expect = {"OFXHEADER": six.u("100"),
@@ -124,7 +125,6 @@ NEWFILEUID:NONE
self.assertEquals(len(ofx_file.headers.keys()), 2)
-
class TestOfxFile(TestCase):
def testHeaders(self):
expect = {"OFXHEADER": six.u("100"),
@@ -219,7 +219,7 @@ class TestParse(TestCase):
def testThatParseFailsIfAPathIsPassedIn(self):
# A file handle should be passed in, not the path.
- self.assertRaises(RuntimeError, OfxParser.parse, '/foo/bar')
+ self.assertRaises(TypeError, OfxParser.parse, '/foo/bar')
def testThatParseReturnsAResultWithABankAccount(self):
ofx = OfxParser.parse(open_file('bank_medium.ofx'))
@@ -232,11 +232,15 @@ class TestParse(TestCase):
self.assertEquals('00', ofx.account.branch_id)
self.assertEquals('CHECKING', ofx.account.account_type)
self.assertEquals(Decimal('382.34'), ofx.account.statement.balance)
+ self.assertEquals(datetime(2009, 5, 23, 12, 20, 17),
+ ofx.account.statement.balance_date)
# Todo: support values in decimal or int form.
# self.assertEquals('15',
# ofx.bank_account.statement.balance_in_pennies)
self.assertEquals(
Decimal('682.34'), ofx.account.statement.available_balance)
+ self.assertEquals(datetime(2009, 5, 23, 12, 20, 17),
+ ofx.account.statement.available_balance_date)
self.assertEquals(
datetime(2009, 4, 1), ofx.account.statement.start_date)
self.assertEquals(
@@ -271,10 +275,13 @@ class TestStringToDate(TestCase):
self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string)
bad_but_close_string = '881103'
- self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string)
+ self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_but_close_string)
no_month_string = '19881301'
- self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string)
+ self.assertRaises(ValueError, OfxParser.parseOfxDateTime, no_month_string)
+
+ def test_returns_none(self):
+ self.assertIsNone(OfxParser.parseOfxDateTime('00000000'))
def test_parses_correct_time(self):
'''Test whether it can parse correct time for some valid time fields'''
@@ -387,8 +394,58 @@ class TestParseStatement(TestCase):
datetime(2009, 5, 23, 12, 20, 17), statement.end_date)
self.assertEquals(1, len(statement.transactions))
self.assertEquals(Decimal('382.34'), statement.balance)
+ self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.balance_date)
self.assertEquals(Decimal('682.34'), statement.available_balance)
+ self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.available_balance_date)
+ def testThatParseStatementWithBlankDatesReturnsAStatement(self):
+ input = '''
+<STMTTRNRS>
+ <TRNUID>20090523122017
+ <STATUS>
+ <CODE>0
+ <SEVERITY>INFO
+ <MESSAGE>OK
+ </STATUS>
+ <STMTRS>
+ <CURDEF>CAD
+ <BANKACCTFROM>
+ <BANKID>160000100
+ <ACCTID>12300 000012345678
+ <ACCTTYPE>CHECKING
+ </BANKACCTFROM>
+ <BANKTRANLIST>
+ <DTSTART>00000000
+ <DTEND>00000000
+ <STMTTRN>
+ <TRNTYPE>POS
+ <DTPOSTED>20090401122017.000[-5:EST]
+ <TRNAMT>-6.60
+ <FITID>0000123456782009040100001
+ <NAME>MCDONALD'S #112
+ <MEMO>POS MERCHANDISE;MCDONALD'S #112
+ </STMTTRN>
+ </BANKTRANLIST>
+ <LEDGERBAL>
+ <BALAMT>382.34
+ <DTASOF>20090523122017
+ </LEDGERBAL>
+ <AVAILBAL>
+ <BALAMT>682.34
+ <DTASOF>20090523122017
+ </AVAILBAL>
+ </STMTRS>
+</STMTTRNRS>
+ '''
+ txn = soup_maker(input)
+ statement = OfxParser.parseStatement(txn.find('stmttrnrs'))
+ self.assertEquals(None, statement.start_date)
+ self.assertEquals(None, statement.end_date)
+ self.assertEquals(1, len(statement.transactions))
+ self.assertEquals(Decimal('382.34'), statement.balance)
+ self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.balance_date)
+ self.assertEquals(Decimal('682.34'), statement.available_balance)
+ self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.available_balance_date)
class TestStatement(TestCase):
def testThatANewStatementIsValid(self):
@@ -420,7 +477,6 @@ class TestParseTransaction(TestCase):
self.assertEquals("MCDONALD'S #112", transaction.payee)
self.assertEquals("POS MERCHANDISE;MCDONALD'S #112", transaction.memo)
-
def testThatParseTransactionWithFieldCheckNum(self):
input = '''
<STMTTRN>
@@ -436,6 +492,61 @@ class TestParseTransaction(TestCase):
transaction = OfxParser.parseTransaction(txn.find('stmttrn'))
self.assertEquals('700', transaction.checknum)
+ def testThatParseTransactionWithCommaAsDecimalPoint(self):
+ input = '''
+<STMTTRN>
+ <TRNTYPE>POS
+ <DTPOSTED>20090401122017.000[-5:EST]
+ <TRNAMT>-1006,60
+ <FITID>0000123456782009040100001
+ <NAME>MCDONALD'S #112
+ <MEMO>POS MERCHANDISE;MCDONALD'S #112
+</STMTTRN>
+'''
+ txn = soup_maker(input)
+ transaction = OfxParser.parseTransaction(txn.find('stmttrn'))
+ self.assertEquals(Decimal('-1006.60'), transaction.amount)
+
+ def testThatParseTransactionWithCommaAsDecimalPointAndDotAsSeparator(self):
+ input = '''
+<STMTTRN>
+ <TRNTYPE>POS
+ <DTPOSTED>20090401122017.000[-5:EST]
+ <TRNAMT>-1.006,60
+ <FITID>0000123456782009040100001
+ <NAME>MCDONALD'S #112
+ <MEMO>POS MERCHANDISE;MCDONALD'S #112
+</STMTTRN>
+'''
+ txn = soup_maker(input)
+ with self.assertRaises(OfxParserException):
+ transaction = OfxParser.parseTransaction(txn.find('stmttrn'))
+
+ def testThatParseTransactionWithNullAmountIgnored(self):
+ """A null transaction value is converted to 0.
+
+ Some banks use a null transaction to include interest
+ rate changes on statements.
+ """
+ input_template = '''
+<STMTTRN>
+ <TRNTYPE>DEP
+ <DTPOSTED>20130306
+ <TRNAMT>{amount}
+ <FITID>2013030601009100
+ <CHECKNUM>700
+ <MEMO>DEPOSITO ONLINE
+</STMTTRN>
+'''
+ for amount in ("null", "-null"):
+ input = input_template.format(amount=amount)
+ txn = soup_maker(input)
+
+ transaction = OfxParser.parseTransaction(txn.find('stmttrn'))
+
+ self.assertEquals(0, transaction.amount)
+
+
class TestTransaction(TestCase):
def testThatAnEmptyTransactionIsValid(self):
t = Transaction()
@@ -473,7 +584,6 @@ class TestInvestmentAccount(TestCase):
# Success!
-
class TestVanguardInvestmentStatement(TestCase):
def testForUnclosedTags(self):
ofx = OfxParser.parse(open_file('vanguard.ofx'))
@@ -497,6 +607,20 @@ class TestVanguardInvestmentStatement(TestCase):
self.assertEquals(len(ofx.security_list), 2)
+class TestVanguard401kStatement(TestCase):
+ def testReadTransfer(self):
+ ofx = OfxParser.parse(open_file('vanguard401k.ofx'))
+ self.assertTrue(hasattr(ofx, 'account'))
+ self.assertTrue(hasattr(ofx.account, 'statement'))
+ self.assertTrue(hasattr(ofx.account.statement, 'transactions'))
+ self.assertEquals(len(ofx.account.statement.transactions), 5)
+ self.assertEquals(ofx.account.statement.transactions[-1].id,
+ '1234567890123456795AAA')
+ self.assertEquals('transfer', ofx.account.statement.transactions[-1].type)
+ self.assertEquals(ofx.account.statement.transactions[-1].inv401ksource,
+ 'MATCH')
+
+
class TestFidelityInvestmentStatement(TestCase):
def testForUnclosedTags(self):
ofx = OfxParser.parse(open_file('fidelity.ofx'))
@@ -510,6 +634,66 @@ class TestFidelityInvestmentStatement(TestCase):
self.assertEquals(len(ofx.security_list), 7)
+class Test401InvestmentStatement(TestCase):
+ def testTransferAggregate(self):
+ ofx = OfxParser.parse(open_file('investment_401k.ofx'))
+ expected_txns = [{'id': '1',
+ 'type': 'buymf',
+ 'units': Decimal('8.846699'),
+ 'unit_price': Decimal('22.2908'),
+ 'total': Decimal('-197.2'),
+ 'security': 'FOO'},
+ {'id': '2',
+ 'type': 'transfer',
+ 'units': Decimal('6.800992'),
+ 'unit_price': Decimal('29.214856'),
+ 'total': Decimal('0.0'),
+ 'security': 'BAR'},
+ {'id': '3',
+ 'type': 'transfer',
+ 'units': Decimal('-9.060702'),
+ 'unit_price': Decimal('21.928764'),
+ 'total': Decimal('0.0'),
+ 'security': 'BAZ'}]
+ for txn, expected_txn in zip(ofx.account.statement.transactions, expected_txns):
+ self.assertEquals(txn.id, expected_txn['id'])
+ self.assertEquals(txn.type, expected_txn['type'])
+ self.assertEquals(txn.units, expected_txn['units'])
+ self.assertEquals(txn.unit_price, expected_txn['unit_price'])
+ self.assertEquals(txn.total, expected_txn['total'])
+ self.assertEquals(txn.security, expected_txn['security'])
+
+ expected_positions = [{'security': 'FOO',
+ 'units': Decimal('17.604312'),
+ 'unit_price': Decimal('22.517211')},
+ {'security': 'BAR',
+ 'units': Decimal('13.550983'),
+ 'unit_price': Decimal('29.214855')},
+ {'security': 'BAZ',
+ 'units': Decimal('0.0'),
+ 'unit_price': Decimal('0.0')}]
+ for pos, expected_pos in zip(ofx.account.statement.positions, expected_positions):
+ self.assertEquals(pos.security, expected_pos['security'])
+ self.assertEquals(pos.units, expected_pos['units'])
+ self.assertEquals(pos.unit_price, expected_pos['unit_price'])
+
+
+class TestSuncorpBankStatement(TestCase):
+ def testCDATATransactions(self):
+ ofx = OfxParser.parse(open_file('suncorp.ofx'))
+ accounts = ofx.accounts
+ self.assertEquals(len(accounts), 1)
+ account = accounts[0]
+ transactions = account.statement.transactions
+ self.assertEquals(len(transactions), 1)
+ transaction = transactions[0]
+ self.assertEquals(transaction.payee, "EFTPOS WDL HANDYWAY ALDI STORE")
+ self.assertEquals(
+ transaction.memo,
+ "EFTPOS WDL HANDYWAY ALDI STORE GEELONG WEST VICAU")
+ self.assertEquals(transaction.amount, Decimal("-16.85"))
+
+
class TestAccountInfoAggregation(TestCase):
def testForFourAccounts(self):
ofx = OfxParser.parse(open_file('account_listing_aggregation.ofx'))
@@ -596,6 +780,7 @@ class TestGracefulFailures(TestCase):
self.assertRaises(OfxParserException, OfxParser.parse,
open_file('fail_nice/empty_balance.ofx'))
+
class TestParseSonrs(TestCase):
def testSuccess(self):