| from datetime import date |
| import json |
| import os |
| from pathlib import Path |
| from tempfile import TemporaryDirectory |
| import unittest |
| from unittest.mock import patch |
|
|
| from training_coach.models import CompletedSession, CompletedSet |
| from training_coach.storage import ( |
| HuggingFaceDatasetHistoryStore, |
| JsonHistoryStore, |
| create_history_store, |
| ) |
|
|
|
|
| def _completed_session(day_number: int) -> CompletedSession: |
| return CompletedSession( |
| date=date(2026, 6, 11), |
| day_number=day_number, |
| completed_sets=[ |
| CompletedSet( |
| exercise_id="dumbbell-row", |
| set_number=1, |
| actual_reps=16, |
| actual_load=32.5, |
| rpe=8, |
| ) |
| ], |
| ) |
|
|
|
|
| class JsonHistoryStoreTest(unittest.TestCase): |
| def test_missing_history_file_loads_as_empty_list(self): |
| with TemporaryDirectory() as directory: |
| store = JsonHistoryStore(Path(directory) / "history.json") |
|
|
| self.assertEqual(store.load_completed_sessions(), []) |
|
|
| def test_save_and_load_completed_sessions(self): |
| with TemporaryDirectory() as directory: |
| store = JsonHistoryStore(Path(directory) / "history.json") |
|
|
| store.save_completed_sessions([_completed_session(day_number=2)]) |
| sessions = store.load_completed_sessions() |
|
|
| self.assertEqual(len(sessions), 1) |
| self.assertEqual(sessions[0].day_number, 2) |
| self.assertEqual(sessions[0].completed_sets[0].exercise_id, "dumbbell-row") |
|
|
| def test_append_completed_session_preserves_existing_history(self): |
| with TemporaryDirectory() as directory: |
| store = JsonHistoryStore(Path(directory) / "history.json") |
|
|
| store.append_completed_session(_completed_session(day_number=1)) |
| store.append_completed_session(_completed_session(day_number=2)) |
| sessions = store.load_completed_sessions() |
|
|
| self.assertEqual([session.day_number for session in sessions], [1, 2]) |
|
|
|
|
| class _FakeHfApi: |
| def __init__(self): |
| self.created_repos = [] |
| self.uploads = [] |
| self.uploaded_payload = None |
|
|
| def create_repo(self, **kwargs): |
| self.created_repos.append(kwargs) |
|
|
| def upload_file(self, **kwargs): |
| self.uploads.append(kwargs) |
| self.uploaded_payload = Path(kwargs["path_or_fileobj"]).read_text( |
| encoding="utf-8" |
| ) |
|
|
|
|
| class HuggingFaceDatasetHistoryStoreTest(unittest.TestCase): |
| def test_load_completed_sessions_downloads_history_file(self): |
| with TemporaryDirectory() as directory: |
| history_path = Path(directory) / "completed_sessions.json" |
| history_path.write_text( |
| json.dumps( |
| { |
| "completed_sessions": [ |
| _completed_session(day_number=3).model_dump(mode="json") |
| ] |
| } |
| ), |
| encoding="utf-8", |
| ) |
| store = HuggingFaceDatasetHistoryStore( |
| repo_id="lucas/training-history", |
| token="secret", |
| downloader=lambda **_: str(history_path), |
| ) |
|
|
| sessions = store.load_completed_sessions() |
|
|
| self.assertEqual(len(sessions), 1) |
| self.assertEqual(sessions[0].day_number, 3) |
|
|
| def test_load_completed_sessions_forces_fresh_hub_download(self): |
| download_calls = [] |
|
|
| with TemporaryDirectory() as directory: |
| history_path = Path(directory) / "completed_sessions.json" |
| history_path.write_text( |
| json.dumps( |
| { |
| "completed_sessions": [ |
| _completed_session(day_number=1).model_dump(mode="json") |
| ] |
| } |
| ), |
| encoding="utf-8", |
| ) |
|
|
| def fake_downloader(**kwargs): |
| download_calls.append(kwargs) |
| return str(history_path) |
|
|
| with patch("huggingface_hub.hf_hub_download", fake_downloader): |
| store = HuggingFaceDatasetHistoryStore( |
| repo_id="lucas/training-history", |
| token="secret", |
| path_in_repo="history/completed_sessions.json", |
| ) |
| store.load_completed_sessions() |
|
|
| self.assertEqual(download_calls[0]["repo_id"], "lucas/training-history") |
| self.assertEqual(download_calls[0]["filename"], "history/completed_sessions.json") |
| self.assertEqual(download_calls[0]["repo_type"], "dataset") |
| self.assertEqual(download_calls[0]["token"], "secret") |
| self.assertEqual(download_calls[0]["force_download"], True) |
|
|
| def test_save_completed_sessions_creates_private_dataset_and_uploads_file(self): |
| api = _FakeHfApi() |
| store = HuggingFaceDatasetHistoryStore( |
| repo_id="lucas/training-history", |
| token="secret", |
| path_in_repo="history/completed_sessions.json", |
| api=api, |
| ) |
|
|
| store.save_completed_sessions([_completed_session(day_number=4)]) |
|
|
| self.assertEqual(api.created_repos[0]["repo_id"], "lucas/training-history") |
| self.assertEqual(api.created_repos[0]["repo_type"], "dataset") |
| self.assertEqual(api.created_repos[0]["private"], True) |
| self.assertEqual(api.uploads[0]["path_in_repo"], "history/completed_sessions.json") |
| self.assertEqual(api.uploads[0]["repo_type"], "dataset") |
| payload = json.loads(api.uploaded_payload) |
| self.assertEqual(payload["completed_sessions"][0]["day_number"], 4) |
|
|
|
|
| class HistoryStoreFactoryTest(unittest.TestCase): |
| def test_create_history_store_defaults_to_local_json(self): |
| with patch.dict(os.environ, {}, clear=True): |
| store = create_history_store() |
|
|
| self.assertIsInstance(store, JsonHistoryStore) |
|
|
| def test_create_history_store_uses_hf_dataset_when_repo_is_set(self): |
| with patch.dict( |
| os.environ, |
| { |
| "HF_HISTORY_DATASET_REPO": "lucas/training-history", |
| "HF_TOKEN": "secret", |
| "HF_HISTORY_FILE": "history.json", |
| }, |
| clear=True, |
| ): |
| store = create_history_store() |
|
|
| self.assertIsInstance(store, HuggingFaceDatasetHistoryStore) |
| self.assertEqual(store.repo_id, "lucas/training-history") |
| self.assertEqual(store.token, "secret") |
| self.assertEqual(store.path_in_repo, "history.json") |
|
|
|
|
| if __name__ == "__main__": |
| unittest.main() |
|
|