Files
thechart/tests/test_ui_manager.py
2025-07-30 16:02:26 -07:00

294 lines
11 KiB
Python

"""
Tests for the UIManager class.
"""
import os
import pytest
import tkinter as tk
from tkinter import ttk
from unittest.mock import Mock, patch
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
from src.ui_manager import UIManager
class TestUIManager:
"""Test cases for the UIManager class."""
@pytest.fixture
def root_window(self):
"""Create a root window for testing."""
root = tk.Tk()
yield root
root.destroy()
@pytest.fixture
def ui_manager(self, root_window, mock_logger):
"""Create a UIManager instance for testing."""
return UIManager(root_window, mock_logger)
def test_init(self, root_window, mock_logger):
"""Test UIManager initialization."""
ui = UIManager(root_window, mock_logger)
assert ui.root == root_window
assert ui.logger == mock_logger
@patch('os.path.exists')
@patch('PIL.Image.open')
def test_setup_application_icon_success(self, mock_image_open, mock_exists, ui_manager):
"""Test successful icon setup."""
mock_exists.return_value = True
mock_image = Mock()
mock_image.resize.return_value = mock_image
mock_image_open.return_value = mock_image
with patch('PIL.ImageTk.PhotoImage') as mock_photo:
mock_photo_instance = Mock()
mock_photo.return_value = mock_photo_instance
with patch.object(ui_manager.root, 'iconphoto') as mock_iconphoto, \
patch.object(ui_manager.root, 'wm_iconphoto') as mock_wm_iconphoto:
result = ui_manager.setup_application_icon("test_icon.png")
assert result is True
mock_image_open.assert_called_once_with("test_icon.png")
mock_image.resize.assert_called_once()
ui_manager.logger.info.assert_called_with("Trying to load icon from: test_icon.png")
@patch('os.path.exists')
def test_setup_application_icon_file_not_found(self, mock_exists, ui_manager):
"""Test icon setup when file is not found."""
mock_exists.return_value = False
result = ui_manager.setup_application_icon("nonexistent_icon.png")
assert result is False
ui_manager.logger.warning.assert_called_with("Icon file not found at nonexistent_icon.png")
@patch('os.path.exists')
@patch('PIL.Image.open')
def test_setup_application_icon_exception(self, mock_image_open, mock_exists, ui_manager):
"""Test icon setup with exception."""
mock_exists.return_value = True
mock_image_open.side_effect = Exception("Test error")
result = ui_manager.setup_application_icon("test_icon.png")
assert result is False
ui_manager.logger.error.assert_called_with("Error setting icon: Test error")
@patch('sys._MEIPASS', '/test/bundle/path', create=True)
@patch('os.path.exists')
@patch('PIL.Image.open')
def test_setup_application_icon_pyinstaller_bundle(self, mock_image_open, mock_exists, ui_manager):
"""Test icon setup in PyInstaller bundle."""
# Mock exists to return False for original path, True for bundle path
def mock_exists_side_effect(path):
if 'test_icon.png' in path and '/test/bundle/path' in path:
return True
return False
mock_exists.side_effect = mock_exists_side_effect
mock_image = Mock()
mock_image.resize.return_value = mock_image
mock_image_open.return_value = mock_image
with patch('PIL.ImageTk.PhotoImage') as mock_photo:
mock_photo_instance = Mock()
mock_photo.return_value = mock_photo_instance
with patch.object(ui_manager.root, 'iconphoto') as mock_iconphoto, \
patch.object(ui_manager.root, 'wm_iconphoto') as mock_wm_iconphoto:
result = ui_manager.setup_application_icon("test_icon.png")
assert result is True
ui_manager.logger.info.assert_called_with("Found icon in PyInstaller bundle: /test/bundle/path/test_icon.png")
def test_create_graph_frame(self, ui_manager, root_window):
"""Test creation of graph frame."""
main_frame = ttk.Frame(root_window)
graph_frame = ui_manager.create_graph_frame(main_frame)
assert isinstance(graph_frame, ttk.LabelFrame)
assert graph_frame.winfo_parent() == str(main_frame)
def test_create_input_frame(self, ui_manager, root_window):
"""Test creation of input frame."""
main_frame = ttk.Frame(root_window)
input_ui = ui_manager.create_input_frame(main_frame)
assert isinstance(input_ui, dict)
assert "frame" in input_ui
assert "symptom_vars" in input_ui
assert "medicine_vars" in input_ui
assert "note_var" in input_ui
assert "date_var" in input_ui
assert isinstance(input_ui["frame"], ttk.LabelFrame)
assert isinstance(input_ui["symptom_vars"], dict)
assert isinstance(input_ui["medicine_vars"], dict)
assert isinstance(input_ui["note_var"], tk.StringVar)
assert isinstance(input_ui["date_var"], tk.StringVar)
def test_create_input_frame_symptom_vars(self, ui_manager, root_window):
"""Test that symptom variables are created correctly."""
main_frame = ttk.Frame(root_window)
input_ui = ui_manager.create_input_frame(main_frame)
symptom_vars = input_ui["symptom_vars"]
expected_symptoms = ["depression", "anxiety", "sleep", "appetite"]
for symptom in expected_symptoms:
assert symptom in symptom_vars
assert isinstance(symptom_vars[symptom], tk.IntVar)
def test_create_input_frame_medicine_vars(self, ui_manager, root_window):
"""Test that medicine variables are created correctly."""
main_frame = ttk.Frame(root_window)
input_ui = ui_manager.create_input_frame(main_frame)
medicine_vars = input_ui["medicine_vars"]
expected_medicines = ["bupropion", "hydroxyzine", "gabapentin", "propranolol", "quetiapine"]
for medicine in expected_medicines:
assert medicine in medicine_vars
assert isinstance(medicine_vars[medicine], tuple)
assert len(medicine_vars[medicine]) == 2 # IntVar and display text
assert isinstance(medicine_vars[medicine][0], tk.IntVar)
assert isinstance(medicine_vars[medicine][1], str)
@patch('src.ui_manager.datetime')
def test_create_input_frame_default_date(self, mock_datetime, ui_manager, root_window):
"""Test that default date is set to today."""
mock_datetime.now.return_value.strftime.return_value = "07/30/2025"
main_frame = ttk.Frame(root_window)
input_ui = ui_manager.create_input_frame(main_frame)
# The actual date will be today's date, not the mocked value
# because the datetime import is within the function
assert input_ui["date_var"].get() == "07/30/2025"
def test_create_table_frame(self, ui_manager, root_window):
"""Test creation of table frame."""
main_frame = ttk.Frame(root_window)
table_ui = ui_manager.create_table_frame(main_frame)
assert isinstance(table_ui, dict)
assert "tree" in table_ui
assert isinstance(table_ui["tree"], ttk.Treeview)
def test_create_table_frame_columns(self, ui_manager, root_window):
"""Test that table columns are set up correctly."""
main_frame = ttk.Frame(root_window)
table_ui = ui_manager.create_table_frame(main_frame)
tree = table_ui["tree"]
expected_columns = [
"Date", "Depression", "Anxiety", "Sleep", "Appetite",
"Bupropion", "Hydroxyzine", "Gabapentin", "Propranolol", "Quetiapine", "Note"
]
# Check that columns are configured
assert tree["columns"] == tuple(expected_columns)
def test_add_buttons(self, ui_manager, root_window):
"""Test adding buttons to a frame."""
frame = ttk.Frame(root_window)
buttons_config = [
{"text": "Test Button 1", "command": lambda: None},
{"text": "Test Button 2", "command": lambda: None, "fill": "x"},
]
ui_manager.add_buttons(frame, buttons_config)
# Check that a button frame was added
children = frame.winfo_children()
assert len(children) >= 1 # At least the button frame should be added
def test_create_edit_window(self, ui_manager):
"""Test creation of edit window."""
values = ("2024-01-01", "3", "2", "4", "3", "1", "0", "2", "1", "Test note")
callbacks = {
"save": lambda win, *args: None,
"delete": lambda win: None
}
edit_window = ui_manager.create_edit_window(values, callbacks)
assert isinstance(edit_window, tk.Toplevel)
assert edit_window.title() == "Edit Entry"
def test_create_edit_window_widgets(self, ui_manager):
"""Test that edit window contains expected widgets."""
values = ("2024-01-01", "3", "2", "4", "3", "1", "0", "2", "1", "Test note")
callbacks = {
"save": lambda win, *args: None,
"delete": lambda win: None
}
edit_window = ui_manager.create_edit_window(values, callbacks)
# Check that window has children (widgets)
children = edit_window.winfo_children()
assert len(children) > 0
def test_create_edit_window_initial_values(self, ui_manager):
"""Test that edit window is populated with initial values."""
values = ("2024-01-01", "3", "2", "4", "3", "1", "0", "2", "1", "Test note")
callbacks = {
"save": lambda win, *args: None,
"delete": lambda win: None
}
edit_window = ui_manager.create_edit_window(values, callbacks)
# The window should be created successfully
assert edit_window is not None
# More detailed testing would require examining the internal widgets
def test_frame_positioning(self, ui_manager, root_window):
"""Test that frames are positioned correctly."""
main_frame = ttk.Frame(root_window)
# Create multiple frames
graph_frame = ui_manager.create_graph_frame(main_frame)
input_ui = ui_manager.create_input_frame(main_frame)
table_ui = ui_manager.create_table_frame(main_frame)
# All frames should be created successfully
assert graph_frame is not None
assert input_ui["frame"] is not None
assert table_ui["tree"] is not None
def test_widget_configuration(self, ui_manager, root_window):
"""Test that widgets are configured with appropriate properties."""
main_frame = ttk.Frame(root_window)
input_ui = ui_manager.create_input_frame(main_frame)
# Check that variables have default values
for var in input_ui["symptom_vars"].values():
assert var.get() == 0
for medicine_data in input_ui["medicine_vars"].values():
assert medicine_data[0].get() == 0 # IntVar should be 0
@patch('tkinter.messagebox.showerror')
def test_error_handling_in_setup_application_icon(self, mock_showerror, ui_manager):
"""Test error handling in setup_application_icon method."""
with patch('PIL.Image.open') as mock_open:
mock_open.side_effect = Exception("Image error")
result = ui_manager.setup_application_icon("test.png")
assert result is False
ui_manager.logger.error.assert_called()