Files
tracker-cli/tests/test_session_service.py
Daniel Arroyo 2735562b65 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.
2026-03-23 09:40:46 -03:00

242 lines
7.6 KiB
Python

"""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