Files
@ 087b3274e7d2
Branch filter:
Location: NPO-Accounting/conservancy_beancount/tests/test_cliutil_searchterm.py
087b3274e7d2
4.6 KiB
text/x-python
ledger: Dedicated reporting tab for Expenses:Payroll.
To better accommodate the new payroll-type metadata.
To better accommodate the new payroll-type metadata.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | """test_cliutil_searchterm - Unit tests for cliutil.SearchTerm"""
# Copyright © 2020 Brett Smith
# License: AGPLv3-or-later WITH Beancount-Plugin-Additional-Permission-1.0
#
# Full copyright and licensing details can be found at toplevel file
# LICENSE.txt in the repository.
import re
import pytest
from . import testutil
from conservancy_beancount import cliutil
from conservancy_beancount import data
TICKET_LINKS = [
'123',
'rt:123',
'rt://ticket/123',
]
ATTACHMENT_LINKS = [
'123/456',
'rt:123/456',
'rt://ticket/123/attachments/456',
]
REPOSITORY_LINKS = [
'789.pdf',
'Documents/789.pdf',
]
RT_LINKS = TICKET_LINKS + ATTACHMENT_LINKS
ALL_LINKS = RT_LINKS + REPOSITORY_LINKS
INVALID_METADATA_KEYS = [
# Must start with a-z
';key',
' key',
'ákey',
'Key',
# Must only contain alphanumerics, -, and _
'key;',
'key ',
'a.key',
]
@pytest.fixture(scope='module')
def defaults_parser():
return cliutil.SearchTerm.arg_parser('document', 'rt-id')
@pytest.fixture(scope='module')
def one_default_parser():
return cliutil.SearchTerm.arg_parser('default')
@pytest.fixture(scope='module')
def no_default_parser():
return cliutil.SearchTerm.arg_parser()
def check_link_regexp(regexp, match_s, first_link_only=False):
assert regexp
assert re.search(regexp, match_s)
assert re.search(regexp, match_s + ' postlink')
assert re.search(regexp, match_s + '0') is None
assert re.search(regexp, '1' + match_s) is None
end_match = re.search(regexp, 'prelink ' + match_s)
if first_link_only:
assert end_match is None
else:
assert end_match
@pytest.mark.parametrize('arg', TICKET_LINKS)
def test_search_term_parse_ticket(defaults_parser, arg):
key, regexp = defaults_parser(arg)
assert key == 'rt-id'
check_link_regexp(regexp, 'rt:123', first_link_only=True)
check_link_regexp(regexp, 'rt://ticket/123', first_link_only=True)
@pytest.mark.parametrize('arg', ATTACHMENT_LINKS)
def test_search_term_parse_attachment(defaults_parser, arg):
key, regexp = defaults_parser(arg)
assert key == 'document'
check_link_regexp(regexp, 'rt:123/456')
check_link_regexp(regexp, 'rt://ticket/123/attachments/456')
@pytest.mark.parametrize('key,query', testutil.combine_values(
['approval', 'contract', 'invoice'],
RT_LINKS,
))
def test_search_term_parse_metadata_rt_shortcut(defaults_parser, key, query):
actual_key, regexp = defaults_parser(f'{key}={query}')
assert actual_key == key
if query.endswith('/456'):
check_link_regexp(regexp, 'rt:123/456')
check_link_regexp(regexp, 'rt://ticket/123/attachments/456')
else:
check_link_regexp(regexp, 'rt:123')
check_link_regexp(regexp, 'rt://ticket/123')
@pytest.mark.parametrize('search_prefix', [
'',
'approval=',
'contract=',
'invoice=',
])
def test_search_term_parse_repo_link(defaults_parser, search_prefix):
document = '1234.pdf'
actual_key, regexp = defaults_parser(f'{search_prefix}{document}')
if search_prefix:
expect_key = search_prefix.rstrip('=')
else:
expect_key = 'document'
assert actual_key == expect_key
check_link_regexp(regexp, document)
@pytest.mark.parametrize('search,unmatched', [
('1234.pdf', '1234_pdf'),
])
def test_search_term_parse_regexp_escaping(defaults_parser, search, unmatched):
_, regexp = defaults_parser(search)
assert re.search(regexp, unmatched) is None
@pytest.mark.parametrize('key', INVALID_METADATA_KEYS)
def test_non_metadata_key(one_default_parser, key):
document = f'{key}=890'
key, pattern = one_default_parser(document)
assert key == 'default'
check_link_regexp(pattern, document)
@pytest.mark.parametrize('arg', ALL_LINKS)
def test_default_parser(one_default_parser, arg):
key, _ = one_default_parser(arg)
assert key == 'default'
@pytest.mark.parametrize('arg', ALL_LINKS + [
f'{nonkey}={link}' for nonkey, link in testutil.combine_values(
INVALID_METADATA_KEYS, ALL_LINKS,
)
])
def test_no_key(no_default_parser, arg):
with pytest.raises(ValueError):
key, pattern = no_default_parser(arg)
@pytest.mark.parametrize('key', ['zero', 'one', 'two'])
def test_filter_postings(key):
txn = testutil.Transaction(postings=[
('Income:Other', 3, {'one': '1', 'two': '2'}),
('Income:Other', 2, {'two': '2'}),
('Income:Other', 1, {'one': '1'}),
])
search = cliutil.SearchTerm(key, '.')
actual = list(search.filter_postings(data.Posting.from_txn(txn)))
assert len(actual) == 0 if key == 'zero' else 2
assert all(post.meta.get(key) for post in actual)
|