"""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, ()),