Files
@ efe9bd88550d
Branch filter:
Location: NPO-Accounting/conservancy_beancount/tests/test_cliutil_searchterm.py - annotation
efe9bd88550d
5.1 KiB
text/x-python
ledger: Change default report dates.
The old defaults were optimized for the audit report.
The new defaults provide more helpful ad hoc reports.
The latter will be run more often and more quickly, so it's
worth optimizing the defaults for them.
The old defaults were optimized for the audit report.
The new defaults provide more helpful ad hoc reports.
The latter will be run more often and more quickly, so it's
worth optimizing the defaults for them.
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 156 157 158 159 160 161 162 163 164 | cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 cd1b28ae3eb1 | """test_cliutil_searchterm - Unit tests for cliutil.SearchTerm"""
# 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 <https://www.gnu.org/licenses/>.
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)
|