File diff 8af45e5f8a5b → 6fa12789661e
tests/test_reports_query.py
Show inline comments
...
 
@@ -21,6 +21,7 @@ import pytest
 
from . import testutil
 

	
 
from beancount.core import data as bc_data
 
from beancount.query import query_parser as bc_query_parser
 
from conservancy_beancount.books import FiscalYear
 
from conservancy_beancount.reports import query as qmod
 
from conservancy_beancount import rtutil
...
 
@@ -38,6 +39,10 @@ class MockRewriteRuleset:
 
            yield post._replace(units=testutil.Amount(number, currency))
 

	
 

	
 
@pytest.fixture(scope='module')
 
def qparser():
 
    return bc_query_parser.Parser()
 

	
 
@pytest.fixture(scope='module')
 
def rt():
 
    return rtutil.RT(testutil.RTClient())
...
 
@@ -130,40 +135,47 @@ def test_rewrite_query(end_index):
 
    assert expected.issubset(actual)
 
    assert frozenset(accounts).difference(expected).isdisjoint(actual)
 

	
 
def test_ods_amount_formatting():
 
def test_ods_amount_formatting(qparser):
 
    statement = qparser.parse('SELECT UNITS(position)')
 
    row_types = [('amount', bc_data.Amount)]
 
    row_source = [(testutil.Amount(12),), (testutil.Amount(1480, 'JPY'),)]
 
    ods = qmod.QueryODS()
 
    ods.write_query(row_types, row_source)
 
    ods.write_query(statement, row_types, row_source)
 
    actual = testutil.ODSCell.from_sheet(ods.document.spreadsheet.firstChild)
 
    assert next(actual)[0].text == 'Amount'
 
    assert next(actual)[0].text == '$12.00'
 
    assert next(actual)[0].text == '¥1,480'
 
    assert next(actual, None) is None
 

	
 
def test_ods_datetime_formatting():
 
def test_ods_datetime_formatting(qparser):
 
    statement = qparser.parse('SELECT date')
 
    row_types = [('date', datetime.date)]
 
    row_source = [(testutil.PAST_DATE,), (testutil.FUTURE_DATE,)]
 
    ods = qmod.QueryODS()
 
    ods.write_query(row_types, row_source)
 
    ods.write_query(statement, row_types, row_source)
 
    actual = testutil.ODSCell.from_sheet(ods.document.spreadsheet.firstChild)
 
    assert next(actual)[0].text == 'Date'
 
    assert next(actual)[0].text == testutil.PAST_DATE.isoformat()
 
    assert next(actual)[0].text == testutil.FUTURE_DATE.isoformat()
 
    assert next(actual, None) is None
 

	
 
