73 self.discoveryPicker.setMode(E5PathPickerModes.DirectoryMode) |
73 self.discoveryPicker.setMode(E5PathPickerModes.DirectoryMode) |
74 self.discoveryPicker.setInsertPolicy(QComboBox.InsertAtTop) |
74 self.discoveryPicker.setInsertPolicy(QComboBox.InsertAtTop) |
75 self.discoveryPicker.setSizeAdjustPolicy( |
75 self.discoveryPicker.setSizeAdjustPolicy( |
76 QComboBox.AdjustToMinimumContentsLength) |
76 QComboBox.AdjustToMinimumContentsLength) |
77 |
77 |
|
78 # TODO: add a "Discover" button enabled upon selection of 'auto-discovery' |
78 self.startButton = self.buttonBox.addButton( |
79 self.startButton = self.buttonBox.addButton( |
79 self.tr("Start"), QDialogButtonBox.ActionRole) |
80 self.tr("Start"), QDialogButtonBox.ActionRole) |
80 self.startButton.setToolTip(self.tr( |
81 self.startButton.setToolTip(self.tr( |
81 "Start the selected testsuite")) |
82 "Start the selected testsuite")) |
82 self.startButton.setWhatsThis(self.tr( |
83 self.startButton.setWhatsThis(self.tr( |
109 self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) |
110 self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) |
110 self.setWindowTitle(self.tr("Unittest")) |
111 self.setWindowTitle(self.tr("Unittest")) |
111 if dbs: |
112 if dbs: |
112 self.ui = ui |
113 self.ui = ui |
113 |
114 |
114 self.venvComboBox.addItem("") |
115 # virtual environment manager is only used in the integrated |
115 self.venvComboBox.addItems( |
116 # variant |
116 sorted(e5App().getObject("VirtualEnvManager") |
117 self.__venvManager = e5App().getObject("VirtualEnvManager") |
117 .getVirtualenvNames())) |
118 self.__populateVenvComboBox() |
118 self.venvComboBox.setVisible(bool(self.__dbs)) |
119 self.__venvManager.virtualEnvironmentAdded.connect( |
119 self.venvLabel.setVisible(bool(self.__dbs)) |
120 self.__populateVenvComboBox) |
|
121 self.__venvManager.virtualEnvironmentRemoved.connect( |
|
122 self.__populateVenvComboBox) |
|
123 self.__venvManager.virtualEnvironmentChanged.connect( |
|
124 self.__populateVenvComboBox) |
|
125 else: |
|
126 self.__venvManager = None |
|
127 self.venvComboBox.setVisible(bool(self.__venvManager)) |
|
128 self.venvLabel.setVisible(bool(self.__venvManager)) |
120 |
129 |
121 self.__setProgressColor("green") |
130 self.__setProgressColor("green") |
122 self.progressLed.setDarkFactor(150) |
131 self.progressLed.setDarkFactor(150) |
123 self.progressLed.off() |
132 self.progressLed.off() |
124 |
133 |
162 |
171 |
163 @param evt key press event to handle (QKeyEvent) |
172 @param evt key press event to handle (QKeyEvent) |
164 """ |
173 """ |
165 if evt.key() == Qt.Key_Escape and self.__dbs: |
174 if evt.key() == Qt.Key_Escape and self.__dbs: |
166 self.close() |
175 self.close() |
|
176 |
|
177 def __populateVenvComboBox(self): |
|
178 """ |
|
179 Private method to (re-)populate the virtual environments selector. |
|
180 """ |
|
181 currentText = self.venvComboBox.currentText() |
|
182 self.venvComboBox.clear() |
|
183 self.venvComboBox.addItem("") |
|
184 self.venvComboBox.addItems( |
|
185 sorted(self.__venvManager.getVirtualenvNames())) |
|
186 index = self.venvComboBox.findText(currentText) |
|
187 if index < 0: |
|
188 index = 0 |
|
189 self.venvComboBox.setCurrentIndex(index) |
167 |
190 |
168 def __setProgressColor(self, color): |
191 def __setProgressColor(self, color): |
169 """ |
192 """ |
170 Private methode to set the color of the progress color label. |
193 Private methode to set the color of the progress color label. |
171 |
194 |
301 Private slot called by a button of the button box clicked. |
325 Private slot called by a button of the button box clicked. |
302 |
326 |
303 @param button button that was clicked (QAbstractButton) |
327 @param button button that was clicked (QAbstractButton) |
304 """ |
328 """ |
305 if button == self.startButton: |
329 if button == self.startButton: |
306 self.on_startButton_clicked() |
330 self.startTests() |
307 elif button == self.stopButton: |
331 elif button == self.stopButton: |
308 self.on_stopButton_clicked() |
332 self.__stopTests() |
309 elif button == self.startFailedButton: |
333 elif button == self.startFailedButton: |
310 self.on_startButton_clicked(failedOnly=True) |
334 self.startTests(failedOnly=True) |
311 |
335 |
312 @pyqtSlot() |
336 @pyqtSlot() |
313 def on_startButton_clicked(self, failedOnly=False): |
337 def startTests(self, failedOnly=False): |
314 """ |
338 """ |
315 Private slot to start the test. |
339 Public slot to start the test. |
316 |
340 |
317 @keyparam failedOnly flag indicating to run only failed tests (boolean) |
341 @keyparam failedOnly flag indicating to run only failed tests (boolean) |
318 """ |
342 """ |
|
343 # TODO: run only failed test ignoring test parameters when failedOnly is set |
319 if self.running: |
344 if self.running: |
320 return |
345 return |
321 |
346 |
322 discover = self.discoverCheckBox.isChecked() |
347 discover = self.discoverCheckBox.isChecked() |
323 if discover: |
348 if discover: |
324 discoveryStart = self.discoveryPicker.currentText() |
349 discoveryStart = self.discoveryPicker.currentText() |
325 prog = "" |
350 testFileName = "" |
|
351 testName = "" |
326 else: |
352 else: |
327 discoveryStart = "" |
353 discoveryStart = "" |
328 prog = self.testsuitePicker.currentText() |
354 testFileName = self.testsuitePicker.currentText() |
329 |
355 testName = self.testComboBox.currentText() |
330 if not prog and not discover: |
356 if testName: |
|
357 self.insertTestName(testName) |
|
358 if testFileName and not testName: |
|
359 testName = "suite" |
|
360 |
|
361 if not discover and not testFileName and not testName: |
331 E5MessageBox.critical( |
362 E5MessageBox.critical( |
332 self, |
363 self, |
333 self.tr("Unittest"), |
364 self.tr("Unittest"), |
334 self.tr("You must enter a test suite file or select" |
365 self.tr("You must select auto-discovery or enter a test suite" |
335 " auto-discovery.")) |
366 " file or a dotted test name.")) |
336 return |
367 return |
337 |
368 |
338 # prepend the selected file to the testsuite combobox |
369 # prepend the selected file to the testsuite combobox |
339 self.insertProg(prog) |
370 self.insertProg(testFileName) |
340 self.sbLabel.setText(self.tr("Preparing Testsuite")) |
371 self.sbLabel.setText(self.tr("Preparing Testsuite")) |
341 QApplication.processEvents() |
372 QApplication.processEvents() |
342 |
373 |
343 if discover: |
374 if discover: |
344 testFunctionName = "" |
|
345 self.testName = self.tr("Unittest with auto-discovery") |
375 self.testName = self.tr("Unittest with auto-discovery") |
346 else: |
376 else: |
347 testFunctionName = self.testComboBox.currentText() |
377 # build the module name from the filename without extension |
348 if testFunctionName: |
378 if testFileName: |
349 self.insertTestName(testFunctionName) |
379 self.testName = os.path.splitext( |
|
380 os.path.basename(testFileName))[0] |
|
381 elif testName: |
|
382 self.testName = testName |
350 else: |
383 else: |
351 testFunctionName = "suite" |
384 self.testName = self.tr("<Unnamed Test>") |
|
385 |
|
386 if self.__dbs: |
|
387 venvName = self.venvComboBox.currentText() |
352 |
388 |
353 # build the module name from the filename without extension |
|
354 self.testName = os.path.splitext(os.path.basename(prog))[0] |
|
355 |
|
356 if self.__dbs: |
|
357 # we are cooperating with the eric6 IDE |
389 # we are cooperating with the eric6 IDE |
358 project = e5App().getObject("Project") |
390 project = e5App().getObject("Project") |
359 if self.__forProject and project.isOpen() and \ |
391 if self.__forProject: |
360 (discover or project.isProjectSource(prog)): |
|
361 mainScript = os.path.abspath(project.getMainScript(True)) |
392 mainScript = os.path.abspath(project.getMainScript(True)) |
362 clientType = project.getProjectLanguage() |
393 clientType = project.getProjectLanguage() |
363 if mainScript: |
394 if mainScript: |
364 workdir = os.path.dirname(mainScript) |
395 workdir = os.path.dirname(mainScript) |
365 else: |
396 else: |
366 workdir = project.getProjectPath() |
397 workdir = project.getProjectPath() |
367 sysPath = [workdir] |
398 sysPath = [workdir] |
|
399 coverageFile = os.path.splitext(mainScript)[0] |
368 if discover and not discoveryStart: |
400 if discover and not discoveryStart: |
369 discoveryStart = workdir |
401 discoveryStart = workdir |
370 else: |
402 else: |
371 if discover: |
403 if discover: |
372 if not discoveryStart: |
404 if not discoveryStart: |
374 self, |
406 self, |
375 self.tr("Unittest"), |
407 self.tr("Unittest"), |
376 self.tr("You must enter a start directory for" |
408 self.tr("You must enter a start directory for" |
377 " auto-discovery.")) |
409 " auto-discovery.")) |
378 return |
410 return |
379 mainScript = os.path.join(discoveryStart, "unittest") |
411 |
|
412 coverageFile = os.path.join(discoveryStart, "unittest") |
380 workdir = "" |
413 workdir = "" |
381 # assume Python3 for auto-discovery |
414 clientType = \ |
382 clientType = "Python3" |
415 self.__venvManager.getVirtualenvVariant(venvName) |
383 else: |
416 if not clientType: |
384 mainScript = os.path.abspath(prog) |
417 # assume Python 3 |
|
418 clientType = "Python3" |
|
419 elif testFileName: |
|
420 mainScript = os.path.abspath(testFileName) |
|
421 flags = Utilities.extractFlagsFromFile(mainScript) |
385 workdir = os.path.dirname(mainScript) |
422 workdir = os.path.dirname(mainScript) |
386 flags = Utilities.extractFlagsFromFile(mainScript) |
|
387 if mainScript.endswith( |
423 if mainScript.endswith( |
388 tuple(Preferences.getPython("PythonExtensions"))) or \ |
424 tuple(Preferences.getPython("PythonExtensions"))) or \ |
389 ("FileType" in flags and |
425 ("FileType" in flags and |
390 flags["FileType"] in ["Python", "Python2"]): |
426 flags["FileType"] in ["Python", "Python2"]): |
391 clientType = "Python2" |
427 clientType = "Python2" |
392 else: |
428 else: |
393 # if it is not Python2 it must be Python3! |
429 # if it is not Python2 it must be Python3! |
394 clientType = "Python3" |
430 clientType = "Python3" |
|
431 coverageFile = os.path.splitext(mainScript)[0] |
|
432 else: |
|
433 coverageFile = os.path.abspath("unittest") |
|
434 workdir = "" |
|
435 clientType = \ |
|
436 self.__venvManager.getVirtualenvVariant(venvName) |
|
437 if not clientType: |
|
438 # assume Python 3 |
|
439 clientType = "Python3" |
395 sysPath = [] |
440 sysPath = [] |
396 if not discover and failedOnly and self.__failedTests: |
441 if not discover and failedOnly and self.__failedTests: |
397 failed = [t.split(".", 1)[1] for t in self.__failedTests] |
442 failed = self.__failedTests[:] |
398 else: |
443 else: |
399 failed = [] |
444 failed = [] |
400 self.__failedTests = [] |
445 self.__failedTests = [] |
401 self.__dbs.remoteUTPrepare( |
446 self.__dbs.remoteUTPrepare( |
402 prog, self.testName, testFunctionName, failed, |
447 testFileName, self.testName, testName, failed, |
403 self.coverageCheckBox.isChecked(), mainScript, |
448 self.coverageCheckBox.isChecked(), coverageFile, |
404 self.coverageEraseCheckBox.isChecked(), clientType=clientType, |
449 self.coverageEraseCheckBox.isChecked(), clientType=clientType, |
405 forProject=self.__forProject, workdir=workdir, |
450 forProject=self.__forProject, workdir=workdir, |
406 venvName=self.venvComboBox.currentText(), syspath=sysPath, |
451 venvName=venvName, syspath=sysPath, |
407 discover=discover, discoveryStart=discoveryStart) |
452 discover=discover, discoveryStart=discoveryStart) |
408 else: |
453 else: |
409 # TODO: add discovery |
|
410 # we are running as an application |
454 # we are running as an application |
411 sys.path = [os.path.dirname(os.path.abspath(prog))] + \ |
455 if testFileName: |
412 self.savedSysPath |
456 sys.path = [os.path.dirname(os.path.abspath(testFileName))] + \ |
|
457 self.savedSysPath |
413 |
458 |
414 # clean up list of imported modules to force a reimport upon |
459 # clean up list of imported modules to force a reimport upon |
415 # running the test |
460 # running the test |
416 if self.savedModulelist: |
461 if self.savedModulelist: |
417 for modname in list(sys.modules.keys()): |
462 for modname in list(sys.modules.keys()): |
430 self.tr("You must enter a start directory for" |
475 self.tr("You must enter a start directory for" |
431 " auto-discovery.")) |
476 " auto-discovery.")) |
432 return |
477 return |
433 |
478 |
434 test = unittest.defaultTestLoader.discover(discoveryStart) |
479 test = unittest.defaultTestLoader.discover(discoveryStart) |
|
480 # testsList = self.__assembleTestCasesList(test) |
435 else: |
481 else: |
436 module = __import__(self.testName) |
482 if testFileName: |
437 try: |
483 module = __import__(self.testName) |
438 if failedOnly and self.__failedTests: |
484 else: |
439 test = \ |
485 module = None |
440 unittest.defaultTestLoader.loadTestsFromNames( |
486 if failedOnly and self.__failedTests: |
441 [t.split(".", 1)[1] |
487 if module: |
442 for t in self.__failedTests], |
488 failed = [t.split(".", 1)[1] |
443 module) |
489 for t in self.__failedTests] |
444 else: |
490 else: |
445 test = \ |
491 failed = self.__failedTests[:] |
446 unittest.defaultTestLoader.loadTestsFromName( |
492 test = unittest.defaultTestLoader.loadTestsFromNames( |
447 testFunctionName, module) |
493 failed, module) |
448 except AttributeError: |
494 else: |
449 test = unittest.defaultTestLoader.loadTestsFromModule( |
495 test = unittest.defaultTestLoader.loadTestsFromName( |
450 module) |
496 testName, module) |
451 except Exception: |
497 except Exception: |
452 exc_type, exc_value, exc_tb = sys.exc_info() |
498 exc_type, exc_value, exc_tb = sys.exc_info() |
453 E5MessageBox.critical( |
499 E5MessageBox.critical( |
454 self, |
500 self, |
455 self.tr("Unittest"), |
501 self.tr("Unittest"), |
487 cover.stop() |
534 cover.stop() |
488 cover.save() |
535 cover.save() |
489 self.__setStoppedMode() |
536 self.__setStoppedMode() |
490 sys.path = self.savedSysPath |
537 sys.path = self.savedSysPath |
491 |
538 |
|
539 def __assembleTestCasesList(self, suite): |
|
540 """ |
|
541 Private method to assemble a list of test cases included in a test |
|
542 suite. |
|
543 |
|
544 @param suite test suite to be inspected |
|
545 @type unittest.TestSuite |
|
546 @return list of tuples containing the test case ID and short |
|
547 description |
|
548 @rtype list of tuples of (str, str) |
|
549 """ |
|
550 testCases = [] |
|
551 for test in suite: |
|
552 if isinstance(test, unittest.TestSuite): |
|
553 testCases.extend(self.__assembleTestCasesList(test)) |
|
554 else: |
|
555 testCases.append((test.id(), test.shortDescription())) |
|
556 return testCases |
|
557 |
492 def __UTPrepared(self, nrTests, exc_type, exc_value): |
558 def __UTPrepared(self, nrTests, exc_type, exc_value): |
493 """ |
559 """ |
494 Private slot to handle the utPrepared signal. |
560 Private slot to handle the utPrepared signal. |
495 |
561 |
496 If the unittest suite was loaded successfully, we ask the |
562 If the unittest suite was loaded successfully, we ask the |