"""test_filters - Unit tests for filter functions""" # Copyright © 2020 Brett Smith # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import itertools import pytest from . import testutil from datetime import date from conservancy_beancount import data from conservancy_beancount import filters MISSING_POSTING = testutil.Posting('', 0) @pytest.fixture def cc_txn_pair(): dates = testutil.date_seq() txn_meta = { 'payee': 'Smith-Dakota', 'rt-id': 'rt:550', } return [ testutil.Transaction( **txn_meta, date=next(dates), receipt='CCReceipt.pdf', metadate=next(dates), postings=[ ('Liabilities:CreditCard', -36), ('Expenses:Other', 35), ('Expenses:Tax:Sales', 1), ], ), testutil.Transaction( **txn_meta, date=next(dates), receipt='CCPayment.pdf', metadate=next(dates), postings=[ ('Liabilities:CreditCard', 36), ('Assets:Checking', -36, {'statement': 'CheckingStatement.pdf'}), ], ), ] def check_filter(actual, entries, expected_indexes): postings = [post for txn in entries for post in txn.postings] expected = (postings[ii] for ii in expected_indexes) for actual_post, expected_post in itertools.zip_longest( actual, expected, fillvalue=MISSING_POSTING, ): assert actual_post[:-1] == expected_post[:-1] @pytest.mark.parametrize('key,value,expected_indexes', [ ('entity', 'Smith-Dakota', range(5)), ('receipt', 'CCReceipt.pdf', range(3)), ('receipt', 'CCPayment.pdf', range(3, 5)), ('receipt', 'CC', ()), ('statement', 'CheckingStatement.pdf', [4]), ('metadate', date(2020, 9, 2), range(3)), ('metadate', date(2020, 9, 4), range(3, 5)), ('BadKey', '', ()), ('emptykey', '', ()), ]) def test_filter_meta_equal(cc_txn_pair, key, value, expected_indexes): postings = data.Posting.from_entries(cc_txn_pair) actual = filters.filter_meta_equal(postings, key, value) check_filter(actual, cc_txn_pair, expected_indexes) @pytest.mark.parametrize('key,regexp,expected_indexes', [ ('entity', '^Smith-', range(5)), ('receipt', r'\.pdf$', range(5)), ('receipt', 'Receipt', range(3)), ('statement', '.', [4]), ('metadate', 'foo', ()), ('BadKey', '.', ()), ('emptykey', '.', ()), ]) def test_filter_meta_match(cc_txn_pair, key, regexp, expected_indexes): postings = data.Posting.from_entries(cc_txn_pair) actual = filters.filter_meta_match(postings, key, regexp) check_filter(actual, cc_txn_pair, expected_indexes) @pytest.mark.parametrize('ticket_id,expected_indexes', [ (550, range(5)), ('550', range(5)), (55, ()), ('55', ()), (50, ()), ('.', ()), ]) def test_filter_for_rt_id(cc_txn_pair, ticket_id, expected_indexes): postings = data.Posting.from_entries(cc_txn_pair) actual = filters.filter_for_rt_id(postings, ticket_id) check_filter(actual, cc_txn_pair, expected_indexes) @pytest.mark.parametrize('rt_id', [ 'rt:450/', ' rt:450 rt:540', 'rt://ticket/450', 'rt://ticket/450/', ' rt://ticket/450', 'rt://ticket/450 rt://ticket/540', ]) def test_filter_for_rt_id_syntax_variations(rt_id): entries = [testutil.Transaction(**{'rt-id': rt_id}, postings=[ ('Income:Donations', -10), ('Assets:Cash', 10), ])] postings = data.Posting.from_entries(entries) actual = filters.filter_for_rt_id(postings, 450) check_filter(actual, entries, range(2)) def test_filter_for_rt_id_uses_first_link_only(): entries = [testutil.Transaction(postings=[ ('Income:Donations', -10, {'rt-id': 'rt:1 rt:350'}), ('Assets:Cash', 10, {'rt-id': 'rt://ticket/2 rt://ticket/350'}), ])] postings = data.Posting.from_entries(entries) actual = filters.filter_for_rt_id(postings, 350) check_filter(actual, entries, ()),