"""Tests for the sync dashboard TUI.""" import pytest from unittest.mock import MagicMock, patch from datetime import datetime from src.cli.sync_dashboard import ( SyncDashboard, SyncProgressTracker, TaskStatus, TaskListItem, get_dashboard, get_progress_tracker, ) class TestSyncProgressTracker: """Tests for the SyncProgressTracker class.""" def test_init(self): """Test tracker initialization.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) assert tracker.dashboard == mock_dashboard def test_start_task(self): """Test starting a new task.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.start_task("inbox", 100) mock_dashboard.start_task.assert_called_once_with("inbox", 100) def test_start_task_default_total(self): """Test starting a task with default total.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.start_task("calendar") mock_dashboard.start_task.assert_called_once_with("calendar", 100) def test_update_task(self): """Test updating task progress.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.update_task("inbox", 50, "Processing...") mock_dashboard.update_task.assert_called_once_with("inbox", 50, "Processing...") def test_update_task_without_message(self): """Test updating task without message.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.update_task("inbox", 75) mock_dashboard.update_task.assert_called_once_with("inbox", 75, "") def test_complete_task(self): """Test completing a task.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.complete_task("inbox", "Done!") mock_dashboard.complete_task.assert_called_once_with("inbox", "Done!") def test_complete_task_no_message(self): """Test completing a task without a message.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.complete_task("inbox") mock_dashboard.complete_task.assert_called_once_with("inbox", "") def test_error_task(self): """Test marking a task as failed.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.error_task("inbox", "Connection failed") mock_dashboard.error_task.assert_called_once_with("inbox", "Connection failed") def test_skip_task(self): """Test skipping a task.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.skip_task("sweep", "Not needed") mock_dashboard.skip_task.assert_called_once_with("sweep", "Not needed") def test_skip_task_no_reason(self): """Test skipping a task without a reason.""" mock_dashboard = MagicMock() tracker = SyncProgressTracker(mock_dashboard) tracker.skip_task("sweep") mock_dashboard.skip_task.assert_called_once_with("sweep", "") class TestTaskListItem: """Tests for the TaskListItem class.""" def test_init(self): """Test TaskListItem initialization.""" item = TaskListItem("inbox", "Inbox Sync") assert item.task_id == "inbox" assert item.task_name == "Inbox Sync" assert item.status == TaskStatus.PENDING assert item.progress == 0 assert item.total == 100 def test_get_status_icon_pending(self): """Test status icon for pending.""" item = TaskListItem("inbox", "Inbox Sync") assert item._get_status_icon() == "○" def test_get_status_icon_running(self): """Test status icon for running (animated spinner).""" from src.cli.sync_dashboard import SPINNER_FRAMES item = TaskListItem("inbox", "Inbox Sync") item.status = TaskStatus.RUNNING # Running uses spinner frames, starts at frame 0 assert item._get_status_icon() == SPINNER_FRAMES[0] def test_get_status_icon_completed(self): """Test status icon for completed.""" item = TaskListItem("inbox", "Inbox Sync") item.status = TaskStatus.COMPLETED assert item._get_status_icon() == "✓" def test_get_status_icon_error(self): """Test status icon for error.""" item = TaskListItem("inbox", "Inbox Sync") item.status = TaskStatus.ERROR assert item._get_status_icon() == "✗" def test_get_status_color_pending(self): """Test status color for pending.""" item = TaskListItem("inbox", "Inbox Sync") assert item._get_status_color() == "dim" def test_get_status_color_running(self): """Test status color for running.""" item = TaskListItem("inbox", "Inbox Sync") item.status = TaskStatus.RUNNING assert item._get_status_color() == "cyan" def test_get_status_color_completed(self): """Test status color for completed.""" item = TaskListItem("inbox", "Inbox Sync") item.status = TaskStatus.COMPLETED assert item._get_status_color() == "bright_white" def test_get_status_color_error(self): """Test status color for error.""" item = TaskListItem("inbox", "Inbox Sync") item.status = TaskStatus.ERROR assert item._get_status_color() == "red" class TestTaskStatus: """Tests for the TaskStatus constants.""" def test_status_values(self): """Test TaskStatus values.""" assert TaskStatus.PENDING == "pending" assert TaskStatus.RUNNING == "running" assert TaskStatus.COMPLETED == "completed" assert TaskStatus.ERROR == "error" class TestSyncDashboard: """Tests for the SyncDashboard class.""" def test_bindings_defined(self): """Test that key bindings are defined.""" assert len(SyncDashboard.BINDINGS) > 0 # Bindings use the Binding class which has a key attribute binding_keys = [b.key for b in SyncDashboard.BINDINGS] # type: ignore assert "q" in binding_keys assert "r" in binding_keys assert "s" in binding_keys # Sync now assert "+" in binding_keys # Increase interval assert "-" in binding_keys # Decrease interval assert "ctrl+c" in binding_keys assert "up" in binding_keys assert "down" in binding_keys def test_css_defined(self): """Test that CSS is defined.""" assert SyncDashboard.CSS is not None assert len(SyncDashboard.CSS) > 0 assert ".dashboard" in SyncDashboard.CSS assert ".sidebar" in SyncDashboard.CSS assert ".main-panel" in SyncDashboard.CSS def test_reactive_selected_task(self): """Test selected_task reactive attribute is defined.""" assert hasattr(SyncDashboard, "selected_task") class TestGlobalInstances: """Tests for global dashboard instances.""" def test_get_dashboard_initial(self): """Test get_dashboard returns None initially.""" # Reset global state import src.cli.sync_dashboard as dashboard_module dashboard_module._dashboard_instance = None result = get_dashboard() assert result is None def test_get_progress_tracker_initial(self): """Test get_progress_tracker returns None initially.""" # Reset global state import src.cli.sync_dashboard as dashboard_module dashboard_module._progress_tracker = None result = get_progress_tracker() assert result is None