""" Tests for the GraphManager class. """ import os import pytest import pandas as pd import tkinter as tk from tkinter import ttk from unittest.mock import Mock, patch, MagicMock import matplotlib.pyplot as plt import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) from src.graph_manager import GraphManager class TestGraphManager: """Test cases for the GraphManager class.""" @pytest.fixture def root_window(self): """Create a root window for testing.""" root = tk.Tk() yield root root.destroy() @pytest.fixture def parent_frame(self, root_window): """Create a parent frame for testing.""" frame = ttk.LabelFrame(root_window, text="Test Frame") frame.pack() return frame def test_init(self, parent_frame): """Test GraphManager initialization.""" gm = GraphManager(parent_frame) assert gm.parent_frame == parent_frame assert isinstance(gm.toggle_vars, dict) assert "depression" in gm.toggle_vars assert "anxiety" in gm.toggle_vars assert "sleep" in gm.toggle_vars assert "appetite" in gm.toggle_vars # Check that all toggles are initially True for var in gm.toggle_vars.values(): assert var.get() is True def test_toggle_controls_creation(self, parent_frame): """Test that toggle controls are created properly.""" gm = GraphManager(parent_frame) # Check that control frame exists assert hasattr(gm, 'control_frame') assert isinstance(gm.control_frame, ttk.Frame) # Check that toggle variables exist expected_toggles = ["depression", "anxiety", "sleep", "appetite"] for toggle in expected_toggles: assert toggle in gm.toggle_vars assert isinstance(gm.toggle_vars[toggle], tk.BooleanVar) def test_graph_frame_creation(self, parent_frame): """Test that graph frame is created properly.""" gm = GraphManager(parent_frame) assert hasattr(gm, 'graph_frame') assert isinstance(gm.graph_frame, ttk.Frame) @patch('matplotlib.pyplot.subplots') def test_matplotlib_initialization(self, mock_subplots, parent_frame): """Test matplotlib figure and canvas initialization.""" mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas gm = GraphManager(parent_frame) assert gm.fig == mock_fig assert gm.ax == mock_ax assert gm.canvas == mock_canvas mock_canvas_class.assert_called_once_with(figure=mock_fig, master=gm.graph_frame) def test_update_graph_empty_dataframe(self, parent_frame): """Test updating graph with empty DataFrame.""" with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg'): gm = GraphManager(parent_frame) # Test with empty DataFrame empty_df = pd.DataFrame() gm.update_graph(empty_df) # Verify ax.clear() was called mock_ax.clear.assert_called() def test_update_graph_with_data(self, parent_frame, sample_dataframe): """Test updating graph with valid data.""" with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas gm = GraphManager(parent_frame) gm.update_graph(sample_dataframe) # Verify methods were called mock_ax.clear.assert_called() mock_canvas.draw.assert_called() def test_toggle_functionality(self, parent_frame, sample_dataframe): """Test that toggle variables affect graph display.""" with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas gm = GraphManager(parent_frame) # Turn off depression toggle gm.toggle_vars["depression"].set(False) gm.update_graph(sample_dataframe) # The graph should still update (specific plotting logic would need more detailed testing) mock_ax.clear.assert_called() mock_canvas.draw.assert_called() def test_close_method(self, parent_frame): """Test the close method.""" with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas with patch('matplotlib.pyplot.close') as mock_plt_close: gm = GraphManager(parent_frame) gm.close() mock_plt_close.assert_called_once_with(mock_fig) def test_date_parsing_in_update_graph(self, parent_frame): """Test that date parsing works correctly in update_graph.""" # Create a DataFrame with date strings df_with_dates = pd.DataFrame({ 'date': ['2024-01-01', '2024-01-02', '2024-01-03'], 'depression': [3, 2, 4], 'anxiety': [2, 3, 1], 'sleep': [4, 3, 5], 'appetite': [3, 4, 2], 'bupropion': [1, 1, 0], 'hydroxyzine': [0, 1, 0], 'gabapentin': [2, 2, 1], 'propranolol': [1, 0, 1], 'note': ['Test note 1', 'Test note 2', ''] }) with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas with patch('pandas.to_datetime') as mock_to_datetime: gm = GraphManager(parent_frame) gm.update_graph(df_with_dates) # Verify pandas.to_datetime was called mock_to_datetime.assert_called() @patch('matplotlib.pyplot.subplots') def test_exception_handling_in_update_graph(self, mock_subplots, parent_frame, sample_dataframe): """Test exception handling in update_graph method.""" mock_fig = Mock() mock_ax = Mock() mock_ax.plot.side_effect = Exception("Plot error") mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas gm = GraphManager(parent_frame) # This should not raise an exception, but handle it gracefully try: gm.update_graph(sample_dataframe) except Exception as e: pytest.fail(f"update_graph should handle exceptions gracefully, but raised: {e}") def test_grid_configuration(self, parent_frame): """Test that grid configuration is set up correctly.""" gm = GraphManager(parent_frame) # The parent frame should have grid configuration # Note: In a real test, you might need to check grid_info() or similar # This is a basic structure test assert hasattr(gm, 'parent_frame') assert hasattr(gm, 'control_frame') assert hasattr(gm, 'graph_frame') def test_canvas_widget_packing(self, parent_frame): """Test that canvas widget is properly packed.""" with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas.get_tk_widget.return_value = Mock() mock_canvas_class.return_value = mock_canvas gm = GraphManager(parent_frame) # Verify get_tk_widget was called (for packing) mock_canvas.get_tk_widget.assert_called() def test_multiple_toggle_combinations(self, parent_frame, sample_dataframe): """Test various combinations of toggle states.""" with patch('matplotlib.pyplot.subplots') as mock_subplots: mock_fig = Mock() mock_ax = Mock() mock_subplots.return_value = (mock_fig, mock_ax) with patch('graph_manager.FigureCanvasTkAgg') as mock_canvas_class: mock_canvas = Mock() mock_canvas_class.return_value = mock_canvas gm = GraphManager(parent_frame) # Test all toggles off for toggle in gm.toggle_vars.values(): toggle.set(False) gm.update_graph(sample_dataframe) # Test mixed toggles gm.toggle_vars["depression"].set(True) gm.toggle_vars["anxiety"].set(False) gm.update_graph(sample_dataframe) # Verify the graph was updated in each case assert mock_ax.clear.call_count >= 2 assert mock_canvas.draw.call_count >= 2