init
This commit is contained in:
commit
ac93e6074b
38 changed files with 7162 additions and 0 deletions
124
tests/test_bulk_edit.py
Normal file
124
tests/test_bulk_edit.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
"""Pure-Python tests for the bulk-edit data path. The Textual modal itself
|
||||
is exercised manually; here we lock in the semantics of the per-row diff
|
||||
overlay so a regression in the loop is caught."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from common_cents.db import Database
|
||||
from common_cents.screens._spending_bulk_form import _split_tags
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def db(tmp_path: Path) -> Database:
|
||||
return Database(tmp_path / "test.db")
|
||||
|
||||
|
||||
def _seed(db: Database, *rows) -> list[int]:
|
||||
for r in rows:
|
||||
db.add_spending(*r)
|
||||
return [row["id"] for row in db.get_spending()]
|
||||
|
||||
|
||||
def _apply_diff(db: Database, ids: list[int], diff: dict) -> int:
|
||||
"""Mirror BulkEditScreen._write so the overlay logic can be tested headlessly."""
|
||||
tag_ids: list[int] | None = None
|
||||
if "tag_names" in diff:
|
||||
tag_ids = [db.get_or_create_metadata("tag", n) for n in diff["tag_names"]]
|
||||
updated = 0
|
||||
for sid in ids:
|
||||
row = db.get_spending_by_id(sid)
|
||||
if row is None:
|
||||
continue
|
||||
new_date = diff.get("date", row["date"])
|
||||
new_category = diff.get("category", row["category_name"])
|
||||
new_merchant = diff["merchant"] if "merchant" in diff else row["merchant_name"]
|
||||
new_notes = diff["notes"] if "notes" in diff else row["notes"]
|
||||
new_tags = (
|
||||
tag_ids
|
||||
if tag_ids is not None
|
||||
else db.get_spending_metadata_ids(sid, "tag")
|
||||
)
|
||||
db.update_spending(
|
||||
sid,
|
||||
new_date,
|
||||
row["cents"],
|
||||
new_category,
|
||||
new_merchant,
|
||||
new_notes,
|
||||
new_tags,
|
||||
)
|
||||
updated += 1
|
||||
return updated
|
||||
|
||||
|
||||
def test_split_tags_strips_and_drops_empty():
|
||||
assert _split_tags("a, b , ,c") == ["a", "b", "c"]
|
||||
assert _split_tags("") == []
|
||||
assert _split_tags(" ") == []
|
||||
|
||||
|
||||
def test_bulk_recategorize_preserves_other_fields(db):
|
||||
ids = _seed(
|
||||
db,
|
||||
("2026-05-01", 1500, "Food", "Whole Foods", "lunch", []),
|
||||
("2026-05-02", 2500, "Food", "Trader Joes", None, []),
|
||||
)
|
||||
_apply_diff(db, ids, {"category": "Groceries"})
|
||||
rows = db.get_spending()
|
||||
assert {r["category"] for r in rows} == {"Groceries"}
|
||||
# merchants and notes preserved
|
||||
by_date = {r["date"]: r for r in rows}
|
||||
assert by_date["2026-05-01"]["merchant"] == "Whole Foods"
|
||||
assert by_date["2026-05-01"]["notes"] == "lunch"
|
||||
assert by_date["2026-05-02"]["merchant"] == "Trader Joes"
|
||||
|
||||
|
||||
def test_bulk_clear_merchant_and_notes(db):
|
||||
ids = _seed(
|
||||
db,
|
||||
("2026-05-01", 1500, "Food", "X", "n1", []),
|
||||
("2026-05-02", 2500, "Food", "Y", "n2", []),
|
||||
)
|
||||
_apply_diff(db, ids, {"merchant": None, "notes": None})
|
||||
for row in db.get_spending():
|
||||
assert row["merchant"] is None
|
||||
assert row["notes"] is None
|
||||
|
||||
|
||||
def test_bulk_replace_tags_overwrites_existing(db):
|
||||
food_id = db.add_metadata("tag", "lunch")
|
||||
ids = _seed(
|
||||
db,
|
||||
("2026-05-01", 1500, "Food", None, None, [food_id]),
|
||||
("2026-05-02", 2500, "Food", None, None, []),
|
||||
)
|
||||
_apply_diff(db, ids, {"tag_names": ["work", "client"]})
|
||||
for sid in ids:
|
||||
names = sorted(
|
||||
t["name"]
|
||||
for t in db.get_metadata("tag")
|
||||
if t["id"] in db.get_spending_metadata_ids(sid, "tag")
|
||||
)
|
||||
assert names == ["client", "work"]
|
||||
|
||||
|
||||
def test_bulk_clear_tags(db):
|
||||
work_id = db.add_metadata("tag", "work")
|
||||
ids = _seed(
|
||||
db,
|
||||
("2026-05-01", 1500, "Food", None, None, [work_id]),
|
||||
)
|
||||
_apply_diff(db, ids, {"tag_names": []})
|
||||
assert db.get_spending_metadata_ids(ids[0], "tag") == []
|
||||
|
||||
|
||||
def test_bulk_skips_missing_id(db):
|
||||
ids = _seed(
|
||||
db,
|
||||
("2026-05-01", 1500, "Food", None, None, []),
|
||||
)
|
||||
n = _apply_diff(db, [*ids, 99999], {"category": "Travel"})
|
||||
assert n == 1 # the bogus id is skipped, not raised
|
||||
assert db.get_spending()[0]["category"] == "Travel"
|
||||
Loading…
Add table
Add a link
Reference in a new issue