| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- """
- Tests for MainWindow UI component.
- """
- import pytest
- # Skip tests if PyQt6 is not installed
- pytest.importorskip("PyQt6")
- from pathlib import Path
- from datetime import datetime
- from PyQt6.QtWidgets import QApplication
- from PyQt6.QtCore import Qt
- from PyQt6.QtTest import QTest
- from src.ui.models import FileItem, FileStatus
- from src.ui.main_window import MainWindow
- @pytest.fixture
- def app(qtbot):
- """Create QApplication fixture."""
- test_app = QApplication.instance()
- if test_app is None:
- test_app = QApplication([])
- yield test_app
- @pytest.fixture
- def main_window(app, qtbot):
- """Create MainWindow fixture."""
- window = MainWindow()
- qtbot.addWidget(window)
- yield window
- window.close()
- class TestMainWindow:
- """Test MainWindow functionality."""
- def test_initialization(self, main_window):
- """Test main window initializes correctly."""
- assert main_window.windowTitle() == "BMAD Novel Translator"
- assert main_window.width() == main_window.DEFAULT_WIDTH
- assert main_window.height() == main_window.DEFAULT_HEIGHT
- assert main_window.minimumWidth() == main_window.MINIMUM_WIDTH
- assert main_window.minimumHeight() == main_window.MINIMUM_HEIGHT
- def test_menu_bar_exists(self, main_window):
- """Test menu bar is created."""
- menubar = main_window.menuBar()
- assert menubar is not None
- # Check menus exist
- menus = {action.text(): action for action in menubar.actions()}
- assert "&File" in menus or "File" in menus
- assert "&Edit" in menus or "Edit" in menus
- assert "&View" in menus or "View" in menus
- assert "&Tools" in menus or "Tools" in menus
- assert "&Help" in menus or "Help" in menus
- def test_toolbar_exists(self, main_window):
- """Test toolbar is created."""
- toolbars = main_window.findChildren(QMainWindow)
- assert main_window.findChild(type(None)) is not None # Basic check
- # Toolbar actions are checked through UI inspection
- def test_status_bar_exists(self, main_window):
- """Test status bar is created."""
- status_bar = main_window.statusBar()
- assert status_bar is not None
- assert "v" in status_bar.currentMessage() or status_bar.children()
- def test_add_file_item(self, main_window, qtbot):
- """Test adding a file item."""
- item = FileItem(
- path=Path("/test/file.txt"),
- name="file.txt",
- size=1024,
- status=FileStatus.PENDING
- )
- main_window.add_file_item(item)
- assert len(main_window.file_items) == 1
- assert main_window.file_items[0].name == "file.txt"
- def test_add_multiple_file_items(self, main_window):
- """Test adding multiple file items."""
- items = [
- FileItem(
- path=Path(f"/test/file{i}.txt"),
- name=f"file{i}.txt",
- size=1024 * (i + 1),
- status=FileStatus.PENDING
- )
- for i in range(3)
- ]
- for item in items:
- main_window.add_file_item(item)
- assert len(main_window.file_items) == 3
- def test_remove_file_item(self, main_window):
- """Test removing a file item."""
- item = FileItem(
- path=Path("/test/file.txt"),
- name="file.txt",
- size=1024,
- status=FileStatus.PENDING
- )
- main_window.add_file_item(item)
- assert len(main_window.file_items) == 1
- main_window.remove_file_item(item)
- assert len(main_window.file_items) == 0
- def test_clear_all_files(self, main_window):
- """Test clearing all files."""
- items = [
- FileItem(
- path=Path(f"/test/file{i}.txt"),
- name=f"file{i}.txt",
- size=1024,
- status=FileStatus.PENDING
- )
- for i in range(3)
- ]
- for item in items:
- main_window.add_file_item(item)
- assert len(main_window.file_items) == 3
- main_window.clear_all_files()
- assert len(main_window.file_items) == 0
- def test_progress_update(self, main_window):
- """Test progress bar update."""
- main_window.set_progress(50)
- # Progress bar value should be 50
- # (Can't directly access widget value without exposing)
- def test_status_message(self, main_window):
- """Test status bar message update."""
- main_window.set_status_message("Test message")
- # Status bar should show the message
- def test_task_status_update(self, main_window):
- """Test task status label update."""
- main_window.set_task_status("Translating...")
- # Task status label should be updated
- def test_control_buttons_disabled_when_empty(self, main_window):
- """Test control buttons are disabled when no files."""
- assert not main_window._start_btn.isEnabled()
- assert not main_window._start_action.isEnabled()
- def test_control_buttons_enabled_with_files(self, main_window):
- """Test control buttons are enabled when files are added."""
- item = FileItem(
- path=Path("/test/file.txt"),
- name="file.txt",
- size=1024,
- status=FileStatus.READY
- )
- main_window.add_file_item(item)
- assert main_window._start_btn.isEnabled()
- assert main_window._start_action.isEnabled()
- def test_signals_emitted(self, main_window):
- """Test that signals are emitted correctly."""
- signal_received = []
- main_window.translation_started.connect(lambda: signal_received.append("started"))
- main_window.translation_paused.connect(lambda: signal_received.append("paused"))
- main_window.translation_cancelled.connect(lambda: signal_received.append("cancelled"))
- main_window.settings_requested.connect(lambda: signal_received.append("settings"))
- main_window._on_start_translation()
- main_window._on_pause_translation()
- main_window._on_cancel_translation()
- main_window._on_settings()
- assert signal_received == ["started", "paused", "cancelled", "settings"]
- def test_file_selector_integration(self, main_window):
- """Test FileSelector component is integrated."""
- file_selector = main_window.get_file_selector()
- if file_selector is not None:
- # FileSelector should be available
- assert hasattr(file_selector, 'file_selected')
- assert hasattr(file_selector, 'selection_cleared')
- else:
- # PyQt6 might not be available in test environment
- pass
- def test_progress_widget_integration(self, main_window):
- """Test ProgressWidget component is integrated."""
- progress_widget = main_window.get_progress_widget()
- if progress_widget is not None:
- # ProgressWidget should be available
- assert hasattr(progress_widget, 'connect_to_notifier')
- assert hasattr(progress_widget, 'reset')
- else:
- # PyQt6 might not be available in test environment
- pass
- def test_splitter_ratio(self, main_window):
- """Test splitter has correct initial ratio (30/70)."""
- # Check that splitter exists
- central_widget = main_window.centralWidget()
- assert central_widget is not None
- # Find splitter
- splitter = central_widget.findChild(type(central_widget).__class__)
- # MainWindow should have a QSplitter
- from PyQt6.QtWidgets import QSplitter
- splitters = central_widget.findChildren(QSplitter)
- assert len(splitters) > 0
- def test_left_right_panels(self, main_window):
- """Test left and right panels exist."""
- # The MainWindow should have file list on left, details on right
- assert hasattr(main_window, '_file_table')
- assert main_window._file_table is not None
- class TestFileItem:
- """Test FileItem model."""
- def test_file_item_creation(self):
- """Test creating a file item."""
- item = FileItem(
- path=Path("/test/file.txt"),
- name="file.txt",
- size=2048,
- status=FileStatus.PENDING
- )
- assert item.name == "file.txt"
- assert item.size == 2048
- assert item.status == FileStatus.PENDING
- assert item.chapters == 0
- assert item.total_words == 0
- def test_progress_calculation(self):
- """Test progress calculation."""
- item = FileItem(
- path=Path("/test/file.txt"),
- name="file.txt",
- size=1024,
- total_words=1000,
- translated_words=500
- )
- assert item.progress == 50.0
- def test_progress_zero_when_no_words(self):
- """Test progress is zero when no words set."""
- item = FileItem(
- path=Path("/test/file.txt"),
- name="file.txt",
- size=1024
- )
- assert item.progress == 0.0
- def test_size_formatting(self):
- """Test file size formatting."""
- # Bytes
- item1 = FileItem(path=Path("/test/small.txt"), name="small.txt", size=512)
- assert "B" in item1.size_formatted
- # KB
- item2 = FileItem(path=Path("/test/medium.txt"), name="medium.txt", size=2048)
- assert "KB" in item2.size_formatted
- # MB
- item3 = FileItem(path=Path("/test/large.txt"), name="large.txt", size=1024 * 1024 * 5)
- assert "MB" in item3.size_formatted
|