Files
SpendingAnalysis/tests/services/test_analysis.py
andy db06108d2b feat: complete v1 implementation - all services, UI views, and tests
Adds remaining files from parallel development:
- Services: analysis, csv_reader, forecasting, normalizer, recurring
- UI: recurring_view, settings_view, sidebar, themes (dark/light)
- Tests: analysis, csv_reader, forecasting, import_categorize,
  normalizer, recurring, integration
- App entry point (main.py) and CLAUDE.md

52 tests passing across all modules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 14:57:46 -05:00

93 lines
3.2 KiB
Python

# tests/services/test_analysis.py
import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from src.db import Base
from src.models import *
from src.seed import seed_categories
from src.services.analysis import AnalysisService
def make_session():
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
return Session(engine)
def make_test_data(session):
seed_categories(session)
member = HouseholdMember(name="Andrew", relationship="self")
session.add(member)
session.flush()
account = Account(name="Chase", institution="Chase", account_type="credit", owner_id=member.id)
session.add(account)
session.flush()
groceries = session.query(Category).filter_by(name="Groceries").one()
dining = session.query(Category).filter_by(name="Dining Out").one()
txns = [
Transaction(date=datetime.date(2026, 1, 5), amount=-50.0, description="PUBLIX", account_id=account.id, category_id=groceries.id, tag="needs"),
Transaction(date=datetime.date(2026, 1, 12), amount=-30.0, description="ALDI", account_id=account.id, category_id=groceries.id, tag="needs"),
Transaction(date=datetime.date(2026, 1, 20), amount=-15.0, description="CHICK-FIL-A", account_id=account.id, category_id=dining.id, tag="wants"),
Transaction(date=datetime.date(2026, 2, 3), amount=-60.0, description="PUBLIX", account_id=account.id, category_id=groceries.id, tag="needs"),
Transaction(date=datetime.date(2026, 2, 7), amount=-25.0, description="KFC", account_id=account.id, category_id=dining.id, tag="wants"),
]
session.add_all(txns)
session.commit()
return account, member
def test_spending_by_month():
session = make_session()
make_test_data(session)
svc = AnalysisService(session)
result = svc.spending_by_period("month")
assert len(result) == 2
jan = [r for r in result if r["period"] == "2026-01"][0]
assert jan["total"] == -95.0
def test_spending_by_category():
session = make_session()
make_test_data(session)
svc = AnalysisService(session)
result = svc.spending_by_category(
start=datetime.date(2026, 1, 1),
end=datetime.date(2026, 2, 28),
)
groceries_row = [r for r in result if r["category"] == "Groceries"][0]
assert groceries_row["total"] == -140.0
def test_spending_by_tag():
session = make_session()
make_test_data(session)
svc = AnalysisService(session)
result = svc.spending_by_tag(
start=datetime.date(2026, 1, 1),
end=datetime.date(2026, 2, 28),
)
needs = [r for r in result if r["tag"] == "needs"][0]
wants = [r for r in result if r["tag"] == "wants"][0]
assert needs["total"] == -140.0
assert wants["total"] == -40.0
def test_spending_filtered_by_person():
session = make_session()
account, member = make_test_data(session)
txns = session.query(Transaction).all()
for t in txns:
t.attributed_to_id = member.id
session.commit()
svc = AnalysisService(session)
result = svc.spending_by_category(
start=datetime.date(2026, 1, 1),
end=datetime.date(2026, 2, 28),
person_id=member.id,
)
total = sum(r["total"] for r in result)
assert total == -180.0