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:
241
tests/test_session_service.py
Normal file
241
tests/test_session_service.py
Normal 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
|
||||
Reference in New Issue
Block a user