"""Tests for ledgerly.services.budgets (R2, R7).""" import pytest from ledgerly.errors import NotFoundError, ValidationError from ledgerly.money import Money from ledgerly.repository import SqliteRepository from ledgerly.services import BudgetService @pytest.fixture() def service(): repo = SqliteRepository(":memory:") yield BudgetService(repo) repo.close() def test_set_budget(service): budget = service.set_budget("Rent", Money(150000)) assert budget.category == "Rent" assert budget.amount == Money(150000) assert service.list_budgets() == [budget] def test_set_budget_replaces(service): service.set_budget("Rent", Money(100)) service.set_budget("Rent", Money(200)) assert [b.amount for b in service.list_budgets()] == [Money(200)] def test_set_budget_rejects_zero(service): with pytest.raises(ValidationError, match="greater than zero"): service.set_budget("Rent", Money(0)) def test_set_budget_unknown_category(service): with pytest.raises(NotFoundError): service.set_budget("Nope", Money(100)) def test_set_budget_rejects_income_category(service): with pytest.raises(ValidationError, match="expense"): service.set_budget("Salary", Money(100)) def test_delete_budget_missing_category(service): with pytest.raises(NotFoundError): service.delete_budget("Nope") def test_delete_budget_not_set(service): with pytest.raises(NotFoundError, match="no budget"): service.delete_budget("Rent") def test_delete_budget_ok(service): service.set_budget("Rent", Money(100)) deleted = service.delete_budget("rent") assert deleted.category == "Rent" assert deleted.amount == Money(100) assert service.list_budgets() == []