--- a/PyUnit/UnittestDialog.py Sun Mar 24 12:57:08 2019 +0100 +++ b/PyUnit/UnittestDialog.py Sun Mar 24 16:11:19 2019 +0100 @@ -75,6 +75,7 @@ self.discoveryPicker.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLength) + # TODO: add a "Discover" button enabled upon selection of 'auto-discovery' self.startButton = self.buttonBox.addButton( self.tr("Start"), QDialogButtonBox.ActionRole) self.startButton.setToolTip(self.tr( @@ -111,12 +112,20 @@ if dbs: self.ui = ui - self.venvComboBox.addItem("") - self.venvComboBox.addItems( - sorted(e5App().getObject("VirtualEnvManager") - .getVirtualenvNames())) - self.venvComboBox.setVisible(bool(self.__dbs)) - self.venvLabel.setVisible(bool(self.__dbs)) + # virtual environment manager is only used in the integrated + # variant + self.__venvManager = e5App().getObject("VirtualEnvManager") + self.__populateVenvComboBox() + self.__venvManager.virtualEnvironmentAdded.connect( + self.__populateVenvComboBox) + self.__venvManager.virtualEnvironmentRemoved.connect( + self.__populateVenvComboBox) + self.__venvManager.virtualEnvironmentChanged.connect( + self.__populateVenvComboBox) + else: + self.__venvManager = None + self.venvComboBox.setVisible(bool(self.__venvManager)) + self.venvLabel.setVisible(bool(self.__venvManager)) self.__setProgressColor("green") self.progressLed.setDarkFactor(150) @@ -165,6 +174,20 @@ if evt.key() == Qt.Key_Escape and self.__dbs: self.close() + def __populateVenvComboBox(self): + """ + Private method to (re-)populate the virtual environments selector. + """ + currentText = self.venvComboBox.currentText() + self.venvComboBox.clear() + self.venvComboBox.addItem("") + self.venvComboBox.addItems( + sorted(self.__venvManager.getVirtualenvNames())) + index = self.venvComboBox.findText(currentText) + if index < 0: + index = 0 + self.venvComboBox.setCurrentIndex(index) + def __setProgressColor(self, color): """ Private methode to set the color of the progress color label. @@ -264,6 +287,7 @@ project = e5App().getObject("Project") if self.__forProject and project.isOpen(): defaultDirectory = project.getProjectPath() + self.testsuitePicker.setDefaultDirectory(defaultDirectory) @pyqtSlot(str) def on_testsuitePicker_pathSelected(self, suite): @@ -303,61 +327,68 @@ @param button button that was clicked (QAbstractButton) """ if button == self.startButton: - self.on_startButton_clicked() + self.startTests() elif button == self.stopButton: - self.on_stopButton_clicked() + self.__stopTests() elif button == self.startFailedButton: - self.on_startButton_clicked(failedOnly=True) + self.startTests(failedOnly=True) @pyqtSlot() - def on_startButton_clicked(self, failedOnly=False): + def startTests(self, failedOnly=False): """ - Private slot to start the test. + Public slot to start the test. @keyparam failedOnly flag indicating to run only failed tests (boolean) """ + # TODO: run only failed test ignoring test parameters when failedOnly is set if self.running: return discover = self.discoverCheckBox.isChecked() if discover: discoveryStart = self.discoveryPicker.currentText() - prog = "" + testFileName = "" + testName = "" else: discoveryStart = "" - prog = self.testsuitePicker.currentText() + testFileName = self.testsuitePicker.currentText() + testName = self.testComboBox.currentText() + if testName: + self.insertTestName(testName) + if testFileName and not testName: + testName = "suite" - if not prog and not discover: + if not discover and not testFileName and not testName: E5MessageBox.critical( self, self.tr("Unittest"), - self.tr("You must enter a test suite file or select" - " auto-discovery.")) + self.tr("You must select auto-discovery or enter a test suite" + " file or a dotted test name.")) return # prepend the selected file to the testsuite combobox - self.insertProg(prog) + self.insertProg(testFileName) self.sbLabel.setText(self.tr("Preparing Testsuite")) QApplication.processEvents() if discover: - testFunctionName = "" self.testName = self.tr("Unittest with auto-discovery") else: - testFunctionName = self.testComboBox.currentText() - if testFunctionName: - self.insertTestName(testFunctionName) + # build the module name from the filename without extension + if testFileName: + self.testName = os.path.splitext( + os.path.basename(testFileName))[0] + elif testName: + self.testName = testName else: - testFunctionName = "suite" - - # build the module name from the filename without extension - self.testName = os.path.splitext(os.path.basename(prog))[0] + self.testName = self.tr("<Unnamed Test>") if self.__dbs: + venvName = self.venvComboBox.currentText() + # we are cooperating with the eric6 IDE project = e5App().getObject("Project") - if self.__forProject and project.isOpen() and \ - (discover or project.isProjectSource(prog)): + if self.__forProject: mainScript = os.path.abspath(project.getMainScript(True)) clientType = project.getProjectLanguage() if mainScript: @@ -365,6 +396,7 @@ else: workdir = project.getProjectPath() sysPath = [workdir] + coverageFile = os.path.splitext(mainScript)[0] if discover and not discoveryStart: discoveryStart = workdir else: @@ -376,14 +408,18 @@ self.tr("You must enter a start directory for" " auto-discovery.")) return - mainScript = os.path.join(discoveryStart, "unittest") + + coverageFile = os.path.join(discoveryStart, "unittest") workdir = "" - # assume Python3 for auto-discovery - clientType = "Python3" - else: - mainScript = os.path.abspath(prog) + clientType = \ + self.__venvManager.getVirtualenvVariant(venvName) + if not clientType: + # assume Python 3 + clientType = "Python3" + elif testFileName: + mainScript = os.path.abspath(testFileName) + flags = Utilities.extractFlagsFromFile(mainScript) workdir = os.path.dirname(mainScript) - flags = Utilities.extractFlagsFromFile(mainScript) if mainScript.endswith( tuple(Preferences.getPython("PythonExtensions"))) or \ ("FileType" in flags and @@ -392,24 +428,33 @@ else: # if it is not Python2 it must be Python3! clientType = "Python3" + coverageFile = os.path.splitext(mainScript)[0] + else: + coverageFile = os.path.abspath("unittest") + workdir = "" + clientType = \ + self.__venvManager.getVirtualenvVariant(venvName) + if not clientType: + # assume Python 3 + clientType = "Python3" sysPath = [] if not discover and failedOnly and self.__failedTests: - failed = [t.split(".", 1)[1] for t in self.__failedTests] + failed = self.__failedTests[:] else: failed = [] self.__failedTests = [] self.__dbs.remoteUTPrepare( - prog, self.testName, testFunctionName, failed, - self.coverageCheckBox.isChecked(), mainScript, + testFileName, self.testName, testName, failed, + self.coverageCheckBox.isChecked(), coverageFile, self.coverageEraseCheckBox.isChecked(), clientType=clientType, forProject=self.__forProject, workdir=workdir, - venvName=self.venvComboBox.currentText(), syspath=sysPath, + venvName=venvName, syspath=sysPath, discover=discover, discoveryStart=discoveryStart) else: - # TODO: add discovery # we are running as an application - sys.path = [os.path.dirname(os.path.abspath(prog))] + \ - self.savedSysPath + if testFileName: + sys.path = [os.path.dirname(os.path.abspath(testFileName))] + \ + self.savedSysPath # clean up list of imported modules to force a reimport upon # running the test @@ -432,22 +477,23 @@ return test = unittest.defaultTestLoader.discover(discoveryStart) +# testsList = self.__assembleTestCasesList(test) else: - module = __import__(self.testName) - try: - if failedOnly and self.__failedTests: - test = \ - unittest.defaultTestLoader.loadTestsFromNames( - [t.split(".", 1)[1] - for t in self.__failedTests], - module) + if testFileName: + module = __import__(self.testName) + else: + module = None + if failedOnly and self.__failedTests: + if module: + failed = [t.split(".", 1)[1] + for t in self.__failedTests] else: - test = \ - unittest.defaultTestLoader.loadTestsFromName( - testFunctionName, module) - except AttributeError: - test = unittest.defaultTestLoader.loadTestsFromModule( - module) + failed = self.__failedTests[:] + test = unittest.defaultTestLoader.loadTestsFromNames( + failed, module) + else: + test = unittest.defaultTestLoader.loadTestsFromName( + testName, module) except Exception: exc_type, exc_value, exc_tb = sys.exc_info() E5MessageBox.critical( @@ -464,8 +510,9 @@ if self.coverageCheckBox.isChecked(): if discover: covname = os.path.join(discoveryStart, "unittest") - elif prog: - covname = os.path.splitext(os.path.abspath(prog))[0] + elif testFileName: + covname = \ + os.path.splitext(os.path.abspath(testFileName))[0] else: covname = "unittest" @@ -489,6 +536,25 @@ self.__setStoppedMode() sys.path = self.savedSysPath + def __assembleTestCasesList(self, suite): + """ + Private method to assemble a list of test cases included in a test + suite. + + @param suite test suite to be inspected + @type unittest.TestSuite + @return list of tuples containing the test case ID and short + description + @rtype list of tuples of (str, str) + """ + testCases = [] + for test in suite: + if isinstance(test, unittest.TestSuite): + testCases.extend(self.__assembleTestCasesList(test)) + else: + testCases.append((test.id(), test.shortDescription())) + return testCases + def __UTPrepared(self, nrTests, exc_type, exc_value): """ Private slot to handle the utPrepared signal. @@ -514,7 +580,7 @@ self.__dbs.remoteUTRun() @pyqtSlot() - def on_stopButton_clicked(self): + def __stopTests(self): """ Private slot to stop the test. """ @@ -925,6 +991,9 @@ 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): """