From d8216aeb9c12ea81d9941edc6eff39be32c24aca Mon Sep 17 00:00:00 2001 From: Andrew Shadura Date: Wed, 19 Oct 2016 18:02:05 +0200 Subject: Imported Upstream version 0.15 --- tests/test_parse.py | 207 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 196 insertions(+), 11 deletions(-) (limited to 'tests/test_parse.py') 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 abNet2222Gross3333 """ 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 = ''' + + 20090523122017 + + 0 + INFO + OK + + + CAD + + 160000100 + 12300 000012345678 + CHECKING + + + 00000000 + 00000000 + + POS + 20090401122017.000[-5:EST] + -6.60 + 0000123456782009040100001 + MCDONALD'S #112 + POS MERCHANDISE;MCDONALD'S #112 + + + + 382.34 + 20090523122017 + + + 682.34 + 20090523122017 + + + + ''' + 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 = ''' @@ -436,6 +492,61 @@ class TestParseTransaction(TestCase): transaction = OfxParser.parseTransaction(txn.find('stmttrn')) self.assertEquals('700', transaction.checknum) + def testThatParseTransactionWithCommaAsDecimalPoint(self): + input = ''' + + POS + 20090401122017.000[-5:EST] + -1006,60 + 0000123456782009040100001 + MCDONALD'S #112 + POS MERCHANDISE;MCDONALD'S #112 + +''' + txn = soup_maker(input) + transaction = OfxParser.parseTransaction(txn.find('stmttrn')) + self.assertEquals(Decimal('-1006.60'), transaction.amount) + + def testThatParseTransactionWithCommaAsDecimalPointAndDotAsSeparator(self): + input = ''' + + POS + 20090401122017.000[-5:EST] + -1.006,60 + 0000123456782009040100001 + MCDONALD'S #112 + POS MERCHANDISE;MCDONALD'S #112 + +''' + 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 = ''' + + DEP + 20130306 + {amount} + 2013030601009100 + 700 + DEPOSITO ONLINE + +''' + 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): -- cgit v1.2.3