PyUnit/UnittestDialog.py

changeset 6899
8c4cf9c405c7
parent 6897
701256697721
child 6900
060a30488316
diff -r 6d7e8a05a33c -r 8c4cf9c405c7 PyUnit/UnittestDialog.py
--- a/PyUnit/UnittestDialog.py	Sun Mar 24 18:25:31 2019 +0100
+++ b/PyUnit/UnittestDialog.py	Sun Mar 24 19:18:56 2019 +0100
@@ -18,7 +18,7 @@
 from PyQt5.QtCore import pyqtSignal, QEvent, Qt, pyqtSlot
 from PyQt5.QtGui import QColor
 from PyQt5.QtWidgets import QWidget, QDialog, QApplication, QDialogButtonBox, \
-    QListWidgetItem, QComboBox
+    QListWidgetItem, QComboBox, QTreeWidgetItem
 
 from E5Gui.E5Application import e5App
 from E5Gui import E5MessageBox
@@ -76,6 +76,13 @@
             QComboBox.AdjustToMinimumContentsLength)
         
         # TODO: add a "Discover" button enabled upon selection of 'auto-discovery'
+        self.discoverButton = self.buttonBox.addButton(
+            self.tr("Discover"), QDialogButtonBox.ActionRole)
+        self.discoverButton.setToolTip(self.tr(
+            "Discover tests"))
+        self.discoverButton.setWhatsThis(self.tr(
+            """<b>Discover</b>"""
+            """<p>This button starts a discovery of available tests.</p>"""))
         self.startButton = self.buttonBox.addButton(
             self.tr("Start"), QDialogButtonBox.ActionRole)
         self.startButton.setToolTip(self.tr(
@@ -97,6 +104,7 @@
         self.stopButton.setWhatsThis(self.tr(
             """<b>Stop Test</b>"""
             """<p>This button stops a running unittest.</p>"""))
+        self.discoverButton.setEnabled(False)
         self.stopButton.setEnabled(False)
         self.startButton.setDefault(True)
         self.startFailedButton.setEnabled(False)
@@ -318,8 +326,15 @@
         @param checked state of the checkbox
         @type bool
         """
-        # TODO: enable this code once the discover button is available
-#        self.discoverButton.setEnabled(checked)
+        self.discoverButton.setEnabled(checked)
+        if not bool(self.discoveryPicker.currentText()):
+            if self.__forProject:
+                project = e5App().getObject("Project")
+                if project.isOpen():
+                    self.insertDiscovery(project.getProjectPath())
+                    return
+            
+            self.insertDiscovery(Preferences.getMultiProject("Workspace"))
     
     def on_buttonBox_clicked(self, button):
         """
@@ -327,7 +342,9 @@
         
         @param button button that was clicked (QAbstractButton)
         """
-        if button == self.startButton:
+        if button == self.discoverButton:
+            self.__discover()
+        elif button == self.startButton:
             self.startTests()
         elif button == self.stopButton:
             self.__stopTests()
@@ -335,6 +352,127 @@
             self.startTests(failedOnly=True)
     
     @pyqtSlot()
+    def __discover(self):
+        """
+        Private slot to discover unit test but don't run them.
+        """
+        if self.running:
+            return
+        
+        self.discoveryList.clear()
+        
+        discoveryStart = self.discoveryPicker.currentText()
+        self.sbLabel.setText(self.tr("Discovering Tests"))
+        QApplication.processEvents()
+        
+        self.testName = self.tr("Unittest with auto-discovery")
+        if self.__dbs:
+            # TODO: implement this later
+            pass
+        else:
+            # we are running as an application
+            if not discoveryStart:
+                E5MessageBox.critical(
+                    self,
+                    self.tr("Unittest"),
+                    self.tr("You must enter a start directory for"
+                            " auto-discovery."))
+                return
+            
+            # clean up list of imported modules to force a reimport upon
+            # running the test
+            if self.savedModulelist:
+                for modname in list(sys.modules.keys()):
+                    if modname not in self.savedModulelist:
+                        # delete it
+                        del(sys.modules[modname])
+            self.savedModulelist = sys.modules.copy()
+            
+            # now try to discover the testsuite
+            os.chdir(discoveryStart)
+            try:
+                test = unittest.defaultTestLoader.discover(discoveryStart)
+                if test:
+                    testsList = self.__assembleTestCasesList(test)
+                    self.__populateDiscoveryResults(testsList)
+                    self.sbLabel.setText(
+                        self.tr("Discovered %n Test(s)", "", len(testsList)))
+                    self.tabWidget.setCurrentIndex(0)
+            except Exception:
+                exc_type, exc_value, exc_tb = sys.exc_info()
+                E5MessageBox.critical(
+                    self,
+                    self.tr("Unittest"),
+                    self.tr(
+                        "<p>Unable to discover tests.<br/>"
+                        "{0}<br/>{1}</p>")
+                    .format(str(exc_type), str(exc_value)))
+    
+    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 __findDiscoveryItem(self, modulePath):
+        """
+        Private method to find an item given the module path.
+        
+        @param modulePath path of the module in dotted notation
+        @type str
+        @return reference to the item or None
+        @rtype QTreeWidgetItem or None
+        """
+        itm = self.discoveryList.topLevelItem(0)
+        while itm is not None:
+            if itm.data(0, Qt.UserRole) == modulePath:
+                return itm
+            itm = self.discoveryList.itemBelow(itm)
+        
+        return None
+    
+    def __populateDiscoveryResults(self, tests):
+        """
+        Private method to populate the test discovery results list.
+        
+        @param tests list of tuples containing the discovery results
+        @type list of tuples of (str, str)
+        """
+        for test, _testDescription in tests:
+            testPath = test.split(".")
+            pitm = None
+            for index in range(1, len(testPath) + 1):
+                modulePath = ".".join(testPath[:index])
+                itm = self.__findDiscoveryItem(modulePath)
+                if itm is not None:
+                    pitm = itm
+                else:
+                    if pitm is None:
+                        itm = QTreeWidgetItem(self.discoveryList,
+                                              [testPath[index - 1]])
+                    else:
+                        itm = QTreeWidgetItem(pitm,
+                                              [testPath[index - 1]])
+                        pitm.setExpanded(True)
+                    itm.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
+                    itm.setCheckState(0, Qt.Unchecked)
+                    itm.setData(0, Qt.UserRole, modulePath)
+                    pitm = itm
+    
+    @pyqtSlot()
     def startTests(self, failedOnly=False):
         """
         Public slot to start the test.
@@ -466,6 +604,9 @@
             if testFileName:
                 sys.path = [os.path.dirname(os.path.abspath(testFileName))] + \
                     self.savedSysPath
+            elif discoveryStart:
+                sys.path = [os.path.abspath(discoveryStart)] + \
+                    self.savedSysPath
             
             # clean up list of imported modules to force a reimport upon
             # running the test
@@ -489,7 +630,6 @@
                     failed = []
                 if discover:
                     test = unittest.defaultTestLoader.discover(discoveryStart)
-#                    testsList = self.__assembleTestCasesList(test)
                 else:
                     if testFileName:
                         module = __import__(self.testName)
@@ -548,25 +688,6 @@
             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.

eric ide

mercurial