Spaces:
Running
Running
| """Tests for new database methods: user profile and scheduled medications.""" | |
| import pytest | |
| from reachy_mini_conversation_app.database import MiniMinderDB | |
| def db() -> MiniMinderDB: | |
| """Create an in-memory database for testing.""" | |
| return MiniMinderDB(":memory:") | |
| # ----------------------------------------------------------------------------- | |
| # User Profile Tests | |
| # ----------------------------------------------------------------------------- | |
| def test_get_or_create_profile(db: MiniMinderDB) -> None: | |
| """Profile should be created on first access.""" | |
| profile = db.get_or_create_profile() | |
| assert profile is not None | |
| assert profile["id"] == 1 | |
| assert profile["onboarding_completed"] == 0 | |
| assert profile["onboarding_step"] == "name" | |
| def test_get_or_create_profile_idempotent(db: MiniMinderDB) -> None: | |
| """Getting profile multiple times should return same data.""" | |
| profile1 = db.get_or_create_profile() | |
| profile2 = db.get_or_create_profile() | |
| assert profile1["id"] == profile2["id"] | |
| assert profile1["created_at"] == profile2["created_at"] | |
| def test_update_profile(db: MiniMinderDB) -> None: | |
| """Profile updates should persist.""" | |
| db.update_profile( | |
| { | |
| "display_name": "Alice", | |
| "onboarding_completed": 1, | |
| "onboarding_step": "done", | |
| } | |
| ) | |
| profile = db.get_or_create_profile() | |
| assert profile["display_name"] == "Alice" | |
| assert profile["onboarding_completed"] == 1 | |
| assert profile["onboarding_step"] == "done" | |
| def test_is_onboarding_complete_default(db: MiniMinderDB) -> None: | |
| """Onboarding should not be complete by default.""" | |
| assert db.is_onboarding_complete() is False | |
| def test_is_onboarding_complete_after_update(db: MiniMinderDB) -> None: | |
| """Onboarding should be complete after marking it.""" | |
| db.update_profile({"onboarding_completed": 1}) | |
| assert db.is_onboarding_complete() is True | |
| # ----------------------------------------------------------------------------- | |
| # Scheduled Medications Tests | |
| # ----------------------------------------------------------------------------- | |
| def test_add_scheduled_medication(db: MiniMinderDB) -> None: | |
| """Add and retrieve a scheduled medication.""" | |
| med_id = db.add_scheduled_medication( | |
| { | |
| "medication_name": "Ibuprofen", | |
| "dose": "400mg", | |
| "frequency": "twice daily", | |
| "times_of_day": ["morning", "evening"], | |
| } | |
| ) | |
| assert med_id == 1 | |
| meds = db.get_scheduled_medications() | |
| assert len(meds) == 1 | |
| assert meds[0]["medication_name"] == "Ibuprofen" | |
| assert meds[0]["dose"] == "400mg" | |
| assert meds[0]["times_of_day"] == ["morning", "evening"] | |
| def test_add_multiple_medications(db: MiniMinderDB) -> None: | |
| """Add multiple medications.""" | |
| db.add_scheduled_medication({"medication_name": "Med A"}) | |
| db.add_scheduled_medication({"medication_name": "Med B"}) | |
| db.add_scheduled_medication({"medication_name": "Med C"}) | |
| meds = db.get_scheduled_medications() | |
| assert len(meds) == 3 | |
| names = [m["medication_name"] for m in meds] | |
| assert "Med A" in names | |
| assert "Med B" in names | |
| assert "Med C" in names | |
| def test_scheduled_medication_with_reminders(db: MiniMinderDB) -> None: | |
| """Medications can have reminder times.""" | |
| db.add_scheduled_medication( | |
| { | |
| "medication_name": "Blood Pressure Med", | |
| "reminder_enabled": 1, | |
| "reminder_times": ["07:55", "19:55"], | |
| } | |
| ) | |
| meds = db.get_scheduled_medications() | |
| assert len(meds) == 1 | |
| assert meds[0]["reminder_enabled"] == 1 | |
| assert meds[0]["reminder_times"] == ["07:55", "19:55"] | |
| def test_update_scheduled_medication(db: MiniMinderDB) -> None: | |
| """Update an existing medication.""" | |
| med_id = db.add_scheduled_medication( | |
| { | |
| "medication_name": "Aspirin", | |
| "dose": "100mg", | |
| } | |
| ) | |
| success = db.update_scheduled_medication( | |
| med_id, | |
| { | |
| "dose": "200mg", | |
| "frequency": "once daily", | |
| }, | |
| ) | |
| assert success is True | |
| meds = db.get_scheduled_medications() | |
| assert meds[0]["dose"] == "200mg" | |
| assert meds[0]["frequency"] == "once daily" | |
| def test_deactivate_scheduled_medication(db: MiniMinderDB) -> None: | |
| """Deactivated medications should not appear in active list.""" | |
| med_id = db.add_scheduled_medication({"medication_name": "Old Med"}) | |
| success = db.deactivate_scheduled_medication(med_id) | |
| assert success is True | |
| # Should not appear in active list | |
| active_meds = db.get_scheduled_medications(active_only=True) | |
| assert len(active_meds) == 0 | |
| # Should appear in full list | |
| all_meds = db.get_scheduled_medications(active_only=False) | |
| assert len(all_meds) == 1 | |
| assert all_meds[0]["active"] == 0 | |
| def test_update_nonexistent_medication(db: MiniMinderDB) -> None: | |
| """Updating a nonexistent medication should return False.""" | |
| success = db.update_scheduled_medication(999, {"dose": "100mg"}) | |
| # Note: SQLite UPDATE returns 0 rows affected, so this returns False | |
| assert success is False | |
| # ----------------------------------------------------------------------------- | |
| # Upsert Scheduled Medication Tests | |
| # ----------------------------------------------------------------------------- | |
| def test_upsert_scheduled_medication_new(db: MiniMinderDB) -> None: | |
| """Upsert should create a new row when no match exists.""" | |
| med_id, is_new = db.upsert_scheduled_medication( | |
| {"medication_name": "Aspirin", "dose": "100mg"} | |
| ) | |
| assert is_new is True | |
| assert med_id >= 1 | |
| meds = db.get_scheduled_medications() | |
| assert len(meds) == 1 | |
| assert meds[0]["medication_name"] == "Aspirin" | |
| def test_upsert_scheduled_medication_existing(db: MiniMinderDB) -> None: | |
| """Upsert should update existing row and not create a duplicate.""" | |
| # First call: creates the row | |
| med_id_1, is_new_1 = db.upsert_scheduled_medication( | |
| {"medication_name": "Amitriptyline"} | |
| ) | |
| assert is_new_1 is True | |
| # Second call: same name, adds dose — should update | |
| med_id_2, is_new_2 = db.upsert_scheduled_medication( | |
| {"medication_name": "Amitriptyline", "dose": "10mg"} | |
| ) | |
| assert is_new_2 is False | |
| assert med_id_2 == med_id_1 | |
| # Third call: same name, adds frequency — should update again | |
| med_id_3, is_new_3 = db.upsert_scheduled_medication( | |
| {"medication_name": "Amitriptyline", "dose": "10mg", "frequency": "once daily"} | |
| ) | |
| assert is_new_3 is False | |
| assert med_id_3 == med_id_1 | |
| # Only one row should exist with all the merged data | |
| meds = db.get_scheduled_medications() | |
| assert len(meds) == 1 | |
| assert meds[0]["dose"] == "10mg" | |
| assert meds[0]["frequency"] == "once daily" | |
| def test_upsert_case_insensitive(db: MiniMinderDB) -> None: | |
| """Upsert should match medication names case-insensitively.""" | |
| db.upsert_scheduled_medication({"medication_name": "Aspirin"}) | |
| med_id, is_new = db.upsert_scheduled_medication( | |
| {"medication_name": "aspirin", "dose": "200mg"} | |
| ) | |
| assert is_new is False | |
| meds = db.get_scheduled_medications() | |
| assert len(meds) == 1 | |
| def test_schema_includes_new_tables(db: MiniMinderDB) -> None: | |
| """The new tables should exist.""" | |
| conn = db._get_conn() | |
| tables = conn.execute( | |
| "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name" | |
| ).fetchall() | |
| table_names = [t["name"] for t in tables] | |
| assert "user_profile" in table_names | |
| assert "scheduled_medications" in table_names | |