File diff 4de5df9035f6 → f508df06c162
tests/test_reports_rewrite.py
Show inline comments
...
 
@@ -6,25 +6,25 @@
 
# LICENSE.txt in the repository.
 

	
 
import datetime
 

	
 
import pytest
 

	
 
from decimal import Decimal
 

	
 
import yaml
 

	
 
from . import testutil
 

	
 
from conservancy_beancount import data
 
from conservancy_beancount import data, errors
 
from conservancy_beancount.reports import rewrite
 

	
 
CMP_OPS = frozenset('< <= == != >= >'.split())
 

	
 
@pytest.mark.parametrize('name', ['Equity:Other', 'Expenses:Other', 'Income:Other'])
 
@pytest.mark.parametrize('operator', CMP_OPS)
 
def test_account_condition(name, operator):
 
    operand = 'Expenses:Other'
 
    txn = testutil.Transaction(postings=[(name, -5)])
 
    post, = data.Posting.from_txn(txn)
 
    tester = rewrite.AccountTest(operator, operand)
 
    assert tester(post) == eval(f'name {operator} operand')
...
 
@@ -122,25 +122,25 @@ def test_parse_good_condition(subject, operator, operand):
 
@pytest.mark.parametrize('cond_s', [
 
    '.account = Income:Other',  # Bad operator
 
    '.account===Equity:Other',  # Bad operand (`=Equity:Other` is not valid)
 
    '.account in foo',  # Bad operand
 
    '.date == 1990-90-5',  # Bad operand
 
    '.date in 1990-9-9',  # Bad operator
 
    '.number > 0xff',  # Bad operand
 
    '.number in 16',  # Bad operator
 
    'units.number == 5',  # Bad subject (syntax)
 
    '.units == 5',  # Bad subject (unknown)
 
])
 
def test_parse_bad_condition(cond_s):
 
    with pytest.raises(ValueError):
 
    with pytest.raises(errors.RewriteRuleConditionError):
 
        rewrite.TestRegistry.parse(cond_s)
 

	
 
@pytest.mark.parametrize('value', ['Equity:Other', 'Income:Other'])
 
def test_account_set(value):
 
    value = data.Account(value)
 
    txn = testutil.Transaction(postings=[
 
        ('Expenses:Other', 5),
 
    ])
 
    post, = data.Posting.from_txn(txn)
 
    setter = rewrite.AccountSet('=', value)
 
    assert setter(post) == ('account', value)
 

	
...
 
@@ -186,25 +186,25 @@ def test_parse_good_set(subject, operator, operand):
 
        assert actual.value == operand
 

	
 
@pytest.mark.parametrize('set_s', [
 
    '.account==Equity:Other',  # Bad operand (`=Equity:Other` is not valid)
 
    '.account*=2',  # Bad operator
 
    '.date = 2020-02-20',  # Bad subject
 
    '.number*=0xff',  # Bad operand
 
    '.number=5',  # Bad operator
 
    'testkey += foo',  # Bad operator
 
    'testkey *= 3',  # Bad operator
 
])
 
def test_parse_bad_set(set_s):
 
    with pytest.raises(ValueError):
 
    with pytest.raises(errors.RewriteRuleActionError):
 
        rewrite.SetRegistry.parse(set_s)
 

	
 
def test_good_rewrite_rule():
 
    rule = rewrite.RewriteRule({
 
        'if': ['.account in Income'],
 
        'add': ['income-type = Other'],
 
    })
 
    txn = testutil.Transaction(postings=[
 
        ('Assets:Cash', 10),
 
        ('Income:Other', -10),
 
    ])
 
    cash_post, inc_post = data.Posting.from_txn(txn)
...
 
@@ -262,44 +262,39 @@ def test_complicated_rewrite_rule():
 
    {'if': ['.date >= 2020-01-02'], 'a': ['.number *= .85'], 'b': ['.number *= .15']},
 
    # Metadata assignment
 
    {'if': ['a==1'], 'then': ['b=2', 'c=3']},
 
])
 
