move everything into src/catnab and add more tests

This commit is contained in:
2025-12-09 08:39:04 -05:00
parent 2509c4dd70
commit 761c7eeda4
7 changed files with 351 additions and 26 deletions

189
tests/conftest.py Normal file
View File

@@ -0,0 +1,189 @@
from datetime import date
from unittest.mock import MagicMock
import pytest
from catnab.ai import ItemClassification
@pytest.fixture
def mk_ynab_tx():
def ynab_tx(
id='1',
payee_name='Amazon',
amount=123450,
var_date=date(2025, 1, 1),
flag_color=None,
approved=False,
subtransactions=[],
):
return MagicMock(
id=id,
payee_name=payee_name,
amount=amount,
var_date=var_date,
flag_color=flag_color,
approved=approved,
subtransactions=subtransactions
)
return ynab_tx
@pytest.fixture
def mk_amz_tx():
def amz_tx(
grand_total=123.45,
completed_date=date(2025, 1, 1),
order_number='A',
is_refund=False,
payment_method='Visa 1234',
):
return MagicMock(
grand_total=grand_total,
completed_date=completed_date,
order_number=order_number,
is_refund=is_refund,
payment_method=payment_method,
)
return amz_tx
def order_item(
title='An example item',
price=120.34,
quantity=1,
):
return MagicMock(
title=title,
price=price,
quantity=quantity,
)
def amz_order(
order_number='A',
order_placed_date=date(2025, 1, 1),
items=[order_item()],
grand_total=123.45, # add a little bit for pretend tax
full_details=True,
):
return MagicMock(
order_number=order_number,
order_placed_date=order_placed_date,
items=items,
grand_total=grand_total,
full_details=full_details,
)
@pytest.fixture
def setup_mock_order(monkeypatch):
def setup(orders, amz_hist, ynab_hist, item_categories):
def __enter__(self): return self
monkeypatch.setattr('catnab.amazon.Session.__enter__', __enter__)
def list_transactions(self, days): return amz_hist
monkeypatch.setattr('catnab.amazon.Session.list_transactions', list_transactions)
orders_map = {o.order_number: o for o in orders}
def get_order(self, order_number): return orders_map[order_number]
monkeypatch.setattr('catnab.amazon.Session.get_order', get_order)
monkeypatch.setattr('catnab.ynab_client.YnabClient.history', ynab_hist)
monkeypatch.setattr('catnab.ynab_client.YnabClient.update_transactions', MagicMock())
# item_categories is mapping of item title -> category
category_names = set(item_categories.values())
category_ids = {cat: str(i) for i, cat in enumerate(category_names)}
monkeypatch.setattr('catnab.ynab_client.YnabClient.category_ids', category_ids)
def classify(item_names, _categories):
result = {}
for n in item_names:
result[n] = ItemClassification(
name=n,
category=item_categories[n],
description='',
)
return result
monkeypatch.setattr('catnab.ai.classify', classify)
return setup
@pytest.fixture
def basic_order(mk_amz_tx, mk_ynab_tx, setup_mock_order):
items = [order_item(title='test', price=120.34, quantity=1)]
item_categories = {'test': 'example category'}
order = amz_order(
order_number='A',
items=items,
grand_total=123.45,
)
amz_tx = mk_amz_tx(order_number='A', grand_total=123.45)
ynab_tx = mk_ynab_tx(id='1', amount=123450)
setup_mock_order(
orders=[order],
amz_hist=[amz_tx],
ynab_hist=[ynab_tx],
item_categories=item_categories,
)
@pytest.fixture
def multi_item_order(mk_amz_tx, mk_ynab_tx, setup_mock_order):
items = [
order_item(title='item 1', price=59.36, quantity=1),
order_item(title='item 2', price=22.18, quantity=1),
]
item_categories={'item 1': 'example category', 'item 2': 'example category'}
order = amz_order(
order_number='A',
items=items,
grand_total=81.54,
)
amz_tx = mk_amz_tx(order_number='A', grand_total=81.54)
ynab_tx = mk_ynab_tx(id='1', amount=81540)
setup_mock_order(
orders=[order],
amz_hist=[amz_tx],
ynab_hist=[ynab_tx],
item_categories=item_categories
)
@pytest.fixture
def multi_category_order(mk_amz_tx, mk_ynab_tx, setup_mock_order):
items = [
order_item(title='item 1', price=59.36, quantity=1),
order_item(title='item 2', price=22.18, quantity=1),
]
# first category will have id 0, second category will have id 1
item_categories={'item 1': 'example category', 'item 2': 'another category'}
order = amz_order(
order_number='A',
items=items,
grand_total=81.54,
)
amz_tx = mk_amz_tx(order_number='A', grand_total=81.54)
ynab_tx = mk_ynab_tx(id='1', amount=81540)
setup_mock_order(
orders=[order],
amz_hist=[amz_tx],
ynab_hist=[ynab_tx],
item_categories=item_categories
)
@pytest.fixture
def ynab_creds(monkeypatch):
monkeypatch.setenv('YNAB_BUDGET_ID', '00000000-0000-0000-0000-000000000000')
monkeypatch.setenv('YNAB_TOKEN', 'very_secure_token')