@pytest.mark.parametrize('meta_key,header_text', [
 
    ('check', 'Check'),
 
    ('purchase-order', 'Purchase Order'),
 
    ('rt-id', 'Ticket'),
 
@pytest.mark.parametrize('meta_key,meta_func', [
 
    ('check', 'ANY_META'),
 
    ('purchase-order', 'META'),
 
    ('rt-id', 'META_DOCS'),
 
])
 
def test_ods_link_formatting(rt, meta_key, header_text):
 
    row_types = [(meta_key.replace('-', '_'), object)]
 
    row_source = [('rt:1/5',), ('rt:3 Checks/9.pdf',)]
 
def test_ods_link_formatting(qparser, rt, meta_key, meta_func):
 
    meta_func_returns_list = meta_func == 'META_DOCS'
 
    statement = qparser.parse(f'SELECT {meta_func}({meta_key!r}) AS docs')
 
    row_types = [('docs', list if meta_func_returns_list else str)]
 
    row_source = [
 
        (s.split() if meta_func_returns_list else s,)
 
        for s in ['rt:1/5', 'rt:3 Checks/9.pdf']
 
    ]
 
    ods = qmod.QueryODS(rt)
 
    ods.write_query(row_types, row_source)
 
    ods.write_query(statement, row_types, row_source)
 
    rows = iter(ods.document.spreadsheet.firstChild.getElementsByType(odf.table.TableRow))
 
    assert next(rows).text == header_text
 
    assert next(rows).text == 'Docs'
 
    actual = iter(
 
        [link.text for link in row.getElementsByType(odf.text.A)]
 
        for row in rows
...
 
@@ -172,50 +184,54 @@ def test_ods_link_formatting(rt, meta_key, header_text):
 
    assert next(actual) == ['rt:3', '9.pdf']
 
    assert next(actual, None) is None
 

	
 
def test_ods_meta_formatting():
 
    row_types = [('metadata', object)]
 
def test_ods_meta_formatting(qparser):
 
    statement = qparser.parse('SELECT ANY_META("entity") AS entity')
 
    row_types = [('entity', object)]
 
    row_source = [(testutil.Amount(14),), (None,), ('foo bar',)]
 
    ods = qmod.QueryODS()
 
    ods.write_query(row_types, row_source)
 
    ods.write_query(statement, row_types, row_source)
 
    actual = testutil.ODSCell.from_sheet(ods.document.spreadsheet.firstChild)
 
    assert next(actual)[0].text == 'Metadata'
 
    assert next(actual)[0].text == 'Entity'
 
    assert next(actual)[0].text == '$14.00'
 
    assert next(actual)[0].text == ''
 
    assert next(actual)[0].text == 'foo bar'
 
    assert next(actual, None) is None
 

	
 
def test_ods_multicolumn_write(rt):
 
    row_types = [('date', datetime.date), ('rt-id', object), ('desc', str)]
 
def test_ods_multicolumn_write(qparser, rt):
 
    statement = qparser.parse(
 
        'SELECT MIN(date) AS date, SET(META_DOCS("rt-id")) AS tix, STR_META("entity") AS entity',
 
    )
 
    row_types = [('date', datetime.date), ('tix', set), ('entity', str)]
 
    row_source = [
 
        (testutil.PAST_DATE, 'rt:1', 'aaa'),
 
        (testutil.FY_START_DATE, 'rt:2', 'bbb'),
 
        (testutil.FUTURE_DATE, 'rt:3', 'ccc'),
 
        (testutil.PAST_DATE, {'rt:1'}, 'AA'),
 
        (testutil.FY_START_DATE, {'rt:2'}, 'BB'),
 
        (testutil.FUTURE_DATE, {'rt:3', 'rt:4'}, 'CC'),
 
    ]
 
    ods = qmod.QueryODS(rt)
 
    ods.write_query(row_types, row_source)
 
    ods.write_query(statement, list(row_types), list(row_source))
 
    actual = iter(
 
        cell.text
 
        for row in testutil.ODSCell.from_sheet(ods.document.spreadsheet.firstChild)
 
        for cell in row
 
    )
 
    assert next(actual) == 'Date'
 
    assert next(actual) == 'Ticket'
 
    assert next(actual) == 'Desc'
 
    for expected, _ in row_types:
 
        assert next(actual) == expected.title()
 
    assert next(actual) == testutil.PAST_DATE.isoformat()
 
    assert next(actual) == 'rt:1'
 
    assert next(actual) == 'aaa'
 
    assert next(actual) == 'AA'
 
    assert next(actual) == testutil.FY_START_DATE.isoformat()
 
    assert next(actual) == 'rt:2'
 
    assert next(actual) == 'bbb'
 
    assert next(actual) == 'BB'
 
    assert next(actual) == testutil.FUTURE_DATE.isoformat()
 
    assert next(actual) == 'rt:3'
 
    assert next(actual) == 'ccc'
 
    assert frozenset(next(actual).split('\0')) == row_source[-1][1]
 
    assert next(actual) == 'CC'
 
    assert next(actual, None) is None
 

	
 
def test_ods_is_empty():
 
def test_ods_is_empty(qparser):
 
    statement = qparser.parse('SELECT * WHERE date < 1900-01-01')
 
    ods = qmod.QueryODS()
 
    assert ods.is_empty()
 
    ods.write_query([], [])
 
    ods.write_query(statement, [], [])
 
    assert not ods.is_empty()
 

	
 
@pytest.mark.parametrize('fy,account,amt_prefix', [
...
 
@@ -232,8 +248,9 @@ def test_ods_output(fy, account, amt_prefix):
 
    ]
 
    returncode, stdout, stderr = pipe_main(arglist, config, io.BytesIO)
 
    assert returncode == 0
 
    stdout.seek(0)
 
    ods_doc = odf.opendocument.load(stdout)
 
    with stdout:
 
        stdout.seek(0)
 
        ods_doc = odf.opendocument.load(stdout)
 
    rows = iter(ods_doc.spreadsheet.firstChild.getElementsByType(odf.table.TableRow))
 
    next(rows)  # Skip header row
 
    amt_pattern = rf'^{re.escape(amt_prefix)}\d'
...
 
@@ -243,3 +260,30 @@ def test_ods_output(fy, account, amt_prefix):
 
        assert narration.text.startswith(f'{fy} ')
 
        assert re.match(amt_pattern, amount.text)
 
    assert count
 

	
 
def test_ods_aggregate_output():
 
    books_path = testutil.test_path(f'books/books/2020.beancount')
 
    config = testutil.TestConfig(books_path=books_path)
 
    arglist = [
 
        '-O', '-',
 
        '-f', 'ods',
 
        'SELECT account, SET(narration), SUM(UNITS(position))',
 
        'WHERE date >= 2020-04-01 AND date <= 2020-04-02',
 
        'GROUP BY account ORDER BY account ASC',
 
    ]
 
    returncode, stdout, stderr = pipe_main(arglist, config, io.BytesIO)
 
    assert returncode == 0
 
    with stdout:
 
        stdout.seek(0)
 
        ods_doc = odf.opendocument.load(stdout)
 
    rows = iter(ods_doc.spreadsheet.firstChild.getElementsByType(odf.table.TableRow))
 
    next(rows)  # Skip header row
 
    actual = {}
 
    for row in rows:
 
        acct, descs, balance = row.childNodes
 
        actual[acct.text] = (frozenset(descs.text.split('\0')), balance.text)
 
    in_desc = {'2020 donation'}
 
    ex_desc = {'2020 bank maintenance fee'}
 
    assert actual['Income:Donations'] == (in_desc, '$20.20')
 
    assert actual['Expenses:BankingFees'] == (ex_desc, '$1.00')
 
    assert actual['Assets:Checking'] == (in_desc | ex_desc, '($21.20)')