diff --git a/src/testium/main_win/test_controller_service.py b/src/testium/main_win/test_controller_service.py new file mode 100644 index 0000000..33583f4 --- /dev/null +++ b/src/testium/main_win/test_controller_service.py @@ -0,0 +1,71 @@ +from interpreter.utils.test_ctrl import TestSetController + + +class TestControllerService: + """Typed interface over TestSetController, decoupling the UI from raw RPC strings.""" + + def __init__(self, controller: TestSetController) -> None: + self._ctrl = controller + + # --- Lifecycle --- + + def stop(self) -> None: + self._ctrl.control("stop") + + def close(self) -> None: + self._ctrl.control("close") + + def execute(self) -> None: + self._ctrl.control("execute") + + def loaded(self, timeout: float = None) -> bool: + return self._ctrl.control("loaded", timeout=timeout) + + def clear(self) -> None: + self._ctrl.clear() + + # --- Execution control --- + + def pause(self) -> None: + self._ctrl.control("pause") + + def cont(self) -> None: + self._ctrl.control("cont") + + # --- Breakpoints --- + + def add_breakpoint(self, item_id) -> None: + self._ctrl.control("add_breakpoint", item_id=item_id) + + def del_breakpoint(self, item_id) -> None: + self._ctrl.control("del_breakpoint", item_id=item_id) + + # --- Tree data --- + + def tree(self) -> dict: + return self._ctrl.control("tree") + + # --- Item state --- + + def get_enabled_state(self, item_id) -> bool: + return self._ctrl.control("enabled_state", item_id=item_id) + + def set_enabled_state(self, item_id, state: bool, unitary: bool = False) -> None: + self._ctrl.control("set_enabled_state", item_id=item_id, enabled_state=state, unitary=unitary) + + def check_uncheck_all(self, checked: bool) -> None: + self._ctrl.control("check_uncheck_all", checked=checked) + + def get_skipped_state(self, item_id) -> bool: + return self._ctrl.control("skipped_state", item_id=item_id) + + # --- Configuration --- + + def process_param(self, param: str) -> str: + return self._ctrl.control("process_param", param=param) + + def set_report(self, rep_path: str, rep_type: str, pattern: list) -> None: + self._ctrl.control("report", rep_path=rep_path, rep_type=rep_type, pattern=pattern) + + def set_test_outputs(self, outputs: list) -> None: + self._ctrl.control("set_test_outputs", outputs=outputs) diff --git a/src/testium/main_win/test_tree.py b/src/testium/main_win/test_tree.py index 1cdf54d..224ef99 100644 --- a/src/testium/main_win/test_tree.py +++ b/src/testium/main_win/test_tree.py @@ -11,7 +11,7 @@ from time import (time) from main_win.test_tree_items.common import (TEST_COLS, TEST_COLS_WITH_TIME) from lib.tum_except import (ETUMFileError, ETUMSyntaxError) -from interpreter.utils.test_ctrl import TestSetController +from main_win.test_controller_service import TestControllerService from main_win.test_tree_items.test_tree_git import QTestTreeItemGit # to be removed in the future and replaced by a more "sexy" mechanism @@ -122,11 +122,11 @@ class QTestTree(QTreeWidget): self.header().sectionResized.connect(self.resized) - def updateTestSetItemState(self, tree_item, tst_ctrl: TestSetController, state, unitary=False): + def updateTestSetItemState(self, tree_item, tst_ctrl: TestControllerService, state, unitary=False): id = tree_item.id - tst_ctrl.control("set_enabled_state", item_id=id, enabled_state=state, unitary=unitary) + tst_ctrl.set_enabled_state(id, state, unitary=unitary) - def updateTreeCheckState(self, tree_item, tst_ctrl: TestSetController): + def updateTreeCheckState(self, tree_item, tst_ctrl: TestControllerService): # treat the case of the invisible root if tree_item is self.root: for i in range(self.root.childCount()): @@ -137,9 +137,9 @@ class QTestTree(QTreeWidget): self.updateTestSetItemState(tree_item, tst_ctrl, state) self.synchronizeEnabledState(tst_ctrl) - def checkUncheckAll(self, tst_ctrl: TestSetController, isChecked): + def checkUncheckAll(self, tst_ctrl: TestControllerService, isChecked): # test_set.enableDisableAll(test_set.rootItem(), isChecked) - tst_ctrl.control("check_uncheck_all", checked=isChecked) + tst_ctrl.check_uncheck_all(isChecked) self.synchronizeEnabledState(tst_ctrl) def __foldRecursively(self, tree_item, is_fold): @@ -158,10 +158,10 @@ class QTestTree(QTreeWidget): def foldAll(self, is_fold): self.__foldRecursively(self.root, is_fold) - def __synchronizeEnabledStateRecursively(self, tree_item, tst_ctrl: TestSetController): + def __synchronizeEnabledStateRecursively(self, tree_item, tst_ctrl: TestControllerService): for i in range(tree_item.childCount()): id = tree_item.child(i).id - checked = tst_ctrl.control("enabled_state", item_id=id) + checked = tst_ctrl.get_enabled_state(id) if checked: tree_item.child(i).setCheckState(self.cols['name']['index'], Qt.Checked) @@ -171,14 +171,14 @@ class QTestTree(QTreeWidget): self.__synchronizeEnabledStateRecursively( tree_item.child(i), tst_ctrl) - def updateTreeSkipState(self, tst_ctrl: TestSetController): + def updateTreeSkipState(self, tst_ctrl: TestControllerService): self.__updateTreeSkipStateRecursively(self.root, tst_ctrl) - def __updateTreeSkipStateRecursively(self, tree_item, tst_ctrl: TestSetController): + def __updateTreeSkipStateRecursively(self, tree_item, tst_ctrl: TestControllerService): for i in range(tree_item.childCount()): id = tree_item.child(i).id # skipped = test_set.getSkippedState(id) - skipped = tst_ctrl.control("skipped_state", item_id=id) + skipped = tst_ctrl.get_skipped_state(id) if skipped: tree_item.child(i).setDisabled(True) tree_item.child(i).setExpanded(False) @@ -195,7 +195,7 @@ class QTestTree(QTreeWidget): tree_item.child(i)._is_skipped = True self.__skipRecursively(tree_item.child(i)) - def synchronizeEnabledState(self, tst_ctrl: TestSetController): + def synchronizeEnabledState(self, tst_ctrl: TestControllerService): self.__synchronizeEnabledStateRecursively(self.root, tst_ctrl) def __enableRecursively(self, tree_item): @@ -347,7 +347,7 @@ class QTestTree(QTreeWidget): if root.child(i).childCount() > 0: self.addCheckBoxes(root.child(i)) - def showCheckBoxes(self, checklist, tst_ctrl: TestSetController): + def showCheckBoxes(self, checklist, tst_ctrl: TestControllerService): self.addCheckBoxes() self.restoreCheckList(checklist, tst_ctrl) @@ -382,12 +382,12 @@ class QTestTree(QTreeWidget): checklist.append((i.checkState(0) == Qt.Checked)) return checklist - def restoreCheckList(self, checklist, tst_ctrl: TestSetController): + def restoreCheckList(self, checklist, tst_ctrl: TestControllerService): itemlist = reversed(list(self.root)) for item in itemlist: state = checklist.pop(len(checklist)-1) if item is not self.root: - skipped = tst_ctrl.control("skipped_state", item_id=item.id) + skipped = tst_ctrl.get_skipped_state(item.id) if skipped: item.setDisabled(True) for i in range(item.childCount()): diff --git a/src/testium/main_win/testium_win.py b/src/testium/main_win/testium_win.py index 366e9ec..82a4041 100755 --- a/src/testium/main_win/testium_win.py +++ b/src/testium/main_win/testium_win.py @@ -39,6 +39,7 @@ from main_win.test_run.thread_output import ThreadTestOutput from lib.string_queue import StringQueue from interpreter.process import TestProcess from interpreter.utils.test_ctrl import TestSetController +from main_win.test_controller_service import TestControllerService from interpreter.utils.icons import icon_prefix from main_win.test_run.outlog import OutLog @@ -181,6 +182,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.debug = debug self.test_proc = None self.ts_controller = None + self.test_service = None self.threadTestStatus = None self._test_started = False self._test_paused = False @@ -380,7 +382,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): checkList = prefs.settings.value(prefs.SettingsItem("checkList", list), []) if checkList is not None: if len(checkList) == self.treeTests.getItemCount(): - self.treeTests.restoreCheckList(checkList, self.ts_controller) + self.treeTests.restoreCheckList(checkList, self.test_service) else: tm.print_info( @@ -436,11 +438,13 @@ class MainWindow(QMainWindow, Ui_MainWindow): and self.test_proc.is_alive() and (self.ts_controller is not None) ): - self.ts_controller.control("stop") - self.ts_controller.control("close") + self.test_service.stop() + self.test_service.close() self.test_proc.join() del self.test_proc self.test_proc = None + del self.test_service + self.test_service = None del self.ts_controller self.ts_controller = None @@ -466,12 +470,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Test to be paused if self._test_started: if not self._test_paused: - self.ts_controller.control("pause") + self.test_service.pause() self.startPauseTimer() else: # Test to be continued - self.ts_controller.control("cont") + self.test_service.cont() self.timerPause.stop() self.timerPause.state = False self.on_timerPause() @@ -488,9 +492,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): try: if not os.path.isabs(log_file): default_path = prefs.settings.log_path - default_path = self.ts_controller.control( - "process_param", param=default_path - ) + default_path = self.test_service.process_param(default_path) log_file = os.path.join(default_path, log_file) # if the directory does not exist if not os.path.exists(os.path.dirname(log_file)): @@ -521,15 +523,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.logFileName = self.logFileHandler.name # Report file definition - rep_file = self.ts_controller.control( - "process_param", param=self.reportFileName - ) - self.ts_controller.control( - "report", - rep_path=rep_file, - rep_type=self.report_type, - pattern=self.report_pattern, - ) + rep_file = self.test_service.process_param(self.reportFileName) + self.test_service.set_report(rep_file, self.report_type, self.report_pattern) self.adaptInterfaceDuringTest() self.treeTests.clearAllStatus() try: @@ -539,9 +534,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.timer.setInterval(100) self.timer.start() # Add the log file to the std test_outputs - self.ts_controller.control("set_test_outputs", outputs=[self.logFileName]) + self.test_service.set_test_outputs([self.logFileName]) # Launch the test - self.ts_controller.control("execute") + self.test_service.execute() except: print(traceback.format_exc()) self.restoreInterfaceAfterTest() @@ -566,7 +561,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): @Slot() def on_actionStop_test_triggered(self): - self.ts_controller.control("stop") + self.test_service.stop() def save_settings(self): prefs.settings.set_value( @@ -709,9 +704,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.disconnect_signals() try: if state == Qt.Checked: - self.treeTests.checkUncheckAll(self.ts_controller, True) + self.treeTests.checkUncheckAll(self.test_service, True) elif state == Qt.Unchecked: - self.treeTests.checkUncheckAll(self.ts_controller, False) + self.treeTests.checkUncheckAll(self.test_service, False) finally: self.reconnect_signals() @@ -719,7 +714,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.checkSelect.setCheckState(Qt.PartiallyChecked) self.disconnect_signals() try: - self.treeTests.updateTreeCheckState(item, self.ts_controller) + self.treeTests.updateTreeCheckState(item, self.test_service) finally: self.reconnect_signals() @@ -772,9 +767,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): isBrkpointCol = item.setBreakpointIfCol(col) if isBrkpointCol: if item.isBreakpoint(): - self.ts_controller.control("add_breakpoint", item_id=item.id) + self.test_service.add_breakpoint(item.id) else: - self.ts_controller.control("del_breakpoint", item_id=item.id) + self.test_service.del_breakpoint(item.id) return s = sys.platform @@ -789,9 +784,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): item = self.treeTests.currentItem() add_breakpoint = item.setBreakpoint() if add_breakpoint: - self.ts_controller.control("add_breakpoint", item_id=item.id) + self.test_service.add_breakpoint(item.id) else: - self.ts_controller.control("del_breakpoint", item_id=item.id) + self.test_service.del_breakpoint(item.id) def on_F1Pressed(self): item = self.treeTests.currentItem() @@ -919,7 +914,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): else: # production mode if hasattr(self, "treeTests"): - self.treeTests.checkUncheckAll(self.ts_controller, True) + self.treeTests.checkUncheckAll(self.test_service, True) self.disconnect_signals() self.treeTests.removeCheckBoxes() self.reconnect_signals() @@ -1005,6 +1000,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.testFile = None self.ts_controller = TestSetController() + self.test_service = TestControllerService(self.ts_controller) self.test_proc = TestProcess( file_name, self.status_queue, @@ -1016,14 +1012,16 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.test_proc.start() while self.test_proc.is_alive(): try: - if self.ts_controller.control("loaded", timeout=1.0): + if self.test_service.loaded(timeout=1.0): break except Empty: - self.ts_controller.clear() + self.test_service.clear() if not self.test_proc.is_alive(): del self.test_proc self.test_proc = None + del self.test_service + self.test_service = None del self.ts_controller self.ts_controller = None @@ -1031,13 +1029,13 @@ class MainWindow(QMainWindow, Ui_MainWindow): "Test could not be loaded (test process crashed for any reason)" ) - test_data = self.ts_controller.control("tree") + test_data = self.test_service.tree() self.treeTests.clear() self.treeTests.loadTestRecursively( self.treeTests.invisibleRootItem(), test_data ) self.treeTests.setFoldDefault() - self.treeTests.updateTreeSkipState(self.ts_controller) + self.treeTests.updateTreeSkipState(self.test_service) self.checkSelect.setChecked(True) self.testFile = file_name @@ -1115,7 +1113,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.logSettingsBox.setEnabled(True) if prefs.settings.show_checkboxes: self.checkSelect.setEnabled(True) - self.treeTests.showCheckBoxes(self._checklist, self.ts_controller) + self.treeTests.showCheckBoxes(self._checklist, self.test_service) self.checkFold.setEnabled(True) self.treeTests.setChildrenEnabled() self.reconnect_signals()