import base64 import json import sqlite3 import sys import tempfile import threading import unittest from datetime import date, timedelta from http.client import HTTPConnection from pathlib import Path import app class StoreTests(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.store = app.Store(Path(self.temp.name) / "flowtrack.sqlite3") self.store.initialize() def tearDown(self): self.temp.cleanup() def test_empty_log_deletes_the_day(self): self.store.set_day("2026-10-01", {"flow": "heavy", "symptoms": ["cramps"]}) self.assertEqual(self.store.days(), {"2026-10-01": {"flow": "heavy", "symptoms": ["cramps"]}}) self.store.set_day("2026-10-01", {"flow": None, "symptoms": []}) self.assertEqual(self.store.days(), {}) def test_fill_never_overwrites(self): self.store.set_day("2026-10-01", {"flow": "heavy", "symptoms": []}) added = self.store.fill_days({ "2026-10-01": {"flow": "period", "symptoms": []}, "2026-10-02": {"flow": "period", "symptoms": []}, }) self.assertEqual(added, 1) self.assertEqual(self.store.days()["2026-10-01"]["flow"], "heavy") def test_backup_rotates(self): self.store.set_day("2026-10-01", {"flow": "light", "symptoms": []}) destination = Path(self.temp.name) / "backups" destination.mkdir() for stale in ("2026-01-01", "2026-01-02", "2026-01-03"): (destination / f"flowtrack-{stale}.sqlite3").touch() target = self.store.backup(destination, keep=2) self.assertEqual(sorted(path.name for path in destination.iterdir()), ["flowtrack-2026-01-03.sqlite3", target.name]) with sqlite3.connect(target) as copy: self.assertEqual(copy.execute("SELECT flow FROM days").fetchone()[0], "light") class ValidationTests(unittest.TestCase): def test_dates(self): self.assertIsNotNone(app.parse_day(date.today().isoformat())) self.assertIsNotNone(app.parse_day((date.today() + timedelta(days=1)).isoformat())) self.assertIsNone(app.parse_day((date.today() + timedelta(days=2)).isoformat())) self.assertIsNone(app.parse_day("2026-02-30")) self.assertIsNone(app.parse_day("26-10-01")) def test_entries(self): self.assertEqual(app.clean_entry({"flow": "light", "symptoms": ["acne", "cramps", "acne"]}), {"flow": "light", "symptoms": ["acne", "cramps"]}) self.assertIsNone(app.clean_entry({"flow": "gushing"})) self.assertIsNone(app.clean_entry({"flow": None, "symptoms": ["