import json import os import sys import tempfile sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from src import store def _fresh_db(): path = os.path.join(tempfile.mkdtemp(), "t.sqlite") conn = store.connect(path) store.init_db(conn) return conn def _row(id_, ts, mood, tags, note="", affirmation=""): return {"id": id_, "ts": ts, "mood": mood, "tags": json.dumps(tags), "note": note, "affirmation": affirmation} def test_upsert_idempotent(): conn = _fresh_db() rows = [ _row(1, "2026-07-01T08:00:00+00:00", 4, ["calm"]), _row(2, "2026-07-02T08:00:00+00:00", 2, ["sad", "tired"]), ] store.upsert_entries(conn, rows) store.upsert_entries(conn, rows) # re-run same rows count = conn.execute("SELECT COUNT(*) c FROM mood_entries").fetchone()["c"] assert count == 2 # no duplication despite double ingest def test_upsert_updates_on_conflict(): conn = _fresh_db() rows = [_row(1, "2026-07-01T08:00:00+00:00", 4, ["calm"], note="first")] store.upsert_entries(conn, rows) rows[0]["note"] = "corrected" store.upsert_entries(conn, rows) got = conn.execute("SELECT note FROM mood_entries WHERE source_id=1").fetchone()["note"] assert got == "corrected" def test_sync_state_high_water_mark(): conn = _fresh_db() store.set_sync_state(conn, "moodtracker_entries", 5) store.set_sync_state(conn, "moodtracker_entries", 3) # older cursor must not regress assert store.get_last_synced_id(conn, "moodtracker_entries") == 5 store.set_sync_state(conn, "moodtracker_entries", 9) assert store.get_last_synced_id(conn, "moodtracker_entries") == 9 def test_summary_and_daily_mood(): conn = _fresh_db() rows = [ _row(1, "2026-07-01T08:00:00+00:00", 4, ["calm"]), _row(2, "2026-07-01T20:00:00+00:00", 2, ["tired"]), _row(3, "2026-07-02T08:00:00+00:00", 5, ["happy"]), ] store.upsert_entries(conn, rows) s = store.summary(conn) assert s["entries"] == 3 assert s["coverage"]["earliest"] is not None daily = store.daily_mood(conn, days=30) by_day = {d["day"]: d for d in daily} assert by_day["2026-07-01"]["entries"] == 2 assert by_day["2026-07-01"]["avg_mood"] == 3.0 # (4+2)/2 assert by_day["2026-07-02"]["avg_mood"] == 5.0 def test_tag_breakdown(): conn = _fresh_db() rows = [ _row(1, "2026-07-01T08:00:00+00:00", 5, ["happy", "energetic"]), _row(2, "2026-07-02T08:00:00+00:00", 1, ["sad", "tired"]), _row(3, "2026-07-03T08:00:00+00:00", 2, ["tired"]), ] store.upsert_entries(conn, rows) tags = store.tag_breakdown(conn, days=90, min_count=2) by_tag = {t["tag"]: t for t in tags} assert by_tag["tired"]["count"] == 2 assert by_tag["tired"]["avg_mood"] == 1.5 assert "happy" not in by_tag # min_count=2 filters singletons def test_correlate_with_series(): conn = _fresh_db() rows = [ _row(1, "2026-07-01T08:00:00+00:00", 5, []), _row(2, "2026-07-02T08:00:00+00:00", 4, []), _row(3, "2026-07-03T08:00:00+00:00", 2, []), _row(4, "2026-07-04T08:00:00+00:00", 1, []), ] store.upsert_entries(conn, rows) # perfectly correlated external series (e.g. "hours slept") external = { "2026-07-01": 8.0, "2026-07-02": 7.0, "2026-07-03": 5.0, "2026-07-04": 4.0, } result = store.correlate_with_series(conn, external, days=30) assert result["n"] == 4 assert result["r"] > 0.99 # near-perfect positive correlation def test_correlate_too_few_points(): conn = _fresh_db() store.upsert_entries(conn, [_row(1, "2026-07-01T08:00:00+00:00", 3, [])]) result = store.correlate_with_series(conn, {"2026-07-01": 5.0}, days=30) assert result["n"] == 1 assert result["r"] is None