feat(taskflow): add core task API, storage persistence, csv export, stats page, and test coverage
This commit is contained in:
146
tests/test_repository_persistence.py
Normal file
146
tests/test_repository_persistence.py
Normal file
@@ -0,0 +1,146 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from uuid import uuid4
|
||||
|
||||
from app.storage import DATA_FORMAT_VERSION, StoredTask
|
||||
from app.storage.repository import JsonFileTaskRepository
|
||||
|
||||
|
||||
def make_task(
|
||||
*,
|
||||
title: str = "Task",
|
||||
started: bool = False,
|
||||
done: bool = False,
|
||||
) -> StoredTask:
|
||||
now = datetime.now(UTC)
|
||||
started_at = now + timedelta(seconds=1) if started else None
|
||||
done_at = now + timedelta(seconds=2) if done else None
|
||||
return StoredTask(
|
||||
id=uuid4(),
|
||||
title=title,
|
||||
created_at=now,
|
||||
started_at=started_at,
|
||||
done_at=done_at,
|
||||
)
|
||||
|
||||
|
||||
def test_replace_all_replaces_empty_state_with_provided_tasks(tmp_path):
|
||||
repo = JsonFileTaskRepository(tmp_path / "tasks.json")
|
||||
task_1 = make_task(title="One")
|
||||
task_2 = make_task(title="Two")
|
||||
|
||||
repo.replace_all([task_1, task_2])
|
||||
|
||||
assert repo.list_tasks() == [task_1, task_2]
|
||||
|
||||
|
||||
def test_replace_all_fully_overwrites_previous_content(tmp_path):
|
||||
repo = JsonFileTaskRepository(tmp_path / "tasks.json")
|
||||
old_task = make_task(title="Old")
|
||||
new_task = make_task(title="New")
|
||||
repo.create_task(old_task)
|
||||
|
||||
repo.replace_all([new_task])
|
||||
|
||||
assert repo.list_tasks() == [new_task]
|
||||
|
||||
|
||||
def test_data_format_version_matches_constant(tmp_path):
|
||||
repo = JsonFileTaskRepository(tmp_path / "tasks.json")
|
||||
|
||||
assert repo.data_format_version == DATA_FORMAT_VERSION
|
||||
|
||||
|
||||
def test_data_format_version_is_stable_across_instances(tmp_path):
|
||||
file_path = tmp_path / "tasks.json"
|
||||
|
||||
repo_1 = JsonFileTaskRepository(file_path)
|
||||
repo_2 = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo_1.data_format_version == repo_2.data_format_version == DATA_FORMAT_VERSION
|
||||
|
||||
|
||||
def test_missing_file_is_created_automatically(tmp_path):
|
||||
file_path = tmp_path / "nested" / "tasks.json"
|
||||
|
||||
repo = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo.list_tasks() == []
|
||||
assert file_path.exists()
|
||||
|
||||
|
||||
def test_existing_valid_file_is_loaded_on_new_instance(tmp_path):
|
||||
file_path = tmp_path / "tasks.json"
|
||||
repo_1 = JsonFileTaskRepository(file_path)
|
||||
task = make_task(title="Persisted")
|
||||
repo_1.create_task(task)
|
||||
|
||||
repo_2 = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo_2.list_tasks() == [task]
|
||||
|
||||
|
||||
def test_parent_directory_is_created_if_missing(tmp_path):
|
||||
file_path = tmp_path / "deep" / "nested" / "data" / "tasks.json"
|
||||
|
||||
repo = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert file_path.parent.exists()
|
||||
assert repo.list_tasks() == []
|
||||
|
||||
|
||||
def test_current_version_payload_loads_as_is(tmp_path):
|
||||
file_path = tmp_path / "tasks.json"
|
||||
repo_1 = JsonFileTaskRepository(file_path)
|
||||
task = make_task(title="Versioned")
|
||||
repo_1.create_task(task)
|
||||
|
||||
repo_2 = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo_2.data_format_version == DATA_FORMAT_VERSION
|
||||
assert repo_2.list_tasks() == [task]
|
||||
|
||||
|
||||
def test_empty_current_version_payload_loads_without_backup(tmp_path):
|
||||
file_path = tmp_path / "tasks.json"
|
||||
repo = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo.list_tasks() == []
|
||||
assert not list(tmp_path.glob("tasks.json.corrupted*"))
|
||||
|
||||
|
||||
def test_persistence_between_repository_instances(tmp_path):
|
||||
file_path = tmp_path / "tasks.json"
|
||||
repo_1 = JsonFileTaskRepository(file_path)
|
||||
task = make_task(title="Cross-session")
|
||||
repo_1.create_task(task)
|
||||
|
||||
repo_2 = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo_2.get_task(task.id) == task
|
||||
|
||||
|
||||
def test_multiple_operations_survive_restart(tmp_path):
|
||||
file_path = tmp_path / "tasks.json"
|
||||
repo_1 = JsonFileTaskRepository(file_path)
|
||||
|
||||
task_1 = make_task(title="First")
|
||||
task_2 = make_task(title="Second")
|
||||
repo_1.create_task(task_1)
|
||||
repo_1.create_task(task_2)
|
||||
repo_1.delete_task(task_1.id)
|
||||
|
||||
updated_task_2 = StoredTask(
|
||||
id=task_2.id,
|
||||
title="Second updated",
|
||||
created_at=task_2.created_at,
|
||||
started_at=datetime.now(UTC),
|
||||
done_at=None,
|
||||
)
|
||||
repo_1.update_task(updated_task_2)
|
||||
|
||||
repo_2 = JsonFileTaskRepository(file_path)
|
||||
|
||||
assert repo_2.list_tasks() == [updated_task_2]
|
||||
|
||||
Reference in New Issue
Block a user