Files @ d49173725a7b
Branch filter:

Location: NPO-Accounting/conservancy_beancount/tests/test_plugin.py - annotation

Brett Smith
tests: Ignore the DeprecationWarning from the socks module.

The socks package in Debian buster does a deprecated import from
the collections module. That's not directly relevant to our own
code (Conservancy has no business requirement for SOCKS support)
so ignore it.
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
0d370c445b9e
0d370c445b9e
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
0d370c445b9e
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
0d370c445b9e
0d370c445b9e
0d370c445b9e
0d370c445b9e
0d370c445b9e
0d370c445b9e
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
0d370c445b9e
0d370c445b9e
d4d9bd655468
d4d9bd655468
d4d9bd655468
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
484c47a680c3
84d8adb7f664
484c47a680c3
e424173216c5
e424173216c5
d4d9bd655468
d4d9bd655468
d4d9bd655468
84d8adb7f664
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
d4d9bd655468
"""Test main plugin"""
# 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 pytest

from . import testutil

from conservancy_beancount import beancount_types, errors as errormod, plugin

HOOK_REGISTRY = plugin.HookRegistry()

class NonError(errormod.Error):
    pass


class TransactionHook:
    DIRECTIVE = beancount_types.Transaction
    HOOK_GROUPS = frozenset()

    def __init__(self, config):
        self.config = config

    def run(self, txn):
        assert False, "something called base class run method"


@HOOK_REGISTRY.add_hook
class ConfigurationError(TransactionHook):
    HOOK_GROUPS = frozenset(['unconfigured'])

    def __init__(self, config):
        raise errormod.ConfigurationError("testing error")


@HOOK_REGISTRY.add_hook
class TransactionError(TransactionHook):
    HOOK_GROUPS = frozenset(['configured'])

    def run(self, txn):
        return [NonError('txn:{}'.format(id(txn)), txn)]


@HOOK_REGISTRY.add_hook
class PostingError(TransactionHook):
    HOOK_GROUPS = frozenset(['configured', 'posting'])

    def run(self, txn):
        return [NonError('post:{}'.format(id(post)), txn)
                for post in txn.postings]


@pytest.fixture
def config_map():
    return {}

@pytest.fixture
def easy_entries():
    return [
        testutil.Transaction(postings=[
            ('Income:Donations', -25),
            ('Assets:Cash', 25),
        ]),
        testutil.Transaction(postings=[
            ('Expenses:General', 10),
            ('Liabilites:CreditCard', -10),
        ]),
    ]

def map_errors(errors):
    retval = {}
    for error in errors:
        key, _, errid = error.message.partition(':')
        retval.setdefault(key, set()).add(errid)
    return retval

@pytest.mark.parametrize('group_str,expected', [
    (None, [TransactionError, PostingError]),
    ('', [TransactionError, PostingError]),
    ('all', [TransactionError, PostingError]),
    ('Transaction', [TransactionError, PostingError]),
    ('-posting', [TransactionError]),
    ('-configured posting', [PostingError]),
    ('configured -posting', [TransactionError]),
])
def test_registry_group_by_directive(group_str, expected):
    args = () if group_str is None else (group_str,)
    actual = {hook for _, hook in HOOK_REGISTRY.group_by_directive(*args)}
    assert actual.issuperset(expected)
    if len(expected) == 1:
        assert not (TransactionError in actual and PostingError in actual)

def test_registry_unknown_group_name():
    with pytest.raises(ValueError):
        next(HOOK_REGISTRY.group_by_directive('UnKnownTestGroup'))

def test_run_with_multiple_hooks(easy_entries, config_map):
    out_entries, errors = plugin.run(easy_entries, config_map, '', HOOK_REGISTRY)
    assert len(out_entries) == 2
    errmap = map_errors(errors)
    assert len(errmap.get('txn', '')) == 2
    assert len(errmap.get('post', '')) == 4

def test_run_with_one_hook(easy_entries, config_map):
    out_entries, errors = plugin.run(easy_entries, config_map, 'posting', HOOK_REGISTRY)
    assert len(out_entries) == 2
    errmap = map_errors(errors)
    assert len(errmap.get('txn', '')) == 0
    assert len(errmap.get('post', '')) == 4