Files
tidal-dl/tests/test_settings_ui.py
T

389 lines
14 KiB
Python
Raw Normal View History

"""Tests for the refactored settings dialog UI."""
from pathlib import Path
from unittest.mock import Mock, patch
import pytest
from PySide6 import QtCore, QtWidgets
from tidal_dl_ng.dialog import DialogPreferences
from tidal_dl_ng.ui.dialog_settings import Ui_DialogSettings
@pytest.fixture
def qapp():
"""Create QApplication instance for tests."""
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication([])
yield app
# Cleanup is handled by pytest-qt if available, otherwise by QApplication
class TestUiDialogSettings:
"""Test the generated UI class."""
def test_ui_setupui_creates_all_widgets(self, qapp):
"""Test that setupUi creates all expected widgets."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
# Check main structural widgets
assert hasattr(ui, "lw_categories")
assert hasattr(ui, "sw_categories")
assert hasattr(ui, "bb_dialog")
# Check pages exist
assert hasattr(ui, "page_flags")
assert hasattr(ui, "page_quality")
assert hasattr(ui, "page_numbers")
assert hasattr(ui, "page_paths")
def test_ui_list_widget_properties(self, qapp):
"""Test that the categories list widget has correct properties."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
assert ui.lw_categories is not None
assert isinstance(ui.lw_categories, QtWidgets.QListWidget)
assert ui.lw_categories.minimumWidth() == 150
assert ui.lw_categories.maximumWidth() == 200
def test_ui_stacked_widget_has_all_pages(self, qapp):
"""Test that the stacked widget contains all 4 pages."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
assert ui.sw_categories is not None
assert isinstance(ui.sw_categories, QtWidgets.QStackedWidget)
assert ui.sw_categories.count() == 5
def test_ui_flags_page_widgets(self, qapp):
"""Test that the Flags page contains all expected checkboxes."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
# Test flags group box exists
assert hasattr(ui, "gb_flags")
assert ui.gb_flags is not None
# Test all checkboxes exist
checkboxes = [
"cb_video_download",
"cb_video_convert_mp4",
"cb_lyrics_embed",
"cb_lyrics_file",
"cb_download_delay",
"cb_extract_flac",
"cb_metadata_cover_embed",
"cb_cover_album_file",
"cb_skip_existing",
"cb_symlink_to_track",
"cb_playlist_create",
"cb_mark_explicit",
"cb_use_primary_album_artist",
"cb_download_dolby_atmos",
]
for cb_name in checkboxes:
assert hasattr(ui, cb_name), f"Missing checkbox: {cb_name}"
checkbox = getattr(ui, cb_name)
assert isinstance(checkbox, QtWidgets.QCheckBox)
def test_ui_quality_page_widgets(self, qapp):
"""Test that the Quality page contains all expected combo boxes."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
# Test choices group box exists
assert hasattr(ui, "gb_choices")
assert ui.gb_choices is not None
# Test all combo boxes exist
combos = [
"c_quality_audio",
"c_quality_video",
"c_metadata_cover_dimension",
]
for combo_name in combos:
assert hasattr(ui, combo_name), f"Missing combo box: {combo_name}"
combo = getattr(ui, combo_name)
assert isinstance(combo, QtWidgets.QComboBox)
def test_ui_numbers_page_widgets(self, qapp):
"""Test that the Numbers page contains all expected spin boxes."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
# Test numbers group box exists
assert hasattr(ui, "gb_numbers")
assert ui.gb_numbers is not None
# Test all spin boxes exist
spinboxes = [
"sb_album_track_num_pad_min",
"sb_downloads_concurrent_max",
]
for sb_name in spinboxes:
assert hasattr(ui, sb_name), f"Missing spin box: {sb_name}"
spinbox = getattr(ui, sb_name)
assert isinstance(spinbox, QtWidgets.QSpinBox)
def test_ui_paths_page_widgets(self, qapp):
"""Test that the Paths page contains all expected line edits and buttons."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
# Test path group box exists
assert hasattr(ui, "gb_path")
assert ui.gb_path is not None
# Test all line edits exist
line_edits = [
"le_download_base_path",
"le_format_track",
"le_format_video",
"le_format_album",
"le_format_playlist",
"le_format_mix",
"le_path_binary_ffmpeg",
]
for le_name in line_edits:
assert hasattr(ui, le_name), f"Missing line edit: {le_name}"
line_edit = getattr(ui, le_name)
assert isinstance(line_edit, QtWidgets.QLineEdit)
# Test buttons exist
assert hasattr(ui, "pb_download_base_path")
assert hasattr(ui, "pb_path_binary_ffmpeg")
def test_ui_dialog_button_box(self, qapp):
"""Test that the dialog has OK and Cancel buttons."""
dialog = QtWidgets.QDialog()
ui = Ui_DialogSettings()
ui.setupUi(dialog)
assert ui.bb_dialog is not None
assert isinstance(ui.bb_dialog, QtWidgets.QDialogButtonBox)
# Check that standard buttons include OK and Cancel
buttons = ui.bb_dialog.standardButtons()
assert QtWidgets.QDialogButtonBox.StandardButton.Ok in buttons
assert QtWidgets.QDialogButtonBox.StandardButton.Cancel in buttons
class TestDialogPreferencesCategories:
"""Test the DialogPreferences category initialization and navigation."""
@pytest.fixture
def mock_settings(self):
"""Create a mock Settings object."""
settings = Mock()
settings.data = Mock()
# Set default values for all parameters
settings.data.lyrics_embed = False
settings.data.lyrics_file = False
settings.data.use_primary_album_artist = False
settings.data.video_download = False
settings.data.download_dolby_atmos = False
settings.data.download_delay = False
settings.data.video_convert_mp4 = False
settings.data.extract_flac = False
settings.data.metadata_cover_embed = False
settings.data.mark_explicit = False
settings.data.cover_album_file = False
settings.data.skip_existing = False
settings.data.symlink_to_track = False
settings.data.playlist_create = False
settings.data.download_base_path = str(Path.home())
settings.data.format_album = "{artist}/{album}"
settings.data.format_playlist = "Playlists/{name}"
settings.data.format_mix = "Mixes/{name}"
settings.data.format_track = "{title}"
settings.data.format_video = "{title}"
settings.data.path_binary_ffmpeg = "ffmpeg"
settings.data.album_track_num_pad_min = 2
settings.data.downloads_concurrent_max = 3
settings.data.quality_audio = Mock()
settings.data.quality_video = Mock()
settings.data.metadata_cover_dimension = Mock()
return settings
@patch.object(DialogPreferences, "exec")
def test_init_categories_adds_all_items(self, mock_exec, mock_settings, qapp):
"""Test that _init_categories adds all 4 categories to the list."""
settings_save = QtCore.Signal()
with patch.object(DialogPreferences, "gui_populate"):
dialog = DialogPreferences(mock_settings, settings_save)
# Check that all categories were added
assert dialog.ui.lw_categories.count() == 5
assert dialog.ui.lw_categories.item(0).text() == "Flags"
assert dialog.ui.lw_categories.item(1).text() == "Quality"
assert dialog.ui.lw_categories.item(2).text() == "Numbers"
assert dialog.ui.lw_categories.item(3).text() == "Paths & Formats"
assert dialog.ui.lw_categories.item(4).text() == "Delimiters"
@patch.object(DialogPreferences, "exec")
def test_init_categories_sets_first_selected(self, mock_exec, mock_settings, qapp):
"""Test that the first category is selected by default."""
settings_save = QtCore.Signal()
with patch.object(DialogPreferences, "gui_populate"):
dialog = DialogPreferences(mock_settings, settings_save)
# Check that first item is selected
assert dialog.ui.lw_categories.currentRow() == 0
@patch.object(DialogPreferences, "exec")
def test_category_change_switches_page(self, mock_exec, mock_settings, qapp):
"""Test that changing category switches the stacked widget page."""
settings_save = QtCore.Signal()
with patch.object(DialogPreferences, "gui_populate"):
dialog = DialogPreferences(mock_settings, settings_save)
# Initially on page 0
assert dialog.ui.sw_categories.currentIndex() == 0
# Change to category 1 (Quality)
dialog.ui.lw_categories.setCurrentRow(1)
assert dialog.ui.sw_categories.currentIndex() == 1
# Change to category 2 (Numbers)
dialog.ui.lw_categories.setCurrentRow(2)
assert dialog.ui.sw_categories.currentIndex() == 2
# Change to category 3 (Paths & Formats)
dialog.ui.lw_categories.setCurrentRow(3)
assert dialog.ui.sw_categories.currentIndex() == 3
# Back to category 0 (Flags)
dialog.ui.lw_categories.setCurrentRow(0)
assert dialog.ui.sw_categories.currentIndex() == 0
@patch.object(DialogPreferences, "exec")
def test_on_category_changed_method(self, mock_exec, mock_settings, qapp):
"""Test that _on_category_changed method works correctly."""
settings_save = QtCore.Signal()
with patch.object(DialogPreferences, "gui_populate"):
dialog = DialogPreferences(mock_settings, settings_save)
# Test method directly
dialog._on_category_changed(0)
assert dialog.ui.sw_categories.currentIndex() == 0
dialog._on_category_changed(1)
assert dialog.ui.sw_categories.currentIndex() == 1
dialog._on_category_changed(2)
assert dialog.ui.sw_categories.currentIndex() == 2
dialog._on_category_changed(3)
assert dialog.ui.sw_categories.currentIndex() == 3
class TestDialogPreferencesIntegration:
"""Integration tests for the complete dialog functionality."""
@pytest.fixture
def mock_settings(self):
"""Create a mock Settings object with all required attributes."""
settings = Mock()
settings.data = Mock()
# Set all required attributes
for attr in [
"lyrics_embed",
"lyrics_file",
"use_primary_album_artist",
"video_download",
"download_dolby_atmos",
"download_delay",
"video_convert_mp4",
"extract_flac",
"metadata_cover_embed",
"mark_explicit",
"cover_album_file",
"skip_existing",
"symlink_to_track",
"playlist_create",
]:
setattr(settings.data, attr, False)
for attr in [
"download_base_path",
"format_album",
"format_playlist",
"format_mix",
"format_track",
"format_video",
"path_binary_ffmpeg",
]:
setattr(settings.data, attr, f"/test/{attr}")
settings.data.album_track_num_pad_min = 2
settings.data.downloads_concurrent_max = 3
settings.data.quality_audio = Mock()
settings.data.quality_video = Mock()
settings.data.metadata_cover_dimension = Mock()
return settings
@patch.object(DialogPreferences, "exec")
def test_dialog_structure_is_correct(self, mock_exec, mock_settings, qapp):
"""Test that the complete dialog structure is correctly set up."""
settings_save = QtCore.Signal()
with patch.object(DialogPreferences, "gui_populate"):
dialog = DialogPreferences(mock_settings, settings_save)
# Check dialog has UI
assert hasattr(dialog, "ui")
assert isinstance(dialog.ui, Ui_DialogSettings)
# Check categories list is populated
assert dialog.ui.lw_categories.count() == 5
# Check stacked widget has 5 pages
assert dialog.ui.sw_categories.count() == 5
# Check all pages are accessible
for i in range(5):
page = dialog.ui.sw_categories.widget(i)
assert page is not None
@patch.object(DialogPreferences, "exec")
def test_navigation_between_all_categories(self, mock_exec, mock_settings, qapp):
"""Test that navigation works correctly between all categories."""
settings_save = QtCore.Signal()
with patch.object(DialogPreferences, "gui_populate"):
dialog = DialogPreferences(mock_settings, settings_save)
# Navigate through all categories
for i in range(4):
dialog.ui.lw_categories.setCurrentRow(i)
assert dialog.ui.sw_categories.currentIndex() == i
# Check that the correct page is visible
current_widget = dialog.ui.sw_categories.currentWidget()
assert current_widget is not None