"""Unit tests for database query functions.""" from pathlib import Path import pytest from xer_mcp.db import db @pytest.fixture(autouse=True) def setup_db(): """Initialize and clear database for each test.""" db.initialize() yield db.clear() class TestActivityQueries: """Tests for activity query functions.""" def test_query_activities_with_pagination(self, sample_xer_single_project: Path) -> None: """Should return paginated activity results.""" from xer_mcp.db.loader import load_parsed_data from xer_mcp.db.queries import query_activities from xer_mcp.parser.xer_parser import XerParser parser = XerParser() parsed = parser.parse(sample_xer_single_project) load_parsed_data(parsed, project_id="1001") activities, total = query_activities(limit=2, offset=0) assert len(activities) == 2 assert total == 5 def test_query_activities_filter_by_type(self, sample_xer_single_project: Path) -> None: """Should filter activities by task type.""" from xer_mcp.db.loader import load_parsed_data from xer_mcp.db.queries import query_activities from xer_mcp.parser.xer_parser import XerParser parser = XerParser() parsed = parser.parse(sample_xer_single_project) load_parsed_data(parsed, project_id="1001") activities, total = query_activities(activity_type="TT_Mile") assert total == 2 for act in activities: assert act["task_type"] == "TT_Mile" def test_query_activities_filter_by_date_range(self, sample_xer_single_project: Path) -> None: """Should filter activities by date range.""" from xer_mcp.db.loader import load_parsed_data from xer_mcp.db.queries import query_activities from xer_mcp.parser.xer_parser import XerParser parser = XerParser() parsed = parser.parse(sample_xer_single_project) load_parsed_data(parsed, project_id="1001") # Filter to very narrow range activities, total = query_activities(start_date="2026-01-01", end_date="2026-01-01") # Only activities starting on 2026-01-01 for act in activities: assert "2026-01-01" in act["target_start_date"] def test_query_activities_filter_by_wbs(self, sample_xer_single_project: Path) -> None: """Should filter activities by WBS ID.""" from xer_mcp.db.loader import load_parsed_data from xer_mcp.db.queries import query_activities from xer_mcp.parser.xer_parser import XerParser parser = XerParser() parsed = parser.parse(sample_xer_single_project) load_parsed_data(parsed, project_id="1001") activities, total = query_activities(wbs_id="102") # WBS 102 has 2 activities assert total == 2 def test_get_activity_by_id(self, sample_xer_single_project: Path) -> None: """Should return single activity by ID.""" from xer_mcp.db.loader import load_parsed_data from xer_mcp.db.queries import get_activity_by_id from xer_mcp.parser.xer_parser import XerParser parser = XerParser() parsed = parser.parse(sample_xer_single_project) load_parsed_data(parsed, project_id="1001") activity = get_activity_by_id("2002") assert activity is not None assert activity["task_code"] == "A1010" def test_get_activity_by_id_not_found(self, sample_xer_single_project: Path) -> None: """Should return None for non-existent activity.""" from xer_mcp.db.loader import load_parsed_data from xer_mcp.db.queries import get_activity_by_id from xer_mcp.parser.xer_parser import XerParser parser = XerParser() parsed = parser.parse(sample_xer_single_project) load_parsed_data(parsed, project_id="1001") activity = get_activity_by_id("nonexistent") assert activity is None class TestDrivingRelationship: """Tests for driving relationship computation.""" def test_is_driving_relationship_fs_driving(self) -> None: """FS relationship is driving when pred_end + lag = succ_start.""" from xer_mcp.db.queries import is_driving_relationship # Pred ends at 2026-01-08T15:00, succ starts at 2026-01-09T07:00 # With 0 lag and overnight gap, this is driving result = is_driving_relationship( pred_early_end="2026-01-08T15:00:00", succ_early_start="2026-01-09T07:00:00", lag_hours=0.0, pred_type="FS", ) assert result is True def test_is_driving_relationship_fs_not_driving(self) -> None: """FS relationship is not driving when there's float.""" from xer_mcp.db.queries import is_driving_relationship # Pred ends much earlier than succ starts (has float) result = is_driving_relationship( pred_early_end="2026-01-01T15:00:00", succ_early_start="2026-01-10T07:00:00", lag_hours=0.0, pred_type="FS", ) assert result is False def test_is_driving_relationship_with_lag(self) -> None: """FS relationship with lag is driving when pred_end + lag = succ_start.""" from xer_mcp.db.queries import is_driving_relationship # Pred ends at 2026-01-08T15:00, 16hr lag, succ starts at 2026-01-09T07:00 # 15:00 + 16hrs = next day 07:00 (exactly matches) result = is_driving_relationship( pred_early_end="2026-01-08T15:00:00", succ_early_start="2026-01-09T07:00:00", lag_hours=16.0, pred_type="FS", ) assert result is True def test_is_driving_relationship_missing_dates(self) -> None: """Relationship is not driving when dates are missing.""" from xer_mcp.db.queries import is_driving_relationship result = is_driving_relationship( pred_early_end=None, succ_early_start="2026-01-09T07:00:00", lag_hours=0.0, pred_type="FS", ) assert result is False result = is_driving_relationship( pred_early_end="2026-01-08T15:00:00", succ_early_start=None, lag_hours=0.0, pred_type="FS", ) assert result is False