test_meta_receipt: Prepare for multiple fallback meta keys.

This commit is contained in:
Brett Smith 2020-05-15 16:46:20 -04:00
parent c1ecc48297
commit 51db04dc20

View file

@ -38,14 +38,15 @@ class PostType(enum.IntFlag):
class AccountForTesting(typing.NamedTuple):
name: str
required_types: PostType
fallback_meta: typing.Optional[str]
fallback_meta: typing.Sequence[str] = ()
def missing_message(self, include_fallback=True):
if self.fallback_meta is None or not include_fallback:
rest = ""
else:
rest = f"/{self.fallback_meta}"
return f"{self.name} missing {TEST_KEY}{rest}"
return "{} missing {}{}{}".format(
self.name,
TEST_KEY,
'/' if self.fallback_meta else '',
'/'.join(self.fallback_meta),
)
def wrong_type_message(self, wrong_value, key=TEST_KEY):
expect_type = 'Decimal' if key == 'check-id' else 'str'
@ -58,22 +59,25 @@ class AccountForTesting(typing.NamedTuple):
ACCOUNTS = [AccountForTesting._make(t) for t in [
('Assets:Bank:CheckCard', PostType.CREDIT, 'check'),
('Assets:Bank:CheckCard', PostType.DEBIT, 'check-id'),
('Assets:Cash', PostType.BOTH, None),
('Assets:Checking', PostType.CREDIT, 'check'),
('Assets:Checking', PostType.DEBIT, 'check-id'),
('Assets:Savings', PostType.BOTH, None),
('Liabilities:CreditCard', PostType.CREDIT, None),
('Liabilities:CreditCard', PostType.DEBIT, 'invoice'),
('Assets:Bank:CheckCard', PostType.CREDIT, ('check',)),
('Assets:Bank:CheckCard', PostType.DEBIT, ('check-id',)),
('Assets:Cash', PostType.BOTH, ()),
('Assets:Checking', PostType.CREDIT, ('check',)),
('Assets:Checking', PostType.DEBIT, ('check-id',)),
('Assets:Savings', PostType.BOTH, ()),
('Liabilities:CreditCard', PostType.CREDIT, ()),
('Liabilities:CreditCard', PostType.DEBIT, ('invoice',)),
]]
ACCOUNTS_WITH_LINK_FALLBACK = [acct for acct in ACCOUNTS
if acct.fallback_meta and acct.fallback_meta != 'check-id']
ACCOUNTS_WITH_CHECK_ID_FALLBACK = [acct for acct in ACCOUNTS
if acct.fallback_meta == 'check-id']
ACCOUNTS_WITHOUT_FALLBACKS = [acct for acct in ACCOUNTS if not acct.fallback_meta]
KNOWN_FALLBACKS = {acct.fallback_meta for acct in ACCOUNTS if acct.fallback_meta}
ACCOUNTS_WITH_LINK_FALLBACK = [
(acct, fallback_key)
for acct in ACCOUNTS
for fallback_key in acct.fallback_meta
if fallback_key != 'check-id'
]
ACCOUNTS_WITH_CHECK_ID_FALLBACK = [
acct for acct in ACCOUNTS if 'check-id' in acct.fallback_meta
]
# These are mostly fill-in values.
# We don't need to run every test on every value for these, just enough to
@ -181,67 +185,69 @@ def test_bad_type_receipt_on_txn(hook, test_acct, other_acct, value):
check(hook, test_acct, other_acct, test_acct.wrong_type_message(value),
txn_meta={TEST_KEY: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.LINK_METADATA_STRINGS,
))
def test_valid_fallback_on_post(hook, test_acct, other_acct, value):
check(hook, test_acct, other_acct, None,
post_meta={test_acct.fallback_meta: value})
def test_valid_fallback_on_post(hook, test_pair, other_acct, value):
test_acct, meta_key = test_pair
check(hook, test_acct, other_acct, None, post_meta={meta_key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.NON_LINK_METADATA_STRINGS,
))
def test_invalid_fallback_on_post(hook, test_acct, other_acct, value):
def test_invalid_fallback_on_post(hook, test_pair, other_acct, value):
test_acct, meta_key = test_pair
check(hook, test_acct, other_acct, {test_acct.missing_message()},
post_meta={test_acct.fallback_meta: value})
post_meta={meta_key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.NON_STRING_METADATA_VALUES,
))
def test_bad_type_fallback_on_post(hook, test_acct, other_acct, value):
def test_bad_type_fallback_on_post(hook, test_pair, other_acct, value):
test_acct, meta_key = test_pair
expected = {
test_acct.missing_message(),
test_acct.wrong_type_message(value, test_acct.fallback_meta),
test_acct.wrong_type_message(value, meta_key),
}
check(hook, test_acct, other_acct, expected,
post_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, expected, post_meta={meta_key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.LINK_METADATA_STRINGS,
))
def test_valid_fallback_on_txn(hook, test_acct, other_acct, value):
check(hook, test_acct, other_acct, None,
txn_meta={test_acct.fallback_meta: value})
def test_valid_fallback_on_txn(hook, test_pair, other_acct, value):
test_acct, meta_key = test_pair
check(hook, test_acct, other_acct, None, txn_meta={meta_key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.NON_LINK_METADATA_STRINGS,
))
def test_invalid_fallback_on_txn(hook, test_acct, other_acct, value):
def test_invalid_fallback_on_txn(hook, test_pair, other_acct, value):
test_acct, meta_key = test_pair
check(hook, test_acct, other_acct, {test_acct.missing_message()},
txn_meta={test_acct.fallback_meta: value})
txn_meta={meta_key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.NON_STRING_METADATA_VALUES,
))
def test_bad_type_fallback_on_txn(hook, test_acct, other_acct, value):
def test_bad_type_fallback_on_txn(hook, test_pair, other_acct, value):
test_acct, meta_key = test_pair
expected = {
test_acct.missing_message(),
test_acct.wrong_type_message(value, test_acct.fallback_meta),
test_acct.wrong_type_message(value, meta_key),
}
check(hook, test_acct, other_acct, expected,
txn_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, expected, txn_meta={meta_key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_CHECK_ID_FALLBACK,
@ -249,8 +255,7 @@ def test_bad_type_fallback_on_txn(hook, test_acct, other_acct, value):
CHECK_IDS,
))
def test_valid_check_id_on_post(hook, test_acct, other_acct, value):
check(hook, test_acct, other_acct, None,
post_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, None, post_meta={'check-id': value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_CHECK_ID_FALLBACK,
@ -260,10 +265,9 @@ def test_valid_check_id_on_post(hook, test_acct, other_acct, value):
def test_invalid_check_id_on_post(hook, test_acct, other_acct, value):
expected = {
test_acct.missing_message(),
f"{test_acct.name} has invalid {test_acct.fallback_meta}: {value}",
f"{test_acct.name} has invalid check-id: {value}",
}
check(hook, test_acct, other_acct, expected,
post_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, expected, post_meta={'check-id': value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_CHECK_ID_FALLBACK,
@ -275,10 +279,9 @@ def test_bad_type_check_id_on_post(hook, test_acct, other_acct, value):
value = ''
expected = {
test_acct.missing_message(),
test_acct.wrong_type_message(value, test_acct.fallback_meta),
test_acct.wrong_type_message(value, 'check-id'),
}
check(hook, test_acct, other_acct, expected,
post_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, expected, post_meta={'check-id': value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_CHECK_ID_FALLBACK,
@ -286,8 +289,7 @@ def test_bad_type_check_id_on_post(hook, test_acct, other_acct, value):
CHECK_IDS,
))
def test_valid_check_id_on_txn(hook, test_acct, other_acct, value):
check(hook, test_acct, other_acct, None,
txn_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, None, txn_meta={'check-id': value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_CHECK_ID_FALLBACK,
@ -297,10 +299,9 @@ def test_valid_check_id_on_txn(hook, test_acct, other_acct, value):
def test_invalid_check_id_on_txn(hook, test_acct, other_acct, value):
expected = {
test_acct.missing_message(),
f"{test_acct.name} has invalid {test_acct.fallback_meta}: {value}",
f"{test_acct.name} has invalid check-id: {value}",
}
check(hook, test_acct, other_acct, expected,
txn_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, expected, txn_meta={'check-id': value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_CHECK_ID_FALLBACK,
@ -312,34 +313,34 @@ def test_bad_type_check_id_on_txn(hook, test_acct, other_acct, value):
value = ''
expected = {
test_acct.missing_message(),
test_acct.wrong_type_message(value, test_acct.fallback_meta),
test_acct.wrong_type_message(value, 'check-id'),
}
check(hook, test_acct, other_acct, expected,
txn_meta={test_acct.fallback_meta: value})
check(hook, test_acct, other_acct, expected, txn_meta={'check-id': value})
@pytest.mark.parametrize('test_acct,other_acct,key,value', testutil.combine_values(
ACCOUNTS_WITHOUT_FALLBACKS,
[acct for acct in ACCOUNTS if not acct.fallback_meta],
NOT_REQUIRED_ACCOUNTS,
KNOWN_FALLBACKS,
{key for acct in ACCOUNTS for key in acct.fallback_meta},
testutil.LINK_METADATA_STRINGS,
))
def test_fallback_not_accepted_on_other_accounts(hook, test_acct, other_acct, key, value):
check(hook, test_acct, other_acct, {test_acct.missing_message()},
post_meta={key: value})
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
@pytest.mark.parametrize('test_pair,other_acct,value', testutil.combine_values(
ACCOUNTS_WITH_LINK_FALLBACK,
NOT_REQUIRED_ACCOUNTS,
testutil.LINK_METADATA_STRINGS,
))
def test_fallback_on_zero_amount_postings(hook, test_acct, other_acct, value):
def test_fallback_on_zero_amount_postings(hook, test_pair, other_acct, value):
# Unfortunately it does happen that we get donations that go 100% to
# banking fees, and our importer writes a zero-amount posting to the
# Assets account.
test_acct, meta_key = test_pair
txn = testutil.Transaction(postings=[
('Income:Donations', '-.1'),
('Expenses:BankingFees', '.1'),
(test_acct.name, 0, {test_acct.fallback_meta: value}),
(test_acct.name, 0, {meta_key: value}),
])
assert not list(hook.run(txn))