298 lines
7.9 KiB
Python
298 lines
7.9 KiB
Python
"""Test SQLite cache operations."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import tempfile
|
|
from datetime import date
|
|
|
|
import pytest
|
|
|
|
from src.cache import Cache
|
|
from src.models import Bill, Legislator, Summary, Vote
|
|
|
|
|
|
@pytest.fixture
|
|
def cache() -> Cache:
|
|
fd, path = tempfile.mkstemp(suffix=".db")
|
|
c = Cache(path)
|
|
yield c
|
|
c.close()
|
|
os.close(fd)
|
|
os.unlink(path)
|
|
|
|
|
|
# --- Legislators ---
|
|
|
|
|
|
def test_save_and_get_legislator(cache: Cache):
|
|
leg = Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
in_office=True,
|
|
start_date=date(2025, 1, 3),
|
|
end_date=None,
|
|
)
|
|
cache.save_legislator(leg)
|
|
fetched = cache.get_legislator("L001")
|
|
assert fetched is not None
|
|
assert fetched.id == "L001"
|
|
assert fetched.full_name == "John Doe"
|
|
assert fetched.party == "Democrat"
|
|
assert fetched.start_date == date(2025, 1, 3)
|
|
assert fetched.end_date is None
|
|
|
|
|
|
def test_get_missing_legislator(cache: Cache):
|
|
assert cache.get_legislator("MISSING") is None
|
|
|
|
|
|
def test_search_legislators(cache: Cache):
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
)
|
|
)
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L002",
|
|
first_name="Jane",
|
|
last_name="Smith",
|
|
full_name="Jane Smith",
|
|
party="Republican",
|
|
state="NY",
|
|
chamber="House",
|
|
)
|
|
)
|
|
results = cache.search_legislators("John")
|
|
assert len(results) == 1
|
|
assert results[0].full_name == "John Doe"
|
|
|
|
results = cache.search_legislators("Smith")
|
|
assert len(results) == 1
|
|
assert results[0].last_name == "Smith"
|
|
|
|
|
|
def test_legislator_retired(cache: Cache):
|
|
leg = Legislator(
|
|
id="M000355",
|
|
first_name="Mitch",
|
|
last_name="McConnell",
|
|
full_name="Mitch McConnell",
|
|
party="Republican",
|
|
state="KY",
|
|
chamber="Senate",
|
|
in_office=False,
|
|
start_date=date(1985, 1, 3),
|
|
end_date=date(2025, 12, 31),
|
|
)
|
|
cache.save_legislator(leg)
|
|
fetched = cache.get_legislator("M000355")
|
|
assert fetched is not None
|
|
assert fetched.in_office is False
|
|
assert fetched.start_date == date(1985, 1, 3)
|
|
assert fetched.end_date == date(2025, 12, 31)
|
|
|
|
|
|
def test_legislator_update(cache: Cache):
|
|
"""Updating a legislator preserves all fields."""
|
|
leg = Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
start_date=date(2025, 1, 3),
|
|
end_date=None,
|
|
)
|
|
cache.save_legislator(leg)
|
|
|
|
leg.party = "Independent"
|
|
leg.in_office = False
|
|
leg.end_date = date(2027, 12, 31)
|
|
cache.save_legislator(leg)
|
|
|
|
fetched = cache.get_legislator("L001")
|
|
assert fetched.party == "Independent"
|
|
assert fetched.in_office is False
|
|
assert fetched.end_date == date(2027, 12, 31)
|
|
assert fetched.start_date == date(2025, 1, 3)
|
|
|
|
|
|
# --- Bills ---
|
|
|
|
|
|
def test_save_and_get_bill(cache: Cache):
|
|
bill = Bill(bill_id="B100", title="Test Bill", subject="Education", text="Full text", enacted=True)
|
|
cache.save_bill(bill)
|
|
fetched = cache.get_bill("B100")
|
|
assert fetched is not None
|
|
assert fetched.title == "Test Bill"
|
|
assert fetched.subject == "Education"
|
|
assert fetched.enacted is True
|
|
|
|
|
|
def test_get_missing_bill(cache: Cache):
|
|
assert cache.get_bill("MISSING") is None
|
|
|
|
|
|
# --- Votes ---
|
|
|
|
|
|
def test_save_and_get_vote(cache: Cache):
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
)
|
|
)
|
|
vote = Vote(legislator_id="L001", roll_call_id="RC001", vote_type="Yea", bill_id="B100", bill_title="Test Bill")
|
|
cache.save_vote(vote)
|
|
votes = cache.get_votes("L001")
|
|
assert len(votes) == 1
|
|
assert votes[0].vote_type == "Yea"
|
|
|
|
|
|
def test_save_multiple_votes(cache: Cache):
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
)
|
|
)
|
|
cache.save_votes(
|
|
[
|
|
Vote(legislator_id="L001", roll_call_id="RC001", vote_type="Yea", bill_id="B100", bill_title="Bill A"),
|
|
Vote(legislator_id="L001", roll_call_id="RC002", vote_type="Nay", bill_id="B101", bill_title="Bill B"),
|
|
]
|
|
)
|
|
votes = cache.get_votes("L001")
|
|
assert len(votes) == 2
|
|
|
|
|
|
def test_vote_duplicate_ignored(cache: Cache):
|
|
"""INSERT OR IGNORE prevents duplicate votes."""
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
)
|
|
)
|
|
vote = Vote(legislator_id="L001", roll_call_id="RC001", vote_type="Yea", bill_id="B100", bill_title="Test Bill")
|
|
cache.save_vote(vote)
|
|
cache.save_vote(vote)
|
|
votes = cache.get_votes("L001")
|
|
assert len(votes) == 1
|
|
|
|
|
|
# --- Summaries ---
|
|
|
|
|
|
def test_save_and_get_summary(cache: Cache):
|
|
cache.save_bill(Bill(bill_id="B100", title="Test Bill", subject="Education"))
|
|
summary = Summary(
|
|
bill_id="B100",
|
|
summary_text="This bill does X.",
|
|
key_measures=["Measure A", "Measure B"],
|
|
model_name="gpt-oss",
|
|
)
|
|
cache.save_summary(summary)
|
|
fetched = cache.get_summary("B100")
|
|
assert fetched is not None
|
|
assert fetched.summary_text == "This bill does X."
|
|
assert fetched.key_measures == ["Measure A", "Measure B"]
|
|
assert fetched.model_name == "gpt-oss"
|
|
|
|
|
|
def test_get_missing_summary(cache: Cache):
|
|
assert cache.get_summary("MISSING") is None
|
|
|
|
|
|
# --- Voting Record ---
|
|
|
|
|
|
def test_voting_record(cache: Cache):
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
)
|
|
)
|
|
cache.save_bill(Bill(bill_id="B100", title="Test Bill", subject="Education"))
|
|
cache.save_vote(
|
|
Vote(legislator_id="L001", roll_call_id="RC001", vote_type="Yea", bill_id="B100", bill_title="Test Bill")
|
|
)
|
|
records, total = cache.get_voting_record("L001")
|
|
assert len(records) == 1
|
|
assert total == 1
|
|
assert records[0]["vote_type"] == "Yea"
|
|
assert records[0]["bill_title"] == "Test Bill"
|
|
|
|
|
|
def test_voting_record_empty(cache: Cache):
|
|
records, total = cache.get_voting_record("MISSING")
|
|
assert records == []
|
|
assert total == 0
|
|
|
|
|
|
def test_voting_record_pagination(cache: Cache):
|
|
cache.save_legislator(
|
|
Legislator(
|
|
id="L001",
|
|
first_name="John",
|
|
last_name="Doe",
|
|
full_name="John Doe",
|
|
party="Democrat",
|
|
state="CA",
|
|
chamber="Senate",
|
|
)
|
|
)
|
|
cache.save_votes(
|
|
[
|
|
Vote(legislator_id="L001", roll_call_id=f"RC{i}", vote_type="Yea", bill_id=f"B{i}", bill_title=f"Bill {i}")
|
|
for i in range(10)
|
|
]
|
|
)
|
|
records, total = cache.get_voting_record("L001", limit=3, offset=0)
|
|
assert len(records) == 3
|
|
assert total == 10
|
|
|
|
records, total = cache.get_voting_record("L001", limit=3, offset=3)
|
|
assert len(records) == 3
|
|
|
|
records, total = cache.get_voting_record("L001", limit=3, offset=9)
|
|
assert len(records) == 1
|