eric7/Unittest/UnittestWidget.py

branch
unittest
changeset 9066
a219ade50f7c
parent 9065
39405e6eba20
child 9069
938039ea15ca
--- a/eric7/Unittest/UnittestWidget.py	Mon May 16 17:22:43 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1024 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a widget to orchestrate unit test execution.
-"""
-
-import contextlib
-import enum
-import locale
-import os
-
-from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QCoreApplication
-from PyQt6.QtWidgets import (
-    QAbstractButton, QComboBox, QDialogButtonBox, QWidget
-)
-
-from EricWidgets import EricMessageBox
-from EricWidgets.EricApplication import ericApp
-from EricWidgets.EricMainWindow import EricMainWindow
-from EricWidgets.EricPathPicker import EricPathPickerModes
-
-from .Ui_UnittestWidget import Ui_UnittestWidget
-
-from .UTTestResultsTree import TestResultsModel, TestResultsTreeView
-from .Interfaces import Frameworks
-from .Interfaces.UTExecutorBase import (
-    UTTestConfig, UTTestResult, ResultCategory
-)
-from .Interfaces.UTFrameworkRegistry import UTFrameworkRegistry
-
-import Preferences
-import UI.PixmapCache
-
-from Globals import (
-    recentNameUnittestDiscoverHistory, recentNameUnittestFileHistory,
-    recentNameUnittestTestnameHistory, recentNameUnittestFramework,
-    recentNameUnittestEnvironment
-)
-
-
-class UnittestWidgetModes(enum.Enum):
-    """
-    Class defining the various modes of the unittest widget.
-    """
-    IDLE = 0            # idle, no test were run yet
-    RUNNING = 1         # test run being performed
-    STOPPED = 2         # test run finished
-
-
-# TODO: add a "Show Coverage" function using PyCoverageDialog
-
-class UnittestWidget(QWidget, Ui_UnittestWidget):
-    """
-    Class implementing a widget to orchestrate unit test execution.
-    
-    @signal unittestFile(str, int, bool) emitted to show the source of a
-        unittest file
-    @signal unittestStopped() emitted after a unit test was run
-    """
-    unittestFile = pyqtSignal(str, int, bool)
-    unittestStopped = pyqtSignal()
-    
-    def __init__(self, testfile=None, parent=None):
-        """
-        Constructor
-        
-        @param testfile file name of the test to load
-        @type str
-        @param parent reference to the parent widget (defaults to None)
-        @type QWidget (optional)
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-        
-        self.__resultsModel = TestResultsModel(self)
-        self.__resultsModel.summary.connect(self.__setStatusLabel)
-        self.__resultsTree = TestResultsTreeView(self)
-        self.__resultsTree.setModel(self.__resultsModel)
-        self.__resultsTree.goto.connect(self.__showSource)
-        self.resultsGroupBox.layout().addWidget(self.__resultsTree)
-        
-        self.versionsButton.setIcon(
-            UI.PixmapCache.getIcon("info"))
-        self.clearHistoriesButton.setIcon(
-            UI.PixmapCache.getIcon("clearPrivateData"))
-        
-        self.testsuitePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
-        self.testsuitePicker.setInsertPolicy(
-            QComboBox.InsertPolicy.InsertAtTop)
-        self.testsuitePicker.setSizeAdjustPolicy(
-            QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon)
-        
-        self.discoveryPicker.setMode(EricPathPickerModes.DIRECTORY_MODE)
-        self.discoveryPicker.setInsertPolicy(
-            QComboBox.InsertPolicy.InsertAtTop)
-        self.discoveryPicker.setSizeAdjustPolicy(
-            QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon)
-        
-        self.testComboBox.lineEdit().setClearButtonEnabled(True)
-        
-        # create some more dialog buttons for orchestration
-        self.__startButton = self.buttonBox.addButton(
-            self.tr("Start"), QDialogButtonBox.ButtonRole.ActionRole)
-        
-        self.__startButton.setToolTip(self.tr(
-            "Start the selected testsuite"))
-        self.__startButton.setWhatsThis(self.tr(
-            """<b>Start Test</b>"""
-            """<p>This button starts the test run.</p>"""))
-        
-        self.__startFailedButton = self.buttonBox.addButton(
-            self.tr("Rerun Failed"), QDialogButtonBox.ButtonRole.ActionRole)
-        self.__startFailedButton.setToolTip(
-            self.tr("Reruns failed tests of the selected testsuite"))
-        self.__startFailedButton.setWhatsThis(self.tr(
-            """<b>Rerun Failed</b>"""
-            """<p>This button reruns all failed tests of the most recent"""
-            """ test run.</p>"""))
-        
-        self.__stopButton = self.buttonBox.addButton(
-            self.tr("Stop"), QDialogButtonBox.ButtonRole.ActionRole)
-        self.__stopButton.setToolTip(self.tr("Stop the running unittest"))
-        self.__stopButton.setWhatsThis(self.tr(
-            """<b>Stop Test</b>"""
-            """<p>This button stops a running test.</p>"""))
-        
-        self.setWindowFlags(
-            self.windowFlags() |
-            Qt.WindowType.WindowContextHelpButtonHint
-        )
-        self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
-        self.setWindowTitle(self.tr("Unittest"))
-        
-        try:
-            # we are called from within the eric IDE
-            self.__venvManager = ericApp().getObject("VirtualEnvManager")
-            self.__project = ericApp().getObject("Project")
-            self.__project.projectOpened.connect(self.__projectOpened)
-            self.__project.projectClosed.connect(self.__projectClosed)
-        except KeyError:
-            # we were called as a standalone application
-            from VirtualEnv.VirtualenvManager import VirtualenvManager
-            self.__venvManager = VirtualenvManager(self)
-            self.__venvManager.virtualEnvironmentAdded.connect(
-                self.__populateVenvComboBox)
-            self.__venvManager.virtualEnvironmentRemoved.connect(
-                self.__populateVenvComboBox)
-            self.__venvManager.virtualEnvironmentChanged.connect(
-                self.__populateVenvComboBox)
-            
-            self.__project = None
-        
-        self.__discoverHistory = []
-        self.__fileHistory = []
-        self.__testNameHistory = []
-        self.__recentFramework = ""
-        self.__recentEnvironment = ""
-        self.__failedTests = []
-        
-        self.__editors = []
-        self.__testExecutor = None
-        
-        # connect some signals
-        self.frameworkComboBox.currentIndexChanged.connect(
-            self.__resetResults)
-        self.discoveryPicker.editTextChanged.connect(
-            self.__resetResults)
-        self.testsuitePicker.editTextChanged.connect(
-            self.__resetResults)
-        self.testComboBox.editTextChanged.connect(
-            self.__resetResults)
-        
-        self.__frameworkRegistry = UTFrameworkRegistry()
-        for framework in Frameworks:
-            self.__frameworkRegistry.register(framework)
-        
-        self.__setIdleMode()
-        
-        self.__loadRecent()
-        self.__populateVenvComboBox()
-        
-        if self.__project and self.__project.isOpen():
-            self.venvComboBox.setCurrentText(self.__project.getProjectVenv())
-            self.frameworkComboBox.setCurrentText(
-                self.__project.getProjectTestingFramework())
-            self.__insertDiscovery(self.__project.getProjectPath())
-        else:
-            self.__insertDiscovery("")
-        
-        self.__insertTestFile(testfile)
-        self.__insertTestName("")
-        
-        self.clearHistoriesButton.clicked.connect(self.clearRecent)
-        
-        self.tabWidget.setCurrentIndex(0)
-    
-    def __populateVenvComboBox(self):
-        """
-        Private method to (re-)populate the virtual environments selector.
-        """
-        currentText = self.venvComboBox.currentText()
-        if not currentText:
-            currentText = self.__recentEnvironment
-        
-        self.venvComboBox.clear()
-        self.venvComboBox.addItem("")
-        self.venvComboBox.addItems(
-            sorted(self.__venvManager.getVirtualenvNames()))
-        self.venvComboBox.setCurrentText(currentText)
-    
-    def __populateTestFrameworkComboBox(self):
-        """
-        Private method to (re-)populate the test framework selector.
-        """
-        currentText = self.frameworkComboBox.currentText()
-        if not currentText:
-            currentText = self.__recentFramework
-        
-        self.frameworkComboBox.clear()
-        
-        if bool(self.venvComboBox.currentText()):
-            interpreter = self.__venvManager.getVirtualenvInterpreter(
-                self.venvComboBox.currentText())
-            self.frameworkComboBox.addItem("")
-            for index, (name, executor) in enumerate(
-                sorted(self.__frameworkRegistry.getFrameworks().items()),
-                start=1
-            ):
-                isInstalled = executor.isInstalled(interpreter)
-                entry = (
-                    name
-                    if isInstalled else
-                    self.tr("{0} (not available)").format(name)
-                )
-                self.frameworkComboBox.addItem(entry)
-                self.frameworkComboBox.model().item(index).setEnabled(
-                    isInstalled)
-            
-            self.frameworkComboBox.setCurrentText(self.__recentFramework)
-    
-    def getResultsModel(self):
-        """
-        Public method to get a reference to the model containing the test
-        result data.
-        
-        @return reference to the test results model
-        @rtype TestResultsModel
-        """
-        return self.__resultsModel
-    
-    def hasFailedTests(self):
-        """
-        Public method to check for failed tests.
-        
-        @return flag indicating the existence of failed tests
-        @rtype bool
-        """
-        return bool(self.__resultsModel.getFailedTests())
-        
-    def getFailedTests(self):
-        """
-        Public method to get the list of failed tests (if any).
-        
-        @return list of IDs of failed tests
-        @rtype list of str
-        """
-        return self.__failedTests[:]
-    
-    @pyqtSlot(str)
-    def __insertHistory(self, widget, history, item):
-        """
-        Private slot to insert an item into a history object.
-        
-        @param widget reference to the widget
-        @type QComboBox or EricComboPathPicker
-        @param history array containing the history
-        @type list of str
-        @param item item to be inserted
-        @type str
-        """
-        # prepend the given directory to the discovery picker
-        if item is None:
-            item = ""
-        if item in history:
-            history.remove(item)
-        history.insert(0, item)
-        widget.clear()
-        widget.addItems(history)
-        widget.setEditText(item)
-    
-    @pyqtSlot(str)
-    def __insertDiscovery(self, start):
-        """
-        Private slot to insert the discovery start directory into the
-        discoveryPicker object.
-        
-        @param start start directory name to be inserted
-        @type str
-        """
-        self.__insertHistory(self.discoveryPicker, self.__discoverHistory,
-                             start)
-    
-    @pyqtSlot(str)
-    def setTestFile(self, testFile):
-        """
-        Public slot to set the given test file as the current one.
-        
-        @param testFile path of the test file
-        @type str
-        """
-        if testFile:
-            self.__insertTestFile(testFile)
-        
-        self.discoverCheckBox.setChecked(not bool(testFile))
-        
-        self.tabWidget.setCurrentIndex(0)
-    
-    @pyqtSlot(str)
-    def __insertTestFile(self, prog):
-        """
-        Private slot to insert a test file name into the testsuitePicker
-        object.
-        
-        @param prog test file name to be inserted
-        @type str
-        """
-        self.__insertHistory(self.testsuitePicker, self.__fileHistory,
-                             prog)
-    
-    @pyqtSlot(str)
-    def __insertTestName(self, testName):
-        """
-        Private slot to insert a test name into the testComboBox object.
-        
-        @param testName name of the test to be inserted
-        @type str
-        """
-        self.__insertHistory(self.testComboBox, self.__testNameHistory,
-                             testName)
-    
-    def __loadRecent(self):
-        """
-        Private method to load the most recently used lists.
-        """
-        Preferences.Prefs.rsettings.sync()
-        
-        # 1. recently selected test framework and virtual environment
-        self.__recentEnvironment = Preferences.Prefs.rsettings.value(
-            recentNameUnittestEnvironment, "")
-        self.__recentFramework = Preferences.Prefs.rsettings.value(
-            recentNameUnittestFramework, "")
-        
-        # 2. discovery history
-        self.__discoverHistory = []
-        rs = Preferences.Prefs.rsettings.value(
-            recentNameUnittestDiscoverHistory)
-        if rs is not None:
-            recent = [f for f in Preferences.toList(rs) if os.path.exists(f)]
-            self.__discoverHistory = recent[
-                :Preferences.getDebugger("RecentNumber")]
-        
-        # 3. test file history
-        self.__fileHistory = []
-        rs = Preferences.Prefs.rsettings.value(
-            recentNameUnittestFileHistory)
-        if rs is not None:
-            recent = [f for f in Preferences.toList(rs) if os.path.exists(f)]
-            self.__fileHistory = recent[
-                :Preferences.getDebugger("RecentNumber")]
-        
-        # 4. test name history
-        self.__testNameHistory = []
-        rs = Preferences.Prefs.rsettings.value(
-            recentNameUnittestTestnameHistory)
-        if rs is not None:
-            recent = [n for n in Preferences.toList(rs) if n]
-            self.__testNameHistory = recent[
-                :Preferences.getDebugger("RecentNumber")]
-    
-    def __saveRecent(self):
-        """
-        Private method to save the most recently used lists.
-        """
-        Preferences.Prefs.rsettings.setValue(
-            recentNameUnittestEnvironment, self.__recentEnvironment)
-        Preferences.Prefs.rsettings.setValue(
-            recentNameUnittestFramework, self.__recentFramework)
-        Preferences.Prefs.rsettings.setValue(
-            recentNameUnittestDiscoverHistory, self.__discoverHistory)
-        Preferences.Prefs.rsettings.setValue(
-            recentNameUnittestFileHistory, self.__fileHistory)
-        Preferences.Prefs.rsettings.setValue(
-            recentNameUnittestTestnameHistory, self.__testNameHistory)
-        
-        Preferences.Prefs.rsettings.sync()
-    
-    @pyqtSlot()
-    def clearRecent(self):
-        """
-        Public slot to clear the recently used lists.
-        """
-        # clear histories
-        self.__discoverHistory = []
-        self.__fileHistory = []
-        self.__testNameHistory = []
-        
-        # clear widgets with histories
-        self.discoveryPicker.clear()
-        self.testsuitePicker.clear()
-        self.testComboBox.clear()
-        
-        # sync histories
-        self.__saveRecent()
-    
-    @pyqtSlot()
-    def __resetResults(self):
-        """
-        Private slot to reset the test results tab and data.
-        """
-        self.__totalCount = 0
-        self.__runCount = 0
-        
-        self.progressCounterRunCount.setText("0")
-        self.progressCounterRemCount.setText("0")
-        self.progressProgressBar.setMaximum(100)
-        self.progressProgressBar.setValue(0)
-        
-        self.statusLabel.clear()
-        
-        self.__resultsModel.clear()
-        self.__updateButtonBoxButtons()
-    
-    @pyqtSlot()
-    def __updateButtonBoxButtons(self):
-        """
-        Private slot to update the state of the buttons of the button box.
-        """
-        failedAvailable = bool(self.__resultsModel.getFailedTests())
-        
-        # Start button
-        if self.__mode in (
-            UnittestWidgetModes.IDLE, UnittestWidgetModes.STOPPED
-        ):
-            self.__startButton.setEnabled(
-                bool(self.venvComboBox.currentText()) and
-                bool(self.frameworkComboBox.currentText()) and
-                (
-                    (self.discoverCheckBox.isChecked() and
-                     bool(self.discoveryPicker.currentText())) or
-                    bool(self.testsuitePicker.currentText())
-                )
-            )
-            self.__startButton.setDefault(
-                self.__mode == UnittestWidgetModes.IDLE or
-                not failedAvailable
-            )
-        else:
-            self.__startButton.setEnabled(False)
-            self.__startButton.setDefault(False)
-        
-        # Start Failed button
-        self.__startFailedButton.setEnabled(
-            self.__mode == UnittestWidgetModes.STOPPED and
-            failedAvailable
-        )
-        self.__startFailedButton.setDefault(
-            self.__mode == UnittestWidgetModes.STOPPED and
-            failedAvailable
-        )
-        
-        # Stop button
-        self.__stopButton.setEnabled(
-            self.__mode == UnittestWidgetModes.RUNNING)
-        self.__stopButton.setDefault(
-            self.__mode == UnittestWidgetModes.RUNNING)
-        
-        # Close button
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close
-        ).setEnabled(self.__mode in (
-            UnittestWidgetModes.IDLE, UnittestWidgetModes.STOPPED
-        ))
-    
-    @pyqtSlot()
-    def __updateProgress(self):
-        """
-        Private slot update the progress indicators.
-        """
-        self.progressCounterRunCount.setText(
-            str(self.__runCount))
-        self.progressCounterRemCount.setText(
-            str(self.__totalCount - self.__runCount))
-        self.progressProgressBar.setMaximum(self.__totalCount)
-        self.progressProgressBar.setValue(self.__runCount)
-    
-    @pyqtSlot()
-    def __setIdleMode(self):
-        """
-        Private slot to switch the widget to idle mode.
-        """
-        self.__mode = UnittestWidgetModes.IDLE
-        self.__updateButtonBoxButtons()
-        self.progressGroupBox.hide()
-        self.tabWidget.setCurrentIndex(0)
-    
-    @pyqtSlot()
-    def __setRunningMode(self):
-        """
-        Private slot to switch the widget to running mode.
-        """
-        self.__mode = UnittestWidgetModes.RUNNING
-        
-        self.__totalCount = 0
-        self.__runCount = 0
-        
-        self.__coverageFile = ""
-        # TODO: implement the handling of the 'Show Coverage' button
-        
-        self.sbLabel.setText(self.tr("Running"))
-        self.tabWidget.setCurrentIndex(1)
-        self.__updateButtonBoxButtons()
-        self.__updateProgress()
-        
-        self.progressGroupBox.show()
-    
-    @pyqtSlot()
-    def __setStoppedMode(self):
-        """
-        Private slot to switch the widget to stopped mode.
-        """
-        self.__mode = UnittestWidgetModes.STOPPED
-        if self.__totalCount == 0:
-            self.progressProgressBar.setMaximum(100)
-        
-        self.progressGroupBox.hide()
-        
-        self.__updateButtonBoxButtons()
-        
-        self.unittestStopped.emit()
-        
-        self.raise_()
-        self.activateWindow()
-    
-    @pyqtSlot(bool)
-    def on_discoverCheckBox_toggled(self, checked):
-        """
-        Private slot handling state changes of the 'discover' checkbox.
-        
-        @param checked state of the checkbox
-        @type bool
-        """
-        if not bool(self.discoveryPicker.currentText()):
-            if self.__project and self.__project.isOpen():
-                self.__insertDiscovery(self.__project.getProjectPath())
-            else:
-                self.__insertDiscovery(
-                    Preferences.getMultiProject("Workspace"))
-        
-        self.__resetResults()
-    
-    @pyqtSlot()
-    def on_testsuitePicker_aboutToShowPathPickerDialog(self):
-        """
-        Private slot called before the test file selection dialog is shown.
-        """
-        if self.__project:
-            # we were called from within eric
-            py3Extensions = ' '.join([
-                "*{0}".format(ext)
-                for ext in
-                ericApp().getObject("DebugServer").getExtensions('Python3')
-            ])
-            fileFilter = self.tr(
-                "Python3 Files ({0});;All Files (*)"
-            ).format(py3Extensions)
-        else:
-            # standalone application
-            fileFilter = self.tr("Python Files (*.py);;All Files (*)")
-        self.testsuitePicker.setFilters(fileFilter)
-        
-        defaultDirectory = (
-            self.__project.getProjectPath()
-            if self.__project and self.__project.isOpen() else
-            Preferences.getMultiProject("Workspace")
-        )
-        if not defaultDirectory:
-            defaultDirectory = os.path.expanduser("~")
-        self.testsuitePicker.setDefaultDirectory(defaultDirectory)
-    
-    @pyqtSlot(QAbstractButton)
-    def on_buttonBox_clicked(self, button):
-        """
-        Private slot called by a button of the button box clicked.
-        
-        @param button button that was clicked
-        @type QAbstractButton
-        """
-        if button == self.__startButton:
-            self.startTests()
-            self.__saveRecent()
-        elif button == self.__stopButton:
-            self.__stopTests()
-        elif button == self.__startFailedButton:
-            self.startTests(failedOnly=True)
-    
-    @pyqtSlot(int)
-    def on_venvComboBox_currentIndexChanged(self, index):
-        """
-        Private slot handling the selection of a virtual environment.
-        
-        @param index index of the selected environment
-        @type int
-        """
-        self.__populateTestFrameworkComboBox()
-        self.__updateButtonBoxButtons()
-        
-        self.versionsButton.setEnabled(bool(self.venvComboBox.currentText()))
-    
-    @pyqtSlot()
-    def on_versionsButton_clicked(self):
-        """
-        Private slot to show the versions of available plugins.
-        """
-        venvName = self.venvComboBox.currentText()
-        if venvName:
-            headerText = self.tr("<h3>Versions of Frameworks and their"
-                                 " Plugins</h3>")
-            versionsText = ""
-            interpreter = self.__venvManager.getVirtualenvInterpreter(venvName)
-            for framework in sorted(
-                self.__frameworkRegistry.getFrameworks().keys()
-            ):
-                executor = self.__frameworkRegistry.createExecutor(
-                    framework, self)
-                versions = executor.getVersions(interpreter)
-                if versions:
-                    txt = "<p><strong>{0} {1}</strong>".format(
-                        versions["name"], versions["version"])
-                    
-                    if versions["plugins"]:
-                        txt += "<table>"
-                        for pluginVersion in versions["plugins"]:
-                            txt += self.tr(
-                                "<tr><td>{0}</td><td>{1}</td></tr>"
-                            ).format(
-                                pluginVersion["name"], pluginVersion["version"]
-                            )
-                        txt += "</table>"
-                    txt += "</p>"
-                    
-                    versionsText += txt
-            
-            if not versionsText:
-                versionsText = self.tr("No version information available.")
-            
-            EricMessageBox.information(
-                self,
-                self.tr("Versions"),
-                headerText + versionsText
-            )
-    
-    @pyqtSlot()
-    def startTests(self, failedOnly=False):
-        """
-        Public slot to start the test run.
-        
-        @param failedOnly flag indicating to run only failed tests
-        @type bool
-        """
-        if self.__mode == UnittestWidgetModes.RUNNING:
-            return
-        
-        self.__recentEnvironment = self.venvComboBox.currentText()
-        self.__recentFramework = self.frameworkComboBox.currentText()
-        
-        self.__failedTests = (
-            self.__resultsModel.getFailedTests()
-            if failedOnly else
-            []
-        )
-        discover = self.discoverCheckBox.isChecked()
-        if discover:
-            discoveryStart = self.discoveryPicker.currentText()
-            testFileName = ""
-            testName = ""
-            
-            if discoveryStart:
-                self.__insertDiscovery(discoveryStart)
-        else:
-            discoveryStart = ""
-            testFileName = self.testsuitePicker.currentText()
-            if testFileName:
-                self.__insertTestFile(testFileName)
-            testName = self.testComboBox.currentText()
-            if testName:
-                self.__insertTestName(testName)
-            if testFileName and not testName:
-                testName = "suite"
-        
-        self.sbLabel.setText(self.tr("Preparing Testsuite"))
-        QCoreApplication.processEvents()
-        
-        interpreter = self.__venvManager.getVirtualenvInterpreter(
-            self.__recentEnvironment)
-        config = UTTestConfig(
-            interpreter=interpreter,
-            discover=self.discoverCheckBox.isChecked(),
-            discoveryStart=discoveryStart,
-            testFilename=testFileName,
-            testName=testName,
-            failFast=self.failfastCheckBox.isChecked(),
-            failedOnly=failedOnly,
-            collectCoverage=self.coverageCheckBox.isChecked(),
-            eraseCoverage=self.coverageEraseCheckBox.isChecked(),
-        )
-        
-        self.__testExecutor = self.__frameworkRegistry.createExecutor(
-            self.__recentFramework, self)
-        self.__testExecutor.collected.connect(self.__testsCollected)
-        self.__testExecutor.collectError.connect(self.__testsCollectError)
-        self.__testExecutor.startTest.connect(self.__testStarted)
-        self.__testExecutor.testResult.connect(self.__processTestResult)
-        self.__testExecutor.testFinished.connect(self.__testProcessFinished)
-        self.__testExecutor.testRunFinished.connect(self.__testRunFinished)
-        self.__testExecutor.stop.connect(self.__testsStopped)
-        self.__testExecutor.coverageDataSaved.connect(self.__coverageData)
-        self.__testExecutor.testRunAboutToBeStarted.connect(
-            self.__testRunAboutToBeStarted)
-        
-        self.__setRunningMode()
-        self.__testExecutor.start(config, [])
-    
-    @pyqtSlot()
-    def __stopTests(self):
-        """
-        Private slot to stop the current test run.
-        """
-        self.__testExecutor.stopIfRunning()
-    
-    @pyqtSlot(list)
-    def __testsCollected(self, testNames):
-        """
-        Private slot handling the 'collected' signal of the executor.
-        
-        @param testNames list of tuples containing the test id and test name
-            of collected tests
-        @type list of tuple of (str, str)
-        """
-        testResults = [
-            UTTestResult(
-                category=ResultCategory.PENDING,
-                status=self.tr("pending"),
-                name=name,
-                id=id,
-                message=desc,
-            ) for id, name, desc in testNames
-        ]
-        self.__resultsModel.setTestResults(testResults)
-        
-        self.__totalCount = len(testResults)
-        self.__updateProgress()
-    
-    @pyqtSlot(list)
-    def __testsCollectError(self, errors):
-        """
-        Private slot handling the 'collectError' signal of the executor.
-        
-        @param errors list of tuples containing the test name and a description
-            of the error
-        @type list of tuple of (str, str)
-        """
-        testResults = []
-        
-        for testFile, error in errors:
-            if testFile:
-                testResults.append(UTTestResult(
-                    category=ResultCategory.FAIL,
-                    status=self.tr("Failure"),
-                    name=testFile,
-                    id=testFile,
-                    message=self.tr("Collection Error"),
-                    extra=error.splitlines()
-                ))
-            else:
-                EricMessageBox.critical(
-                    self,
-                    self.tr("Collection Error"),
-                    self.tr(
-                        "<p>There was an error while collecting unit tests."
-                        "</p><p>{0}</p>"
-                    ).format("<br/>".join(error.splitlines()))
-                )
-        
-        if testResults:
-            self.__resultsModel.addTestResults(testResults)
-    
-    @pyqtSlot(tuple)
-    def __testStarted(self, test):
-        """
-        Private slot handling the 'startTest' signal of the executor.
-        
-        @param test tuple containing the id, name and short description of the
-            tests about to be run
-        @type tuple of (str, str, str)
-        """
-        self.__resultsModel.updateTestResults([
-            UTTestResult(
-                category=ResultCategory.RUNNING,
-                status=self.tr("running"),
-                id=test[0],
-                name=test[1],
-                message="" if test[2] is None else test[2],
-            )
-        ])
-    
-    @pyqtSlot(UTTestResult)
-    def __processTestResult(self, result):
-        """
-        Private slot to handle the receipt of a test result object.
-        
-        @param result test result object
-        @type UTTestResult
-        """
-        if not result.subtestResult:
-            self.__runCount += 1
-        self.__updateProgress()
-        
-        self.__resultsModel.updateTestResults([result])
-    
-    @pyqtSlot(list, str)
-    def __testProcessFinished(self, results, output):
-        """
-        Private slot to handle the 'testFinished' signal of the executor.
-        
-        @param results list of test result objects (if not sent via the
-            'testResult' signal
-        @type list of UTTestResult
-        @param output string containing the test process output (if any)
-        @type str
-        """
-        self.__setStoppedMode()
-        self.__testExecutor = None
-    
-    @pyqtSlot(int, float)
-    def __testRunFinished(self, noTests, duration):
-        """
-        Private slot to handle the 'testRunFinished' signal of the executor.
-        
-        @param noTests number of tests run by the executor
-        @type int
-        @param duration time needed in seconds to run the tests
-        @type float
-        """
-        self.sbLabel.setText(
-            self.tr("Ran %n test(s) in {0}s", "", noTests).format(
-                locale.format_string("%.3f", duration, grouping=True)
-            )
-        )
-        
-        self.__setStoppedMode()
-    
-    @pyqtSlot()
-    def __testsStopped(self):
-        """
-        Private slot to handle the 'stop' signal of the executor.
-        """
-        self.sbLabel.setText(self.tr("Ran %n test(s)", "", self.__runCount))
-        
-        self.__setStoppedMode()
-    
-    @pyqtSlot()
-    def __testRunAboutToBeStarted(self):
-        """
-        Private slot to handle the 'testRunAboutToBeStarted' signal of the
-        executor.
-        """
-        self.__resultsModel.clear()
-    
-    @pyqtSlot(str)
-    def __coverageData(self, coverageFile):
-        """
-        Private slot to handle the 'coverageData' signal of the executor.
-        
-        @param coverageFile file containing the coverage data
-        @type str
-        """
-        self.__coverageFile = coverageFile
-        
-        # TODO: implement the handling of the 'Show Coverage' button
-    
-    @pyqtSlot(str)
-    def __setStatusLabel(self, statusText):
-        """
-        Private slot to set the status label to the text sent by the model.
-        
-        @param statusText text to be shown
-        @type str
-        """
-        self.statusLabel.setText(f"<b>{statusText}</b>")
-    
-    @pyqtSlot()
-    def __projectOpened(self):
-        """
-        Private slot to handle a project being opened.
-        """
-        self.venvComboBox.setCurrentText(self.__project.getProjectVenv())
-        self.frameworkComboBox.setCurrentText(
-            self.__project.getProjectTestingFramework())
-        self.__insertDiscovery(self.__project.getProjectPath())
-    
-    @pyqtSlot()
-    def __projectClosed(self):
-        """
-        Private slot to handle a project being closed.
-        """
-        self.venvComboBox.setCurrentText("")
-        self.frameworkComboBox.setCurrentText("")
-        self.__insertDiscovery("")
-    
-    @pyqtSlot(str, int)
-    def __showSource(self, filename, lineno):
-        """
-        Private slot to show the source of a traceback in an editor.
-        
-        @param filename file name of the file to be shown
-        @type str
-        @param lineno line number to go to in the file
-        @type int
-        """
-        if self.__project:
-            # running as part of eric IDE
-            self.unittestFile.emit(filename, lineno, True)
-        else:
-            self.__openEditor(filename, lineno)
-    
-    def __openEditor(self, filename, linenumber):
-        """
-        Private method to open an editor window for the given file.
-        
-        Note: This method opens an editor window when the unittest dialog
-        is called as a standalone application.
-        
-        @param filename path of the file to be opened
-        @type str
-        @param linenumber line number to place the cursor at
-        @type int
-        """
-        from QScintilla.MiniEditor import MiniEditor
-        editor = MiniEditor(filename, "Python3", self)
-        editor.gotoLine(linenumber)
-        editor.show()
-        
-        self.__editors.append(editor)
-    
-    def closeEvent(self, event):
-        """
-        Protected method to handle the close event.
-        
-        @param event close event
-        @type QCloseEvent
-        """
-        event.accept()
-        
-        for editor in self.__editors:
-            with contextlib.suppress(Exception):
-                editor.close()
-
-
-class UnittestWindow(EricMainWindow):
-    """
-    Main window class for the standalone dialog.
-    """
-    def __init__(self, testfile=None, parent=None):
-        """
-        Constructor
-        
-        @param testfile file name of the test script to open
-        @type str
-        @param parent reference to the parent widget
-        @type QWidget
-        """
-        super().__init__(parent)
-        self.__cw = UnittestWidget(testfile=testfile, parent=self)
-        self.__cw.installEventFilter(self)
-        size = self.__cw.size()
-        self.setCentralWidget(self.__cw)
-        self.resize(size)
-        
-        self.setStyle(Preferences.getUI("Style"),
-                      Preferences.getUI("StyleSheet"))
-        
-        self.__cw.buttonBox.accepted.connect(self.close)
-        self.__cw.buttonBox.rejected.connect(self.close)
-    
-    def eventFilter(self, obj, event):
-        """
-        Public method to filter events.
-        
-        @param obj reference to the object the event is meant for (QObject)
-        @param event reference to the event object (QEvent)
-        @return flag indicating, whether the event was handled (boolean)
-        """
-        if event.type() == QEvent.Type.Close:
-            QCoreApplication.exit(0)
-            return True
-        
-        return False
-
-
-def clearSavedHistories(self):
-    """
-    Function to clear the saved history lists.
-    """
-    Preferences.Prefs.rsettings.setValue(
-        recentNameUnittestDiscoverHistory, [])
-    Preferences.Prefs.rsettings.setValue(
-        recentNameUnittestFileHistory, [])
-    Preferences.Prefs.rsettings.setValue(
-        recentNameUnittestTestnameHistory, [])
-    
-    Preferences.Prefs.rsettings.sync()

eric ide

mercurial