98 |
98 |
99 self.__startButton.setToolTip(self.tr( |
99 self.__startButton.setToolTip(self.tr( |
100 "Start the selected testsuite")) |
100 "Start the selected testsuite")) |
101 self.__startButton.setWhatsThis(self.tr( |
101 self.__startButton.setWhatsThis(self.tr( |
102 """<b>Start Test</b>""" |
102 """<b>Start Test</b>""" |
103 """<p>This button starts the selected testsuite.</p>""")) |
103 """<p>This button starts the test run.</p>""")) |
104 |
104 |
105 # TODO: implement "Rerun Failed" |
105 self.__startFailedButton = self.buttonBox.addButton( |
106 ## self.__startFailedButton = self.buttonBox.addButton( |
106 self.tr("Rerun Failed"), QDialogButtonBox.ButtonRole.ActionRole) |
107 ## self.tr("Rerun Failed"), QDialogButtonBox.ButtonRole.ActionRole) |
107 self.__startFailedButton.setToolTip( |
108 ## self.__startFailedButton.setToolTip( |
108 self.tr("Reruns failed tests of the selected testsuite")) |
109 ## self.tr("Reruns failed tests of the selected testsuite")) |
109 self.__startFailedButton.setWhatsThis(self.tr( |
110 ## self.__startFailedButton.setWhatsThis(self.tr( |
110 """<b>Rerun Failed</b>""" |
111 ## """<b>Rerun Failed</b>""" |
111 """<p>This button reruns all failed tests of the most recent""" |
112 ## """<p>This button reruns all failed tests of the selected""" |
112 """ test run.</p>""")) |
113 ## """ testsuite.</p>""")) |
113 |
114 ## |
|
115 self.__stopButton = self.buttonBox.addButton( |
114 self.__stopButton = self.buttonBox.addButton( |
116 self.tr("Stop"), QDialogButtonBox.ButtonRole.ActionRole) |
115 self.tr("Stop"), QDialogButtonBox.ButtonRole.ActionRole) |
117 self.__stopButton.setToolTip(self.tr("Stop the running unittest")) |
116 self.__stopButton.setToolTip(self.tr("Stop the running unittest")) |
118 self.__stopButton.setWhatsThis(self.tr( |
117 self.__stopButton.setWhatsThis(self.tr( |
119 """<b>Stop Test</b>""" |
118 """<b>Stop Test</b>""" |
120 """<p>This button stops a running unittest.</p>""")) |
119 """<p>This button stops a running test.</p>""")) |
121 |
|
122 self.__stopButton.setEnabled(False) |
|
123 self.__startButton.setDefault(True) |
|
124 self.__startButton.setEnabled(False) |
|
125 ## self.__startFailedButton.setEnabled(False) |
|
126 |
120 |
127 self.setWindowFlags( |
121 self.setWindowFlags( |
128 self.windowFlags() | |
122 self.windowFlags() | |
129 Qt.WindowType.WindowContextHelpButtonHint |
123 Qt.WindowType.WindowContextHelpButtonHint |
130 ) |
124 ) |
146 self.__discoverHistory = [] |
140 self.__discoverHistory = [] |
147 self.__fileHistory = [] |
141 self.__fileHistory = [] |
148 self.__testNameHistory = [] |
142 self.__testNameHistory = [] |
149 self.__recentFramework = "" |
143 self.__recentFramework = "" |
150 self.__recentEnvironment = "" |
144 self.__recentEnvironment = "" |
151 |
145 self.__failedTests = [] |
152 self.__failedTests = set() |
|
153 |
146 |
154 self.__editors = [] |
147 self.__editors = [] |
155 self.__testExecutor = None |
148 self.__testExecutor = None |
156 |
149 |
157 # connect some signals |
150 # connect some signals |
158 self.frameworkComboBox.currentIndexChanged.connect( |
151 self.frameworkComboBox.currentIndexChanged.connect( |
159 self.__updateButtonBoxButtons) |
152 self.__resetResults) |
160 self.discoverCheckBox.toggled.connect( |
153 self.discoverCheckBox.toggled.connect( |
161 self.__updateButtonBoxButtons) |
154 self.__resetResults) |
162 self.discoveryPicker.editTextChanged.connect( |
155 self.discoveryPicker.editTextChanged.connect( |
163 self.__updateButtonBoxButtons) |
156 self.__resetResults) |
164 self.testsuitePicker.editTextChanged.connect( |
157 self.testsuitePicker.editTextChanged.connect( |
165 self.__updateButtonBoxButtons) |
158 self.__resetResults) |
|
159 self.testComboBox.editTextChanged.connect( |
|
160 self.__resetResults) |
166 |
161 |
167 self.__frameworkRegistry = UTFrameworkRegistry() |
162 self.__frameworkRegistry = UTFrameworkRegistry() |
168 for framework in Frameworks: |
163 for framework in Frameworks: |
169 self.__frameworkRegistry.register(framework) |
164 self.__frameworkRegistry.register(framework) |
170 |
165 |
233 self.frameworkComboBox.model().item(index).setEnabled( |
228 self.frameworkComboBox.model().item(index).setEnabled( |
234 isInstalled) |
229 isInstalled) |
235 |
230 |
236 self.frameworkComboBox.setCurrentText(self.__recentFramework) |
231 self.frameworkComboBox.setCurrentText(self.__recentFramework) |
237 |
232 |
|
233 def getResultsModel(self): |
|
234 """ |
|
235 Public method to get a reference to the model containing the test |
|
236 result data. |
|
237 |
|
238 @return reference to the test results model |
|
239 @rtype TestResultsModel |
|
240 """ |
|
241 return self.__resultsModel |
|
242 |
|
243 def getFailedTests(self): |
|
244 """ |
|
245 Public method to get the list of failed tests (if any). |
|
246 |
|
247 @return list of IDs of failed tests |
|
248 @rtype list of str |
|
249 """ |
|
250 return self.__failedTests[:] |
|
251 |
238 @pyqtSlot(str) |
252 @pyqtSlot(str) |
239 def __insertHistory(self, widget, history, item): |
253 def __insertHistory(self, widget, history, item): |
240 """ |
254 """ |
241 Private slot to insert an item into a history object. |
255 Private slot to insert an item into a history object. |
242 |
256 |
368 self.testComboBox.clear() |
382 self.testComboBox.clear() |
369 |
383 |
370 # sync histories |
384 # sync histories |
371 self.__saveRecent() |
385 self.__saveRecent() |
372 |
386 |
|
387 @pyqtSlot() |
|
388 def __resetResults(self): |
|
389 """ |
|
390 Private slot to reset the test results tab and data. |
|
391 """ |
|
392 self.__totalCount = 0 |
|
393 self.__runCount = 0 |
|
394 |
|
395 self.progressCounterRunCount.setText("0") |
|
396 self.progressCounterRemCount.setText("0") |
|
397 self.progressProgressBar.setMaximum(100) |
|
398 self.progressProgressBar.setValue(0) |
|
399 |
|
400 self.statusLabel.clear() |
|
401 |
|
402 self.__resultsModel.clear() |
|
403 self.__updateButtonBoxButtons() |
|
404 |
|
405 @pyqtSlot() |
373 def __updateButtonBoxButtons(self): |
406 def __updateButtonBoxButtons(self): |
374 """ |
407 """ |
375 Private method to update the state of the buttons of the button box. |
408 Private slot to update the state of the buttons of the button box. |
376 """ |
409 """ |
377 failedAvailable = bool(self.__failedTests) |
410 failedAvailable = bool(self.__resultsModel.getFailedTests()) |
378 |
411 |
379 # Start button |
412 # Start button |
380 if self.__mode in ( |
413 if self.__mode in ( |
381 UnittestWidgetModes.IDLE, UnittestWidgetModes.STOPPED |
414 UnittestWidgetModes.IDLE, UnittestWidgetModes.STOPPED |
382 ): |
415 ): |
396 else: |
429 else: |
397 self.__startButton.setEnabled(False) |
430 self.__startButton.setEnabled(False) |
398 self.__startButton.setDefault(False) |
431 self.__startButton.setDefault(False) |
399 |
432 |
400 # Start Failed button |
433 # Start Failed button |
401 # TODO: not implemented yet (Start Failed button) |
434 self.__startFailedButton.setEnabled( |
|
435 self.__mode == UnittestWidgetModes.STOPPED and |
|
436 failedAvailable |
|
437 ) |
|
438 self.__startFailedButton.setDefault( |
|
439 self.__mode == UnittestWidgetModes.STOPPED and |
|
440 failedAvailable |
|
441 ) |
402 |
442 |
403 # Stop button |
443 # Stop button |
404 self.__stopButton.setEnabled( |
444 self.__stopButton.setEnabled( |
405 self.__mode == UnittestWidgetModes.RUNNING) |
445 self.__mode == UnittestWidgetModes.RUNNING) |
406 self.__stopButton.setDefault( |
446 self.__stopButton.setDefault( |
411 QDialogButtonBox.StandardButton.Close |
451 QDialogButtonBox.StandardButton.Close |
412 ).setEnabled(self.__mode in ( |
452 ).setEnabled(self.__mode in ( |
413 UnittestWidgetModes.IDLE, UnittestWidgetModes.STOPPED |
453 UnittestWidgetModes.IDLE, UnittestWidgetModes.STOPPED |
414 )) |
454 )) |
415 |
455 |
|
456 @pyqtSlot() |
416 def __updateProgress(self): |
457 def __updateProgress(self): |
417 """ |
458 """ |
418 Private method update the progress indicators. |
459 Private slot update the progress indicators. |
419 """ |
460 """ |
420 self.progressCounterRunCount.setText( |
461 self.progressCounterRunCount.setText( |
421 str(self.__runCount)) |
462 str(self.__runCount)) |
422 self.progressCounterRemCount.setText( |
463 self.progressCounterRemCount.setText( |
423 str(self.__totalCount - self.__runCount)) |
464 str(self.__totalCount - self.__runCount)) |
424 self.progressProgressBar.setMaximum(self.__totalCount) |
465 self.progressProgressBar.setMaximum(self.__totalCount) |
425 self.progressProgressBar.setValue(self.__runCount) |
466 self.progressProgressBar.setValue(self.__runCount) |
426 |
467 |
|
468 @pyqtSlot() |
427 def __setIdleMode(self): |
469 def __setIdleMode(self): |
428 """ |
470 """ |
429 Private method to switch the widget to idle mode. |
471 Private slot to switch the widget to idle mode. |
430 """ |
472 """ |
431 self.__mode = UnittestWidgetModes.IDLE |
473 self.__mode = UnittestWidgetModes.IDLE |
432 self.__updateButtonBoxButtons() |
474 self.__updateButtonBoxButtons() |
|
475 self.progressGroupBox.hide() |
433 self.tabWidget.setCurrentIndex(0) |
476 self.tabWidget.setCurrentIndex(0) |
434 |
477 |
|
478 @pyqtSlot() |
435 def __setRunningMode(self): |
479 def __setRunningMode(self): |
436 """ |
480 """ |
437 Private method to switch the widget to running mode. |
481 Private slot to switch the widget to running mode. |
438 """ |
482 """ |
439 self.__mode = UnittestWidgetModes.RUNNING |
483 self.__mode = UnittestWidgetModes.RUNNING |
440 |
484 |
441 self.__totalCount = 0 |
485 self.__totalCount = 0 |
442 self.__runCount = 0 |
486 self.__runCount = 0 |
447 self.sbLabel.setText(self.tr("Running")) |
491 self.sbLabel.setText(self.tr("Running")) |
448 self.tabWidget.setCurrentIndex(1) |
492 self.tabWidget.setCurrentIndex(1) |
449 self.__updateButtonBoxButtons() |
493 self.__updateButtonBoxButtons() |
450 self.__updateProgress() |
494 self.__updateProgress() |
451 |
495 |
452 self.__resultsModel.clear() |
496 self.progressGroupBox.show() |
453 |
497 |
|
498 @pyqtSlot() |
454 def __setStoppedMode(self): |
499 def __setStoppedMode(self): |
455 """ |
500 """ |
456 Private method to switch the widget to stopped mode. |
501 Private slot to switch the widget to stopped mode. |
457 """ |
502 """ |
458 self.__mode = UnittestWidgetModes.STOPPED |
503 self.__mode = UnittestWidgetModes.STOPPED |
|
504 if self.__totalCount == 0: |
|
505 self.progressProgressBar.setMaximum(100) |
|
506 |
|
507 self.progressGroupBox.hide() |
459 |
508 |
460 self.__updateButtonBoxButtons() |
509 self.__updateButtonBoxButtons() |
461 |
510 |
462 self.raise_() |
511 self.raise_() |
463 self.activateWindow() |
512 self.activateWindow() |
|
513 |
|
514 @pyqtSlot() |
|
515 def on_testsuitePicker_aboutToShowPathPickerDialog(self): |
|
516 """ |
|
517 Private slot called before the test file selection dialog is shown. |
|
518 """ |
|
519 # TODO: implement eric-ide mode |
|
520 # if self.__dbs: |
|
521 # py3Extensions = ' '.join( |
|
522 # ["*{0}".format(ext) |
|
523 # for ext in self.__dbs.getExtensions('Python3')] |
|
524 # ) |
|
525 # fileFilter = self.tr( |
|
526 # "Python3 Files ({0});;All Files (*)" |
|
527 # ).format(py3Extensions) |
|
528 # else: |
|
529 fileFilter = self.tr("Python Files (*.py);;All Files (*)") |
|
530 self.testsuitePicker.setFilters(fileFilter) |
|
531 |
|
532 defaultDirectory = Preferences.getMultiProject("Workspace") |
|
533 if not defaultDirectory: |
|
534 defaultDirectory = os.path.expanduser("~") |
|
535 # if self.__dbs: |
|
536 # project = ericApp().getObject("Project") |
|
537 # if self.__forProject and project.isOpen(): |
|
538 # defaultDirectory = project.getProjectPath() |
|
539 self.testsuitePicker.setDefaultDirectory(defaultDirectory) |
464 |
540 |
465 @pyqtSlot(QAbstractButton) |
541 @pyqtSlot(QAbstractButton) |
466 def on_buttonBox_clicked(self, button): |
542 def on_buttonBox_clicked(self, button): |
467 """ |
543 """ |
468 Private slot called by a button of the button box clicked. |
544 Private slot called by a button of the button box clicked. |
473 if button == self.__startButton: |
549 if button == self.__startButton: |
474 self.startTests() |
550 self.startTests() |
475 self.__saveRecent() |
551 self.__saveRecent() |
476 elif button == self.__stopButton: |
552 elif button == self.__stopButton: |
477 self.__stopTests() |
553 self.__stopTests() |
478 # elif button == self.__startFailedButton: |
554 elif button == self.__startFailedButton: |
479 # self.startTests(failedOnly=True) |
555 self.startTests(failedOnly=True) |
480 |
556 |
481 @pyqtSlot(int) |
557 @pyqtSlot(int) |
482 def on_venvComboBox_currentIndexChanged(self, index): |
558 def on_venvComboBox_currentIndexChanged(self, index): |
483 """ |
559 """ |
484 Private slot handling the selection of a virtual environment. |
560 Private slot handling the selection of a virtual environment. |
546 return |
622 return |
547 |
623 |
548 self.__recentEnvironment = self.venvComboBox.currentText() |
624 self.__recentEnvironment = self.venvComboBox.currentText() |
549 self.__recentFramework = self.frameworkComboBox.currentText() |
625 self.__recentFramework = self.frameworkComboBox.currentText() |
550 |
626 |
|
627 self.__failedTests = ( |
|
628 self.__resultsModel.getFailedTests() |
|
629 if failedOnly else |
|
630 [] |
|
631 ) |
551 discover = self.discoverCheckBox.isChecked() |
632 discover = self.discoverCheckBox.isChecked() |
552 if discover: |
633 if discover: |
553 discoveryStart = self.discoveryPicker.currentText() |
634 discoveryStart = self.discoveryPicker.currentText() |
554 testFileName = "" |
635 testFileName = "" |
555 testName = "" |
636 testName = "" |
577 discover=self.discoverCheckBox.isChecked(), |
658 discover=self.discoverCheckBox.isChecked(), |
578 discoveryStart=discoveryStart, |
659 discoveryStart=discoveryStart, |
579 testFilename=testFileName, |
660 testFilename=testFileName, |
580 testName=testName, |
661 testName=testName, |
581 failFast=self.failfastCheckBox.isChecked(), |
662 failFast=self.failfastCheckBox.isChecked(), |
|
663 failedOnly=failedOnly, |
582 collectCoverage=self.coverageCheckBox.isChecked(), |
664 collectCoverage=self.coverageCheckBox.isChecked(), |
583 eraseCoverage=self.coverageEraseCheckBox.isChecked(), |
665 eraseCoverage=self.coverageEraseCheckBox.isChecked(), |
584 ) |
666 ) |
585 |
667 |
586 self.__resultsModel.clear() |
|
587 self.__testExecutor = self.__frameworkRegistry.createExecutor( |
668 self.__testExecutor = self.__frameworkRegistry.createExecutor( |
588 self.__recentFramework, self) |
669 self.__recentFramework, self) |
589 self.__testExecutor.collected.connect(self.__testsCollected) |
670 self.__testExecutor.collected.connect(self.__testsCollected) |
590 self.__testExecutor.collectError.connect(self.__testsCollectError) |
671 self.__testExecutor.collectError.connect(self.__testsCollectError) |
591 self.__testExecutor.startTest.connect(self.__testStarted) |
672 self.__testExecutor.startTest.connect(self.__testStarted) |
592 self.__testExecutor.testResult.connect(self.__processTestResult) |
673 self.__testExecutor.testResult.connect(self.__processTestResult) |
593 self.__testExecutor.testFinished.connect(self.__testProcessFinished) |
674 self.__testExecutor.testFinished.connect(self.__testProcessFinished) |
594 self.__testExecutor.testRunFinished.connect(self.__testRunFinished) |
675 self.__testExecutor.testRunFinished.connect(self.__testRunFinished) |
595 self.__testExecutor.stop.connect(self.__testsStopped) |
676 self.__testExecutor.stop.connect(self.__testsStopped) |
596 self.__testExecutor.coverageDataSaved.connect(self.__coverageData) |
677 self.__testExecutor.coverageDataSaved.connect(self.__coverageData) |
|
678 self.__testExecutor.testRunAboutToBeStarted.connect( |
|
679 self.__testRunAboutToBeStarted) |
597 |
680 |
598 self.__setRunningMode() |
681 self.__setRunningMode() |
599 self.__testExecutor.start(config, []) |
682 self.__testExecutor.start(config, []) |
600 |
683 |
601 @pyqtSlot() |
684 @pyqtSlot() |
734 """ |
817 """ |
735 self.sbLabel.setText(self.tr("Ran %n test(s)", "", self.__runCount)) |
818 self.sbLabel.setText(self.tr("Ran %n test(s)", "", self.__runCount)) |
736 |
819 |
737 self.__setStoppedMode() |
820 self.__setStoppedMode() |
738 |
821 |
|
822 @pyqtSlot() |
|
823 def __testRunAboutToBeStarted(self): |
|
824 """ |
|
825 Private slot to handle the 'testRunAboutToBeStarted' signal of the |
|
826 executor. |
|
827 """ |
|
828 self.__resultsModel.clear() |
|
829 |
739 @pyqtSlot(str) |
830 @pyqtSlot(str) |
740 def __coverageData(self, coverageFile): |
831 def __coverageData(self, coverageFile): |
741 """ |
832 """ |
742 Private slot to handle the 'coverageData' signal of the executor. |
833 Private slot to handle the 'coverageData' signal of the executor. |
743 |
834 |