Add comprehensive test suite for MVP-1 Personal Tracker CLI

Implements 72 tests covering:
- Model tests (Project, Session, Note, Change)
- ProjectService tests (create, get, list, ensure structure)
- SessionService tests (active session management)
- FileStorage tests (read/write operations)
- Complete flow tests (init -> start -> note -> stop -> show)
- Note consolidation tests

Uses pytest with tmp_path fixtures for isolated testing.
This commit is contained in:
2026-03-23 09:40:46 -03:00
parent 4e67062c99
commit 2735562b65
6 changed files with 1302 additions and 0 deletions

View File

@@ -0,0 +1,241 @@
"""Tests for SessionService."""
import json
from datetime import datetime
from pathlib import Path
from unittest.mock import patch, MagicMock
import pytest
from tracker.models import Session
from tracker.services import (
get_active_session,
set_active_session,
clear_active_session,
get_active_session_path,
validate_no_other_active_session,
)
@pytest.fixture
def mock_active_session_path(tmp_path, monkeypatch):
"""Mock the active session path to use tmp_path."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
return fake_path
class TestSetAndGetActiveSession:
"""Tests for set and get active session functions."""
def test_set_and_get_active_session(self, tmp_path, mock_session, monkeypatch):
"""Test setting and getting an active session."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
retrieved = get_active_session()
assert retrieved is not None
assert retrieved.id == mock_session.id
assert retrieved.project_slug == mock_session.project_slug
assert retrieved.started_at == mock_session.started_at
def test_get_active_session_returns_none_when_no_session(self, tmp_path, monkeypatch):
"""Test that get_active_session returns None when no session exists."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
result = get_active_session()
assert result is None
def test_set_active_session_creates_parent_directories(self, tmp_path, mock_session, monkeypatch):
"""Test that set_active_session creates parent directories if needed."""
fake_path = tmp_path / "subdir" / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
assert fake_path.exists()
def test_active_session_contains_all_fields(self, tmp_path, mock_session, monkeypatch):
"""Test that active session file contains all session fields."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
with open(fake_path, "r") as f:
data = json.load(f)
assert data["id"] == mock_session.id
assert data["project_slug"] == mock_session.project_slug
assert "started_at" in data
assert "work_done" in data
assert data["work_done"] == mock_session.work_done
class TestClearActiveSession:
"""Tests for clear_active_session function."""
def test_clear_active_session_removes_file(self, tmp_path, mock_session, monkeypatch):
"""Test that clear_active_session removes the active session file."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
assert fake_path.exists()
clear_active_session()
assert not fake_path.exists()
def test_clear_active_session_when_no_session(self, tmp_path, monkeypatch):
"""Test that clear_active_session does not error when no session exists."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
clear_active_session()
assert not fake_path.exists()
def test_get_active_session_after_clear(self, tmp_path, mock_session, monkeypatch):
"""Test that get_active_session returns None after clearing."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
clear_active_session()
result = get_active_session()
assert result is None
class TestValidateNoOtherActiveSession:
"""Tests for validate_no_other_active_session function."""
def test_validate_no_other_active_session_returns_true_when_none(self, tmp_path, monkeypatch):
"""Test validation returns True when no active session exists."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
result = validate_no_other_active_session("any-project")
assert result is True
def test_validate_no_other_active_session_returns_true_for_same_project(
self, tmp_path, mock_session, monkeypatch
):
"""Test validation returns True for same project's session."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
result = validate_no_other_active_session(mock_session.project_slug)
assert result is True
def test_validate_no_other_active_session_returns_false_for_different_project(
self, tmp_path, mock_session, monkeypatch
):
"""Test validation returns False for different project's session."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
result = validate_no_other_active_session("different-project")
assert result is False
def test_validate_no_other_active_session_with_no_active_after_clear(
self, tmp_path, mock_session, monkeypatch
):
"""Test validation returns True after clearing session."""
fake_path = tmp_path / ".active_session.json"
def mock_get_active_session_path():
return fake_path
monkeypatch.setattr(
"tracker.services.session_service.get_active_session_path",
mock_get_active_session_path
)
set_active_session(mock_session)
clear_active_session()
result = validate_no_other_active_session("any-project")
assert result is True