"""test_meta_tax_reporting.py - Unit tests for tax-reporting metadata validation""" # Copyright © 2021 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 pytest from . import testutil from conservancy_beancount.plugin import meta_tax_reporting TEST_KEY = 'tax-reporting' IMPLICATION_KEY = 'tax-implication' REQUIRED_ACCOUNTS = { 'Assets:Checking', 'Assets:Bank:Savings', } NON_REQUIRED_ACCOUNTS = { 'Assets:Prepaid:Expenses', 'Assets:Receivable:Accounts', 'Liabilities:CreditCard', } REQUIRED_AMOUNTS = {-50, -500} NON_REQUIRED_AMOUNTS = {-5, 500} REQUIRED_IMPLICATIONS = { '1099', '1099-Misc-Other', 'foreign-grantee', 'Foreign-Individual-Contractor', 'USA-501c3', 'US-Grantee', } NON_REQUIRED_IMPLICATIONS = { 'Bank-Transfer', 'chargeback', 'Foreign-Corp', 'Loan', 'refund', 'Reimbursement', 'retirement-pretax', 'Tax-Payment', 'us-corp', 'w2', } @pytest.fixture(scope='module') def hook(): config = testutil.TestConfig(payment_threshold=10) return meta_tax_reporting.MetaTaxReporting(config) @pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, testutil.LINK_METADATA_STRINGS, )) def test_pass_on_txn(hook, account, amount, implication, value): txn_meta = { IMPLICATION_KEY: implication, TEST_KEY: value, } txn = testutil.Transaction(**txn_meta, postings=[ (account, amount), ('Expenses:Other', -amount), ]) assert not list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, testutil.LINK_METADATA_STRINGS, )) def test_pass_on_post(hook, account, amount, implication, value): post_meta = { IMPLICATION_KEY: implication, TEST_KEY: value, } txn = testutil.Transaction(postings=[ (account, amount, post_meta), ('Expenses:Other', -amount), ]) assert not list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, )) def test_error_when_missing(hook, account, amount, implication): txn = testutil.Transaction(postings=[ (account, amount, {IMPLICATION_KEY: implication}), ('Expenses:Other', -amount), ]) assert list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, testutil.NON_LINK_METADATA_STRINGS, )) def test_error_when_empty(hook, account, amount, implication, value): txn_meta = { IMPLICATION_KEY: implication, TEST_KEY: value, } txn = testutil.Transaction(**txn_meta, postings=[ (account, amount), ('Expenses:Other', -amount), ]) assert list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication,value', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, testutil.NON_STRING_METADATA_VALUES, )) def test_error_when_wrong_type(hook, account, amount, implication, value): txn_meta = { IMPLICATION_KEY: implication, TEST_KEY: value, } txn = testutil.Transaction(**txn_meta, postings=[ (account, amount), ('Expenses:Other', -amount), ]) assert list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication', testutil.combine_values( NON_REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, )) def test_skip_by_account(hook, account, amount, implication): txn = testutil.Transaction(postings=[ (account, amount, {IMPLICATION_KEY: implication}), ('Expenses:Other', -amount), ]) assert not list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication', testutil.combine_values( REQUIRED_ACCOUNTS, NON_REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, )) def test_skip_by_amount(hook, account, amount, implication): txn = testutil.Transaction(postings=[ (account, amount, {IMPLICATION_KEY: implication}), ('Expenses:Other', -amount), ]) assert not list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, NON_REQUIRED_IMPLICATIONS, )) def test_skip_by_implication(hook, account, amount, implication): txn = testutil.Transaction(postings=[ (account, amount, {IMPLICATION_KEY: implication}), ('Expenses:Other', -amount), ]) assert not list(hook.run(txn)) @pytest.mark.parametrize('account,amount,implication', testutil.combine_values( REQUIRED_ACCOUNTS, REQUIRED_AMOUNTS, REQUIRED_IMPLICATIONS, )) def test_skip_by_flag(hook, account, amount, implication): txn = testutil.Transaction(flag='!', postings=[ (account, amount, {IMPLICATION_KEY: implication}), ('Expenses:Other', -amount), ]) assert not list(hook.run(txn))