From 4db688771ae042a5ee77b5e55a510cdddb7b4248 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Tue, 20 Dec 2022 10:07:14 -0600 Subject: [PATCH] Addon Manager: Fix test language dependency Fixes #8065 --- .../AddonManagerTest/gui/gui_mocks.py | 30 +++++-- .../gui/test_installer_gui.py | 80 +++++++++++++------ .../gui/test_uninstaller_gui.py | 33 ++++++-- 3 files changed, 103 insertions(+), 40 deletions(-) diff --git a/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py b/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py index 4a4f107d19..3270e34780 100644 --- a/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py +++ b/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py @@ -26,14 +26,23 @@ from PySide import QtCore, QtWidgets class DialogWatcher(QtCore.QObject): """Examine the running GUI and look for a modal dialog with a given title, containing a button with a given label. Click that button, which is expected to close the dialog. Generally run on - a one-shot QTimer to allow the dialog time to open up.""" + a one-shot QTimer to allow the dialog time to open up. If the specified dialog is found, but + it does not contain the expected button, button_found will be false, and the dialog will be + closed with a reject() slot.""" - def __init__(self, dialog_to_watch_for, button): + def __init__(self, dialog_to_watch_for, button=QtWidgets.QDialogButtonBox.NoButton): super().__init__() + + # Status variables for tests to check: self.dialog_found = False self.has_run = False + self.button_found = False + self.dialog_to_watch_for = dialog_to_watch_for - self.button = button + if button != QtWidgets.QDialogButtonBox.NoButton: + self.button = button + else: + self.button = QtWidgets.QDialogButtonBox.Cancel def run(self): widget = QtWidgets.QApplication.activeModalWidget() @@ -50,11 +59,16 @@ class DialogWatcher(QtCore.QObject): self.has_run = True def click_button(self, widget): - buttons = widget.findChildren(QtWidgets.QPushButton) - for button in buttons: - text = button.text().replace("&", "") - if text == self.button: - button.click() + button_boxes = widget.findChildren(QtWidgets.QDialogButtonBox) + if len(button_boxes) == 1: # There should be one, and only one + button_to_click = button_boxes[0].button(self.button) + if button_to_click: + self.button_found = True + button_to_click.click() + else: + widget.reject() + else: + widget.reject() class DialogInteractor(DialogWatcher): diff --git a/src/Mod/AddonManager/AddonManagerTest/gui/test_installer_gui.py b/src/Mod/AddonManager/AddonManagerTest/gui/test_installer_gui.py index ba7e00fbc8..9b2cdac8be 100644 --- a/src/Mod/AddonManager/AddonManagerTest/gui/test_installer_gui.py +++ b/src/Mod/AddonManager/AddonManagerTest/gui/test_installer_gui.py @@ -50,19 +50,23 @@ class TestInstallerGui(unittest.TestCase): def test_success_dialog(self): # Pop the modal dialog and verify that it opens, and responds to an OK click dialog_watcher = DialogWatcher( - translate("AddonsInstaller", "Success"), translate("AddonsInstaller", "OK") + translate("AddonsInstaller", "Success"), + QtWidgets.QDialogButtonBox.Ok, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._installation_succeeded() self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_failure_dialog(self): # Pop the modal dialog and verify that it opens, and responds to a Cancel click dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Installation Failed"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._installation_failed( @@ -71,36 +75,45 @@ class TestInstallerGui(unittest.TestCase): self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_no_python_dialog(self): # Pop the modal dialog and verify that it opens, and responds to a No click dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Cannot execute Python"), - translate("AddonsInstaller", "No"), + QtWidgets.QDialogButtonBox.No, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._report_no_python_exe() self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_no_pip_dialog(self): # Pop the modal dialog and verify that it opens, and responds to a No click dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Cannot execute pip"), - translate("AddonsInstaller", "No"), + QtWidgets.QDialogButtonBox.No, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._report_no_pip("pip not actually run, this was a test") self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_dependency_failure_dialog(self): # Pop the modal dialog and verify that it opens, and responds to a No click dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Package installation failed"), - translate("AddonsInstaller", "No"), + QtWidgets.QDialogButtonBox.No, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._report_dependency_failure( @@ -109,6 +122,9 @@ class TestInstallerGui(unittest.TestCase): self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_install(self): # Run the installation code and make sure it puts the directory in place @@ -132,13 +148,16 @@ class TestInstallerGui(unittest.TestCase): disallowed_packages = ["disallowed_package_name"] dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Missing Requirement"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._handle_disallowed_python(disallowed_packages) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_handle_disallowed_python_long_list(self): """A separate test for when there are MANY packages, which takes a separate code path.""" @@ -147,39 +166,48 @@ class TestInstallerGui(unittest.TestCase): disallowed_packages.append(f"disallowed_package_name_{i}") dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Missing Requirement"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._handle_disallowed_python(disallowed_packages) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_report_missing_workbenches_single(self): """Test only missing one workbench""" wbs = ["OneMissingWorkbench"] dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Missing Requirement"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._report_missing_workbenches(wbs) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_report_missing_workbenches_multiple(self): """Test only missing one workbench""" wbs = ["FirstMissingWorkbench", "SecondMissingWorkbench"] dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Missing Requirement"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._report_missing_workbenches(wbs) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_resolve_dependencies_then_install(self): class MissingDependenciesMock: @@ -190,14 +218,17 @@ class TestInstallerGui(unittest.TestCase): missing = MissingDependenciesMock() dialog_watcher = DialogWatcher( - translate("AddonsInstaller", "Resolve Dependencies"), - translate("AddonsInstaller", "Cancel"), + translate("DependencyResolutionDialog", "Resolve Dependencies"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer_gui._resolve_dependencies_then_install(missing) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_check_python_version_bad(self): class MissingDependenciesMock: @@ -207,13 +238,16 @@ class TestInstallerGui(unittest.TestCase): missing = MissingDependenciesMock() dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Incompatible Python version"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) stop_installing = self.installer_gui._check_python_version(missing) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) self.assertTrue( stop_installing, "Failed to halt installation on bad Python version" ) @@ -427,8 +461,8 @@ class TestMacroInstallerGui(unittest.TestCase): # First test: the user cancels the dialog self.installer.addon_params.set("alwaysAskForToolbar", True) dialog_watcher = DialogWatcher( - translate("AddonsInstaller", "Select Toolbar"), - translate("AddonsInstaller", "Cancel"), + translate("select_toolbar_dialog", "Select Toolbar"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) result = self.installer._ask_for_toolbar([]) @@ -440,17 +474,12 @@ class TestMacroInstallerGui(unittest.TestCase): # - The checkbox "Ask every time" is unchecked # - The selected toolbar option is "Create new toolbar", which triggers a search for # a new custom toolbar name by calling _create_new_custom_toolbar, which we mock. - dialog_watcher = DialogWatcher( - translate("AddonsInstaller", "Select Toolbar"), - translate("AddonsInstaller", "Cancel"), - ) - QtCore.QTimer.singleShot(10, dialog_watcher.run) fake_custom_toolbar_group = TestMacroInstallerGui.MockParameter() fake_custom_toolbar_group.set("Name", "UnitTestCustomToolbar") self.installer._create_new_custom_toolbar = lambda: fake_custom_toolbar_group dialog_watcher = DialogWatcher( - translate("AddonsInstaller", "Select Toolbar"), - translate("AddonsInstaller", "OK"), + translate("select_toolbar_dialog", "Select Toolbar"), + QtWidgets.QDialogButtonBox.Ok, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) result = self.installer._ask_for_toolbar([]) @@ -460,13 +489,16 @@ class TestMacroInstallerGui(unittest.TestCase): self.assertEqual(name, "UnitTestCustomToolbar") self.assertIn("alwaysAskForToolbar", self.installer.addon_params.params) self.assertFalse(self.installer.addon_params.get("alwaysAskForToolbar", True)) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_ask_for_toolbar_with_dialog_selection(self): # Third test: the user selects a custom toolbar in the dialog, and checks the box to always # ask. dialog_interactor = DialogInteractor( - translate("AddonsInstaller", "Select Toolbar"), + translate("select_toolbar_dialog", "Select Toolbar"), self.interactor_selection_option_and_checkbox, ) QtCore.QTimer.singleShot(10, dialog_interactor.run) @@ -526,8 +558,8 @@ class TestMacroInstallerGui(unittest.TestCase): def test_ask_to_install_toolbar_button_enabled_no(self): self.installer.addon_params.SetBool("dontShowAddMacroButtonDialog", False) dialog_watcher = DialogWatcher( - translate("AddonsInstaller", "Add button?"), - translate("AddonsInstaller", "No"), + translate("toolbar_button", "Add button?"), + QtWidgets.QDialogButtonBox.No, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.installer._ask_to_install_toolbar_button() # Blocks until killed by watcher diff --git a/src/Mod/AddonManager/AddonManagerTest/gui/test_uninstaller_gui.py b/src/Mod/AddonManager/AddonManagerTest/gui/test_uninstaller_gui.py index 8e43e34380..93c59635ea 100644 --- a/src/Mod/AddonManager/AddonManagerTest/gui/test_uninstaller_gui.py +++ b/src/Mod/AddonManager/AddonManagerTest/gui/test_uninstaller_gui.py @@ -23,13 +23,12 @@ import functools import unittest -from PySide import QtCore +from PySide import QtCore, QtWidgets import FreeCAD from AddonManagerTest.gui.gui_mocks import ( DialogWatcher, - DialogInteractor, FakeWorker, MockThread, ) @@ -59,25 +58,31 @@ class TestUninstallerGUI(unittest.TestCase): def test_confirmation_dialog_yes(self): dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Confirm remove"), - translate("AddonsInstaller", "Yes"), + QtWidgets.QDialogButtonBox.Yes, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) answer = self.uninstaller_gui._confirm_uninstallation() self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) self.assertTrue(answer, "Expected a 'Yes' click to return True, but got False") def test_confirmation_dialog_cancel(self): dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Confirm remove"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) answer = self.uninstaller_gui._confirm_uninstallation() self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) self.assertFalse( answer, "Expected a 'Cancel' click to return False, but got True" ) @@ -85,7 +90,7 @@ class TestUninstallerGUI(unittest.TestCase): def test_progress_dialog(self): dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Removing Addon"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.uninstaller_gui._show_progress_dialog() @@ -95,12 +100,15 @@ class TestUninstallerGUI(unittest.TestCase): self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_timer_launches_progress_dialog(self): worker = FakeWorker() dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Removing Addon"), - translate("AddonsInstaller", "Cancel"), + QtWidgets.QDialogButtonBox.Cancel, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) QtCore.QTimer.singleShot(20, worker.stop) @@ -114,22 +122,28 @@ class TestUninstallerGUI(unittest.TestCase): self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_success_dialog(self): dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Uninstall complete"), - translate("AddonsInstaller", "OK"), + QtWidgets.QDialogButtonBox.Ok, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.uninstaller_gui._succeeded(self.addon_to_remove) self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_failure_dialog(self): dialog_watcher = DialogWatcher( translate("AddonsInstaller", "Uninstall failed"), - translate("AddonsInstaller", "OK"), + QtWidgets.QDialogButtonBox.Ok, ) QtCore.QTimer.singleShot(10, dialog_watcher.run) self.uninstaller_gui._failed( @@ -138,6 +152,9 @@ class TestUninstallerGUI(unittest.TestCase): self.assertTrue( dialog_watcher.dialog_found, "Failed to find the expected dialog box" ) + self.assertTrue( + dialog_watcher.button_found, "Failed to find the expected button" + ) def test_finalize(self): self.uninstaller_gui.finished.connect(