def test_valid_rewrite_rule(source):
 
    assert rewrite.RewriteRule(source)
 

	
 
@pytest.mark.parametrize('source', [
 
    # Incomplete rules
 
    {},
 
    {'if': ['.account in Equity']},
 
    {'a': ['.account = Income:Other'], 'b': ['.account = Expenses:Other']},
 
    # Condition/assignment mixup
 
    {'if': ['.account = Equity:Other'], 'then': ['equity-type = other']},
 
    {'if': ['.account == Equity:Other'], 'then': ['equity-type != other']},
 
    # Cross-category account assignment
 
    {'if': ['.date >= 2020-01-01'], 'then': ['.account = Assets:Cash']},
 
    {'if': ['.account in Equity'], 'then': ['.account = Assets:Cash']},
 
    # Number reallocation != 1
 
    {'if': ['.date >= 2020-01-01'], 'then': ['.number *= .5']},
 
    {'if': ['.date >= 2020-01-01'], 'a': ['k1=v1'], 'b': ['k2=v2']},
 
    # Date assignment
 
    {'if': ['.date == 2020-01-01'], 'then': ['.date = 2020-02-02']},
 
    # Redundant assignments
 
    {'if': ['.account in Income'],
 
     'then': ['.account = Income:Other', '.account = Income:Other']},
 
    {'if': ['.number > 0'],
 
     'a': ['.number *= .5', '.number *= .5'],
 
     'b': ['.number *= .5']},
 
])
 
def test_invalid_rewrite_rule(source):
 
    with pytest.raises(ValueError):
 
    with pytest.raises(errors.RewriteRuleValidationError):
 
        rewrite.RewriteRule(source)
 

	
 
def test_rewrite_ruleset():
 
    account = 'Income:CurrencyConversion'
 
    ruleset = rewrite.RewriteRuleset(rewrite.RewriteRule(src) for src in [
 
        {'if': ['.account == Expenses:CurrencyConversion'],
 
         'rename': [f'.account = {account}']},
 
        {'if': ['project == alpha', '.account != Assets:Cash'],
 
         'cap': ['project = Alpha']},
 
    ])
 
    txn = testutil.Transaction(project='alpha', postings=[
 
        ('Assets:Cash', -20),
...
 
@@ -324,33 +319,33 @@ def test_rewrite_ruleset():
 

	
 
def test_ruleset_from_yaml_path():
 
    yaml_path = testutil.test_path('userconfig/Rewrites01.yml')
 
    assert rewrite.RewriteRuleset.from_yaml(yaml_path)
 

	
 
def test_ruleset_from_yaml_str():
 
    with testutil.test_path('userconfig/Rewrites01.yml').open() as yaml_file:
 
        yaml_s = yaml_file.read()
 
    assert rewrite.RewriteRuleset.from_yaml(yaml_s)
 

	
 
def test_bad_ruleset_yaml_path():
 
    yaml_path = testutil.test_path('repository/Projects/project-data.yml')
 
    with pytest.raises(ValueError):
 
    with pytest.raises(errors.RewriteRuleLoadError):
 
        rewrite.RewriteRuleset.from_yaml(yaml_path)
 

	
 
@pytest.mark.parametrize('source', [
 
    # Wrong root objects
 
    1,
 
    2.3,
 
    True,
 
    None,
 
    {},
 
    'string',
 
    [{}, 'a'],
 
    [{}, ['b']],
 
    ['a'],
 
    [['b']],
 
    # Rules have wrong type
 
    [{'if': '.account in Equity', 'add': ['testkey = value']}],
 
    [{'if': ['.account in Equity'], 'add': 'testkey = value'}],
 
])
 
def test_bad_ruleset_yaml_str(source):
 
    yaml_doc = yaml.safe_dump(source)
 
    with pytest.raises(ValueError):
 
    with pytest.raises(errors.RewriteRuleLoadError):
 
        rewrite.RewriteRuleset.from_yaml(yaml_doc)