""" BenchmarkDialog 的單元測試。 測試策略: - PyQt5 在 CI 環境中不可用,透過 conftest.py 的 Stub 注入繞過 import。 - 測試驗證 BenchmarkDialog 的行為邏輯: - 對話框可正常建立 - pipeline_config 為空時開始按鈕被禁用 - show_result 正確顯示加速倍數文字 - update_progress 更新進度條值 """ import pytest from unittest.mock import MagicMock # --------------------------------------------------------------------------- # 測試:BenchmarkDialog 可以建立 # --------------------------------------------------------------------------- class TestBenchmarkDialogInit: def should_be_importable(self): """BenchmarkDialog 模組應可匯入(即使 PyQt5 被 Stub)。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog assert BenchmarkDialog is not None def should_instantiate_with_valid_config(self): """提供非空 pipeline_config 時,BenchmarkDialog 應可正常建立。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage_config = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage_config]) assert dialog is not None def should_instantiate_with_empty_config(self): """pipeline_config 為空時,BenchmarkDialog 應可建立(不應拋出例外)。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog dialog = BenchmarkDialog(parent=None, pipeline_config=[]) assert dialog is not None # --------------------------------------------------------------------------- # 測試:pipeline_config 為空時禁用開始按鈕 # --------------------------------------------------------------------------- class TestStartButtonDisabledWhenEmptyConfig: def should_disable_start_button_when_pipeline_config_is_empty(self): """pipeline_config 為空時,start_button 應被禁用。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog dialog = BenchmarkDialog(parent=None, pipeline_config=[]) assert dialog.start_button.isEnabled() is False def should_enable_start_button_when_pipeline_config_has_stages(self): """pipeline_config 有 Stage 時,start_button 應為啟用狀態。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage_config = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage_config]) assert dialog.start_button.isEnabled() is True def should_show_info_label_when_pipeline_config_is_empty(self): """pipeline_config 為空時,應有提示訊息 label 顯示。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog dialog = BenchmarkDialog(parent=None, pipeline_config=[]) assert hasattr(dialog, "info_label") # --------------------------------------------------------------------------- # 測試:show_result 顯示加速倍數 # --------------------------------------------------------------------------- class TestShowResult: def should_display_speedup_text_with_x_suffix(self): """show_result 後,speedup_label 的文字應包含倍數數值與 'x'。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage]) seq_result = MagicMock() par_result = MagicMock() dialog.show_result(seq_result, par_result, speedup=3.2) call_arg = dialog.speedup_label.setText.call_args[0][0] assert "3.2" in call_arg assert "x" in call_arg.lower() or "X" in call_arg def should_display_faster_in_speedup_text(self): """show_result 後,speedup_label 文字應包含 'FASTER' 或 'faster'。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage]) seq_result = MagicMock() par_result = MagicMock() dialog.show_result(seq_result, par_result, speedup=2.5) call_arg = dialog.speedup_label.setText.call_args[0][0] assert "FASTER" in call_arg or "faster" in call_arg def should_store_seq_result(self): """show_result 後,seq_result 應儲存在 dialog 上。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage]) seq_result = MagicMock() par_result = MagicMock() dialog.show_result(seq_result, par_result, speedup=1.8) assert dialog.seq_result is seq_result def should_store_par_result(self): """show_result 後,par_result 應儲存在 dialog 上。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage]) seq_result = MagicMock() par_result = MagicMock() dialog.show_result(seq_result, par_result, speedup=1.8) assert dialog.par_result is par_result # --------------------------------------------------------------------------- # 測試:update_progress 更新進度條 # --------------------------------------------------------------------------- class TestUpdateProgress: def should_update_progress_bar_value(self): """update_progress 應將進度條值更新為傳入的 value。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage]) dialog.progress_bar.setValue.reset_mock() dialog.update_progress("warmup", 42) dialog.progress_bar.setValue.assert_called_once_with(42) def should_store_current_phase(self): """update_progress 應儲存當前 phase 名稱。""" from ui.dialogs.benchmark_dialog import BenchmarkDialog stage = MagicMock() dialog = BenchmarkDialog(parent=None, pipeline_config=[stage]) dialog.update_progress("sequential", 70) assert dialog.current_phase == "sequential"