3b821cbbee
This makes it possible to support transactions that divide funds in ways other than a simple percentage split. For example, there might be tax withheld, or a flat fee expense on each transaction.
127 lines
4.5 KiB
Python
127 lines
4.5 KiB
Python
import contextlib
|
|
import datetime
|
|
import itertools
|
|
import logging
|
|
import os
|
|
import pathlib
|
|
|
|
START_DATE = datetime.date.today()
|
|
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
from import2ledger import config, errors
|
|
|
|
from . import DATA_DIR
|
|
|
|
def config_from_file(path, arglist=[]):
|
|
path = pathlib.Path(path)
|
|
if not path.is_absolute():
|
|
path = DATA_DIR / path
|
|
arglist = ['-C', path.as_posix(), *arglist, os.devnull]
|
|
return config.Configuration(arglist)
|
|
|
|
def test_defaults():
|
|
config = config_from_file('test_config.ini', ['--sign', 'GBP', '-O', 'out_arg'])
|
|
factory = mock.Mock(name='Template')
|
|
template = config.get_template('one', 'Templates', factory)
|
|
assert factory.called
|
|
kwargs = factory.call_args[1]
|
|
assert list(kwargs.pop('signed_currencies', '')) == ['GBP']
|
|
assert kwargs == {
|
|
'date_fmt': '%Y-%m-%d',
|
|
'signed_currency_fmt': kwargs['signed_currency_fmt'],
|
|
'template_name': 'one',
|
|
'unsigned_currency_fmt': kwargs['unsigned_currency_fmt'],
|
|
}
|
|
|
|
def test_template_parsing():
|
|
config = config_from_file('test_config.ini')
|
|
factory = mock.Mock(name='Template')
|
|
template = config.get_template('two', 'Templates', factory)
|
|
try:
|
|
tmpl_s = factory.call_args[0][0]
|
|
except IndexError as error:
|
|
assert False, error
|
|
assert "\n;Tag1: {value}\n" in tmpl_s
|
|
assert "\nIncome:Donations -{amount}\n" in tmpl_s
|
|
assert "\n;IncomeTag: Donations\n" in tmpl_s
|
|
|
|
@pytest.mark.parametrize('arg_s', [None, '-', 'output.ledger'])
|
|
def test_output_path(arg_s):
|
|
arglist = [] if arg_s is None else ['-O', arg_s]
|
|
config = config_from_file(os.devnull, arglist)
|
|
output_path = config.get_output_path()
|
|
if (arg_s is None) or (arg_s == '-'):
|
|
assert output_path is None
|
|
else:
|
|
assert output_path == pathlib.Path(arg_s)
|
|
|
|
def test_output_path_from_section():
|
|
expected_path = pathlib.Path('Template.output')
|
|
config = config_from_file('test_config.ini', ['-O', 'output.ledger'])
|
|
assert config.get_output_path('Templates') == expected_path
|
|
assert config.get_output_path() != expected_path
|
|
with config.from_section('Templates'):
|
|
assert config.get_output_path() == expected_path
|
|
|
|
@pytest.mark.parametrize('range_s,date_fmt', [
|
|
(range_s.replace('/', sep), sep.join(['%Y', '%m', '%d']))
|
|
for range_s, sep in itertools.product([
|
|
'-',
|
|
'2016/06/01-2016/06/30',
|
|
'2016/06/01-',
|
|
'-2016/06/30',
|
|
], '/-')
|
|
])
|
|
def test_date_in_want_range(range_s, date_fmt):
|
|
config = config_from_file(os.devnull, ['--date-range=' + range_s, '--date-format', date_fmt])
|
|
assert config.date_in_want_range(datetime.date(2016, 5, 31)) == range_s.startswith('-')
|
|
assert config.date_in_want_range(datetime.date(2016, 6, 1))
|
|
assert config.date_in_want_range(datetime.date(2016, 6, 30))
|
|
assert config.date_in_want_range(datetime.date(2016, 7, 1)) == range_s.endswith('-')
|
|
|
|
@pytest.mark.parametrize('arglist,expect_date', [
|
|
([], None),
|
|
(['-d', '2017-10-12'], datetime.date(2017, 10, 12)),
|
|
(['-c', 'Date'], datetime.date(2017, 10, 8)),
|
|
])
|
|
def test_default_date(arglist, expect_date):
|
|
config = config_from_file('test_config.ini', arglist)
|
|
default_date = config.get_default_date()
|
|
if expect_date is None:
|
|
assert START_DATE <= default_date <= datetime.date.today()
|
|
else:
|
|
assert default_date == expect_date
|
|
assert config.get_default_date('Date') == datetime.date(2017, 10, 8)
|
|
|
|
@pytest.mark.parametrize('level_s,expect_level', [
|
|
(s, getattr(logging, s.upper()))
|
|
for s in ['critical', 'debug', 'error', 'info', 'warning']
|
|
])
|
|
def test_loglevel(level_s, expect_level):
|
|
config = config_from_file(os.devnull, ['--loglevel', level_s])
|
|
assert config.get_loglevel() == expect_level
|
|
|
|
@contextlib.contextmanager
|
|
def bad_config(expect_input):
|
|
with pytest.raises(errors.UserInputConfigurationError) as exc_info:
|
|
yield exc_info
|
|
assert exc_info.value.user_input == expect_input
|
|
|
|
def test_bad_default_date():
|
|
date_s = '2017-10-06'
|
|
with bad_config(date_s):
|
|
config = config_from_file(os.devnull, ['--date', date_s])
|
|
config.get_default_date()
|
|
|
|
def test_bad_loglevel():
|
|
with bad_config('wraning'):
|
|
config = config_from_file('test_config.ini', ['-c', 'Bad Loglevel'])
|
|
config.get_loglevel()
|
|
|
|
def test_undefined_template():
|
|
template_name = 'template nonexistent'
|
|
config = config_from_file(os.devnull)
|
|
with bad_config(template_name):
|
|
config.get_template(template_name)
|