FreeCAD
258 строк · 10.0 Кб
1# SPDX-License-Identifier: LGPL-2.1-or-later
2# ***************************************************************************
3# * *
4# * Copyright (c) 2022 FreeCAD Project Association *
5# * *
6# * This file is part of FreeCAD. *
7# * *
8# * FreeCAD is free software: you can redistribute it and/or modify it *
9# * under the terms of the GNU Lesser General Public License as *
10# * published by the Free Software Foundation, either version 2.1 of the *
11# * License, or (at your option) any later version. *
12# * *
13# * FreeCAD is distributed in the hope that it will be useful, but *
14# * WITHOUT ANY WARRANTY; without even the implied warranty of *
15# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16# * Lesser General Public License for more details. *
17# * *
18# * You should have received a copy of the GNU Lesser General Public *
19# * License along with FreeCAD. If not, see *
20# * <https://www.gnu.org/licenses/>. *
21# * *
22# ***************************************************************************
23
24from time import sleep25import unittest26import FreeCAD27
28from Addon import Addon29
30from PySide import QtCore, QtWidgets31
32from addonmanager_update_all_gui import UpdateAllGUI, AddonStatus33
34
35class MockUpdater(QtCore.QObject):36success = QtCore.Signal(object)37failure = QtCore.Signal(object)38finished = QtCore.Signal()39
40def __init__(self, addon, addons=[]):41super().__init__()42self.addon_to_install = addon43self.addons = addons44self.has_run = False45self.emit_success = True46self.work_function = None # Set to some kind of callable to make this function take time47
48def run(self):49self.has_run = True50if self.work_function is not None and callable(self.work_function):51self.work_function()52if self.emit_success:53self.success.emit(self.addon_to_install)54else:55self.failure.emit(self.addon_to_install)56self.finished.emit()57
58
59class MockUpdaterFactory:60def __init__(self, addons):61self.addons = addons62self.work_function = None63self.updater = None64
65def get_updater(self, addon):66self.updater = MockUpdater(addon, self.addons)67self.updater.work_function = self.work_function68return self.updater69
70
71class MockAddon:72def __init__(self, name):73self.display_name = name74self.name = name75self.macro = None76
77def status(self):78return Addon.Status.UPDATE_AVAILABLE79
80
81class CallInterceptor:82def __init__(self):83self.called = False84self.args = None85
86def intercept(self, *args):87self.called = True88self.args = args89
90
91class TestUpdateAllGui(unittest.TestCase):92def setUp(self):93self.addons = []94for i in range(3):95self.addons.append(MockAddon(f"Mock Addon {i}"))96self.factory = MockUpdaterFactory(self.addons)97self.test_object = UpdateAllGUI(self.addons)98self.test_object.updater_factory = self.factory99
100def tearDown(self):101pass102
103def test_run(self):104self.factory.work_function = lambda: sleep(0.1)105self.test_object.run()106while self.test_object.is_running():107QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)108self.test_object.dialog.accept()109
110def test_setup_dialog(self):111self.test_object._setup_dialog()112self.assertIsNotNone(113self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel)114)115self.assertEqual(self.test_object.dialog.tableWidget.rowCount(), 3)116
117def test_cancelling_installation(self):118class Worker:119def __init__(self):120self.counter = 0121self.LIMIT = 100122self.limit_reached = False123
124def run(self):125while self.counter < self.LIMIT:126if QtCore.QThread.currentThread().isInterruptionRequested():127return128self.counter += 1129sleep(0.01)130self.limit_reached = True131
132worker = Worker()133self.factory.work_function = worker.run134self.test_object.run()135cancel_timer = QtCore.QTimer()136cancel_timer.timeout.connect(137self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel).click138)139cancel_timer.start(90)140while self.test_object.is_running():141QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 10)142self.assertGreater(len(self.test_object.addons_with_update), 0)143
144def test_add_addon_to_table(self):145mock_addon = MockAddon("MockAddon")146self.test_object.dialog.tableWidget.clear()147self.test_object._add_addon_to_table(mock_addon)148self.assertEqual(self.test_object.dialog.tableWidget.rowCount(), 1)149
150def test_update_addon_status(self):151self.test_object._setup_dialog()152self.test_object._update_addon_status(0, AddonStatus.WAITING)153self.assertEqual(154self.test_object.dialog.tableWidget.item(0, 1).text(),155AddonStatus.WAITING.ui_string(),156)157self.test_object._update_addon_status(0, AddonStatus.INSTALLING)158self.assertEqual(159self.test_object.dialog.tableWidget.item(0, 1).text(),160AddonStatus.INSTALLING.ui_string(),161)162self.test_object._update_addon_status(0, AddonStatus.SUCCEEDED)163self.assertEqual(164self.test_object.dialog.tableWidget.item(0, 1).text(),165AddonStatus.SUCCEEDED.ui_string(),166)167self.test_object._update_addon_status(0, AddonStatus.FAILED)168self.assertEqual(169self.test_object.dialog.tableWidget.item(0, 1).text(),170AddonStatus.FAILED.ui_string(),171)172
173def test_process_next_update(self):174self.test_object._setup_dialog()175self.test_object._launch_active_installer = lambda: None176self.test_object._process_next_update()177self.assertEqual(178self.test_object.dialog.tableWidget.item(0, 1).text(),179AddonStatus.INSTALLING.ui_string(),180)181
182self.test_object._process_next_update()183self.assertEqual(184self.test_object.dialog.tableWidget.item(1, 1).text(),185AddonStatus.INSTALLING.ui_string(),186)187
188self.test_object._process_next_update()189self.assertEqual(190self.test_object.dialog.tableWidget.item(2, 1).text(),191AddonStatus.INSTALLING.ui_string(),192)193
194self.test_object._process_next_update()195
196def test_launch_active_installer(self):197self.test_object.active_installer = self.factory.get_updater(self.addons[0])198self.test_object._update_succeeded = lambda _: None199self.test_object._update_failed = lambda _: None200self.test_object.process_next_update = lambda: None201self.test_object._launch_active_installer()202# The above call does not block, so spin until it has completed (basically instantly in testing)203while self.test_object.worker_thread.isRunning():204QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)205self.test_object.dialog.accept()206
207def test_update_succeeded(self):208self.test_object._setup_dialog()209self.test_object._update_succeeded(self.addons[0])210self.assertEqual(211self.test_object.dialog.tableWidget.item(0, 1).text(),212AddonStatus.SUCCEEDED.ui_string(),213)214
215def test_update_failed(self):216self.test_object._setup_dialog()217self.test_object._update_failed(self.addons[0])218self.assertEqual(219self.test_object.dialog.tableWidget.item(0, 1).text(),220AddonStatus.FAILED.ui_string(),221)222
223def test_update_finished(self):224self.test_object._setup_dialog()225call_interceptor = CallInterceptor()226self.test_object.worker_thread = QtCore.QThread()227self.test_object.worker_thread.start()228self.test_object._process_next_update = call_interceptor.intercept229self.test_object.active_installer = self.factory.get_updater(self.addons[0])230self.test_object._update_finished()231self.assertFalse(self.test_object.worker_thread.isRunning())232self.test_object.worker_thread.quit()233self.assertTrue(call_interceptor.called)234self.test_object.worker_thread.wait()235
236def test_finalize(self):237self.test_object._setup_dialog()238self.test_object.worker_thread = QtCore.QThread()239self.test_object.worker_thread.start()240self.test_object._finalize()241self.assertFalse(self.test_object.worker_thread.isRunning())242self.test_object.worker_thread.quit()243self.test_object.worker_thread.wait()244self.assertFalse(self.test_object.running)245self.assertIsNotNone(246self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Close)247)248self.assertIsNone(249self.test_object.dialog.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel)250)251
252def test_is_running(self):253self.assertFalse(self.test_object.is_running())254self.test_object.run()255self.assertTrue(self.test_object.is_running())256while self.test_object.is_running():257QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)258self.test_object.dialog.accept()259