예제 #1
0
    def _makeRunButtons(self, _btmLayout):
        self._resetAllBtn = uiutils.makeIconButton(self._resetIcon, self)
        self._resetAllBtn.setToolTip(
            "Reset the test item states, icons and stats and collapse the tree view items in a certain level."
        )
        self._resetAllBtn.clicked.connect(self._view.resetAllItemsToNormal)
        _btmLayout.addWidget(self._resetAllBtn, 1)

        self._runSelectedBtn = QtWidgets.QPushButton("Run &Selected", self)
        self._runSelectedBtn.setToolTip("Run the selected tests in the view.")
        self._runSelectedBtn.clicked.connect(self._runViewSelectedTests)
        self._runSelectedBtn.setIcon(self._view._runSelectedIcon)
        _btmLayout.addWidget(self._runSelectedBtn, 1)

        self._runAllBtn = QtWidgets.QPushButton("Run &All", self)
        self._runAllBtn.setToolTip(
            "Run all the tests, including those filtered from the view.")
        self._runAllBtn.setIcon(self._view._runAllIcon)
        self._runAllBtn.clicked.connect(self._runAllTests)
        _btmLayout.addWidget(self._runAllBtn, 1)

        self._reimportAndRerunBtn = QtWidgets.QPushButton(
            "&Reload && Rerun", self)
        self._reimportAndRerunBtn.setToolTip(
            "Reimport all changed python modules and rerun the last tests.")
        self._reimportAndRerunBtn.clicked.connect(self._reimportPyAndRerun)
        self._reimportAndRerunBtn.setIcon(self._view._reimportAndRunIcon)
        _btmLayout.addWidget(self._reimportAndRerunBtn, 1)

        _runMoreBtn = self._makeRunMoreButton()
        _btmLayout.addWidget(_runMoreBtn, 0)
예제 #2
0
    def __init__(self, parent=None):
        QtWidgets.QDialog.__init__(self, parent)
        self.setWindowTitle("{} Preference".format(constants.APP_NAME))

        self._mainLayout = uiutils.makeMainLayout(self)
        self._formLayout = uiutils.makeMinorLayout(QtWidgets.QFormLayout)
        self._mainLayout.addLayout(self._formLayout)
        self._formLayout.setLabelAlignment(QtCore.Qt.AlignRight)

        # Code viewing config
        self._codeEditorLE = QtWidgets.QLineEdit(self)
        editorSetting = gotocode.CodeLineVisitor.config()
        self._codeEditorLE.setText(editorSetting)
        self._codeEditorLE.editingFinished.connect(
            self._onCodeEditorEditFinished)
        self._codeEditorLE.setPlaceholderText(
            "Example: pargram $file -argToLine $line")
        self._codeEditorLE.setToolTip(
            "Input the command to jump to the code at the line. \n"
            "$file is the placeholder for file path, $line is the line number."
        )
        _annoText = QtWidgets.QLabel("Default: {}".format(
            constants.CONFIG_KEY_CODE_EDITOR_DEFAULT))
        _annoText.setEnabled(False)

        self._formLayout.addRow("Go To Code Line", self._codeEditorLE)
        self._formLayout.addRow("", _annoText)

        self.setMinimumWidth(400)
        self.setMinimumHeight(100)

        self.destroyed.connect(self._onDialogDeleted)
예제 #3
0
 def _createSplitterContent(self):
     wgt = QtWidgets.QWidget(self)
     splitterLay = QtWidgets.QVBoxLayout(wgt)
     splitterLay.setSpacing(3)
     splitterLay.setContentsMargins(0, 0, 0, 0)
     self._splitter.addWidget(wgt)
     return wgt, splitterLay
예제 #4
0
def makeMenuToolButton(icon=None, toolTip="", parent=None):
    btn = QtWidgets.QToolButton(parent)
    if icon:
        btn.setIcon(icon)
    btn.setToolTip(toolTip)
    btn.setContentsMargins(0, 0, 0, 0)
    btn.setIconSize(QtCore.QSize(20, 20))
    btn.setPopupMode(btn.InstantPopup)
    menu = QtWidgets.QMenu(btn)
    btn.setMenu(menu)
    return (btn, menu)
예제 #5
0
    def _makeDirWidgets(self):
        lbl = QtWidgets.QLabel("Test Root")
        lbl.setToolTip(
            "Input a python module path or an absolute dir path in the lineEdit for the tests."
        )
        self._rootDirLE = rootpathedit.RootPathEdit(self)
        self._rootDirLE.rootPathChanged.connect(self._switchToTestRootPath)
        self._rootDirLE.rootDirPicked.connect(self._onBrowseTestsRootDir)
        self._rootDirLE.topDirPicked.connect(self._onBrowseTopDir)
        self._rootDirLE.saveCurrentDirSettings.connect(
            self._onSaveCurrentDirSettings)
        self._rootDirLE.loadSavedDirPair.connect(self._loadSavedDirPair)
        self._rootDirLE.deleteCurrentDirSettings.connect(
            self._onDeleteCurrentDirSettings)

        self._panelVisBtn = uiutils.makeIconButton(self._panelStateIconSet[-1],
                                                   self)
        self._panelVisBtn.setToolTip(
            "Switch the test tree view and the log browser visibility.")
        self._panelVisBtn.clicked.connect(self._onPanelVisButtonClicked)
        self._makeRunnerConfigButton()

        self._dirLayout.addWidget(lbl)
        self._dirLayout.addWidget(self._rootDirLE)
        self._dirLayout.addWidget(self._panelVisBtn)
        self._dirLayout.addWidget(self._runnerConfigBtn)

        self._updateDirUI()
예제 #6
0
def makeIconButton(icon, parent=None):
    btn = QtWidgets.QPushButton("", parent)
    btn.setIcon(icon)
    btn.setFlat(True)
    btn.setIconSize(QtCore.QSize(20, 20))
    btn.setFixedSize(QtCore.QSize(24, 24))
    return btn
예제 #7
0
    def __init__(self, parent):
        QtWidgets.QTreeWidget.__init__(self, parent)
        self._pan = scrollareapan.ScrollAreaPan(self, scrollFactor=0.05)
        self._pan.installEventFilterOn(self.viewport())
        self._uiStream = uistream.UiStream()
        self._codeVisitor = gotocode.CodeLineVisitor(self)
        self._codeVisitor.errorIssued.connect(self._onGoToCodeError)

        self.setItemDelegate(self._TreeItemDelegate(self))
        self.setTextElideMode(QtCore.Qt.ElideLeft)
        self.setColumnCount(2)
        self._setHeaderStretch()
        self.setHeaderHidden(True)
        self.setAlternatingRowColors(True)
        self.setExpandsOnDoubleClick(False)
        self.setSelectionMode(self.ExtendedSelection)
        self.itemDoubleClicked.connect(self.onItemDoubleClicked)
        self.setIndentation(10)

        self._rootTestItem = None
        self._testCases = []
        self._allItemsIdMap = {}
        self._initAllIcons()

        self._testManager = None
        self._viewStates = ViewStates(self)

        self._contextMenu = QtWidgets.QMenu(self)
        self._makeContextMenu()

        self.setToolTip(
            "This view lists out the tests, <b>Double Click</b> on them to run them, <b>Ctrl+C</b> to copy the python module path;"
            + "<br><br><b>MMB Dragging</b> to pan the view around."
        )
예제 #8
0
    def _makeLogBrowserTopWidgets(self, layout):
        _console = QtWidgets.QLabel("Log Browser")

        self._logSearchLE = btnLineEdit.InlineButtonLineEdit(
            withClearButton=True, parent=self)
        self._logSearchLE.setToolTip(
            "Enter to search next keyword in the log browser, ctrl+Enter to search backward."
        )
        self._logSearchLE.setPlaceholderText("Input to search")
        self._logSearchLE.returnPressed.connect(self._applyLoggingSearchText)

        self._wholeWordBtn = uiutils.makeIconButton(self._wholeWordIcon)
        self._wholeWordBtn.setCheckable(True)
        self._logSearchLE.addButton("wholeWord", self._wholeWordBtn)

        self._sensitiveBtn = uiutils.makeIconButton(self._caseSensitiveIcon)
        self._sensitiveBtn.setCheckable(True)
        self._logSearchLE.addButton("caseSensitive", self._sensitiveBtn)

        self._clearLogBtn = uiutils.makeIconButton(self._clearLogIcon, self)
        self._clearLogBtn.setToolTip("Clear the log browser logging.")
        self._clearLogBtn.clicked.connect(self._logBrowser.clear)

        layout.addWidget(_console, 0)
        layout.addStretch(1)
        layout.addWidget(self._logSearchLE, 0)
        layout.addWidget(self._clearLogBtn, 0)
예제 #9
0
    def _makeContextMenu(self):
        self._initAllIcons()

        self._runSetupOnlyAct = QtWidgets.QAction("Run setUp( ) Only", self)
        self._runSetupOnlyAct.triggered.connect(self._atRunSetupOnly)
        self._runSetupOnlyAct.setIcon(self._runPartialIcon)

        self._runWithoutTearDownAct = QtWidgets.QAction("Run Without tearDown( )", self)
        self._runWithoutTearDownAct.triggered.connect(self._atRunWithoutTearDown)
        self._runWithoutTearDownAct.setIcon(self._runPartialIcon)

        self._runSelectedAct = QtWidgets.QAction("Run Selected", self)
        self._runSelectedAct.triggered.connect(self._atRunSelected)
        self._runSelectedAct.setIcon(self._runSelectedIcon)

        self._runAllAct = QtWidgets.QAction("Run All", self)
        self._runAllAct.triggered.connect(self._atRunAll)
        self._runAllAct.setIcon(self._runAllIcon)

        self._copyPathAct = QtWidgets.QAction("Copy Selected Path", self)
        self._copyPathAct.triggered.connect(self.copyFirstSelectedTestId)

        self._goToCodeAct = QtWidgets.QAction("Go To Code...", self)
        self._goToCodeAct.triggered.connect(self._atGoToCode)

        self._reloadModulesAct = QtWidgets.QAction("Reload Selected Modules", self)
        self._reloadModulesAct.setVisible(
            importutils.isReimportFeatureAvailable(silentCheck=True)
        )
        self._reloadModulesAct.triggered.connect(self._atReloadSelectedModules)
        self._reloadModulesAct.setIcon(self._reimportAndRunIcon)

        self._contextMenu.addAction(self._runAllAct)
        self._contextMenu.addAction(self._runSelectedAct)
        self._contextMenu.addSeparator()

        self._contextMenu.addAction(self._runSetupOnlyAct)
        self._contextMenu.addAction(self._runWithoutTearDownAct)
        self._contextMenu.addSeparator()

        self._contextMenu.addAction(self._copyPathAct)
        self._contextMenu.addAction(self._goToCodeAct)

        self._contextMenu.addSeparator()
        self._contextMenu.addAction(self._reloadModulesAct)

        self._logLevelMenu = QtWidgets.QMenu("Set Logging Level")
        self._contextMenu.addMenu(self._logLevelMenu)
        self._logLevelActionGrp = QtWidgets.QActionGroup(self._logLevelMenu)
        self._logLevelActionGrp.setExclusive(True)
예제 #10
0
    def _makeRunnerConfigButton(self):
        currentRunner = self._setInitialTestMode()
        currentRunnerMode = currentRunner.mode()
        self._runnerConfigBtn, self._configMenu = uiutils.makeMenuToolButton(
            parent=self)
        self._updateConfigButton(currentRunner)

        for runner in self._testManager.iterAllRunners():
            icon = runner.icon()
            toolTip = "Run tests using {}.".format(runner.name())
            runnerMode = runner.mode()
            act = QtWidgets.QAction(runner.name(), self)
            act.setIcon(icon)
            act.setEnabled(runner.isValid())
            act.setToolTip(toolTip)
            act.setData(runnerMode)
            act.triggered.connect(self._onTestRunnerSwitched)
            self._updateLabelOfTestRunnerAct(act, currentRunnerMode)
            self._testRunnerActions.append(act)
            self._configMenu.addAction(act)

        self._configMenu.addSeparator()

        # Stop on error act:
        self._stopOnErrorAct, stopOnError = self._addToggleConfigAction(
            "Stop On Error",
            self._stopAtErrorIcon,
            "Stop the tests running once it encounters a test error/failure.",
            configKey=constants.CONFIG_KEY_STOP_ON_ERROR,
            slot=self._onStopOnErrorActionToggled,
        )
        self._testManager.setStopOnError(stopOnError)

        # auto filer on run act:
        self._autoFilterAct, stopOnError = self._addToggleConfigAction(
            "Only Show Tests that Run",
            self._autoFilterIcon,
            "Apply a ':ran' filter automatically after every test run so that only the run tests shown in the view.",
            configKey=constants.CONFIG_KEY_AUTO_FILTERING_STATE,
            slot=self._onAutoFilterActionToggled,
        )

        # auto clear log on run act:
        self._clearLogOnRunAct, stopOnError = self._addToggleConfigAction(
            "Clear LogBrowser On Run",
            self._clearLogOnRunIcon,
            "Clear the log browser automatically before every test run.",
            configKey=constants.CONFIG_KEY_AUTO_CLEAR_LOG_STATE,
            slot=self._onAutoClearLogActionToggled,
        )

        self._configMenu.addSeparator()
        act = self._configMenu.addAction("Preference..")
        act.setIcon(self._configIcon)
        act.triggered.connect(self._showConfigWindow)
예제 #11
0
 def _addToggleConfigAction(self, lbl, icon, tooltip, configKey, slot):
     # Cannot use self._configMenu.addAction() directly here since over-zealous garbage collection in some DCC apps:
     act = QtWidgets.QAction(lbl, self)
     act.setIcon(icon)
     act.setCheckable(True)
     act.setToolTip(tooltip)
     act.toggled.connect(slot)
     value = appsettings.get().simpleConfigBoolValue(configKey)
     act.setChecked(value)
     self._configMenu.addAction(act)
     return (act, value)
예제 #12
0
    def _makeRunMoreButton(self):
        _runMoreBtn = QtWidgets.QToolButton(self)
        _runMoreBtn.setIcon(self._view._runPartialIcon)
        _runMoreBtn.setAutoRaise(True)
        _runMoreBtn.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        _runMoreBtn.setPopupMode(_runMoreBtn.InstantPopup)

        self._runSetupAct = QtWidgets.QAction("Run setUp( ) Only", self)
        self._runSetupAct.setIcon(self._view._runPartialIcon)
        self._runSetupAct.triggered.connect(self._runTestSetupOnly)

        self._runNoTearDown = QtWidgets.QAction("Run without tearDown( )",
                                                self)
        self._runNoTearDown.setIcon(self._view._runPartialIcon)
        self._runNoTearDown.triggered.connect(self._runTestWithoutTearDown)

        menu = QtWidgets.QMenu(_runMoreBtn)
        menu.addAction(self._runSetupAct)
        menu.addAction(self._runNoTearDown)
        _runMoreBtn.setMenu(menu)
        return _runMoreBtn
예제 #13
0
def addSeparatorToLayout(layout, direction):
    sep = QtWidgets.QFrame()
    sep.setStyleSheet("color:black")
    policy = sep.sizePolicy()
    if direction == QtCore.Qt.Horizontal:
        sep.setFrameShape(sep.HLine)
        sep.setSizePolicy(policy.Minimum, policy.Preferred)
    else:
        sep.setFrameShape(sep.VLine)
        sep.setSizePolicy(policy.Preferred, policy.Minimum)

    sep.setLineWidth(1)
    layout.addWidget(sep)
예제 #14
0
    def __init__(self, parent=None):
        btnLineEdit.InlineButtonLineEdit.__init__(self,
                                                  withClearButton=False,
                                                  parent=parent)
        self._initIcons()

        self.editingFinished.connect(self.onEditFinished)
        self._initPath = None

        self._browseBtn = uiutils.makeIconButton(self._moreIcon, self)
        self._browseBtn.clicked.connect(self._onBrowseBtnClicked)
        self._browseMenu = QtWidgets.QMenu(self._browseBtn)
        self.addButton("Browse", self._browseBtn)
        self.regenerateBrowseMenu()
예제 #15
0
    def reload(self, keepUiStates=True):
        if keepUiStates:
            self._viewStates.save()

        self._testCases = []
        self._rootTestItem = None
        self._allItemsIdMap = {}
        self.clear()

        startDirOrModule = self._testManager.startDirOrModule()
        if not startDirOrModule:
            return

        self._rootTestItem = QtWidgets.QTreeWidgetItem([startDirOrModule])
        self._rootTestItem.setToolTip(0, startDirOrModule)
        self._rootTestItem.setData(0, QtCore.Qt.UserRole, constants.ITEM_CATEGORY_ALL)
        self._setItemIconState(self._rootTestItem, constants.TEST_RESULT_NONE)
        self.addTopLevelItem(self._rootTestItem)

        self._allItemsIdMap[startDirOrModule] = self._rootTestItem

        isModule = not pathutils.isPath(startDirOrModule)
        headingCount = 0
        heading = ""
        if isModule:
            headingCount = len(startDirOrModule) + 1
            heading = startDirOrModule + "."

        testCount = 0
        for test in self._testManager.iterAllTestIds():
            testCount = testCount + 1
            if isModule and test.startswith(startDirOrModule):
                test = test[headingCount:]
            testPaths = test.split(".")
            cParent = self._rootTestItem
            for i, p in enumerate(testPaths):
                path = heading + ".".join(testPaths[0 : (i + 1)])
                if path in self._allItemsIdMap:
                    cParent = self._allItemsIdMap[path]
                    continue

                item = QtWidgets.QTreeWidgetItem(cParent)
                item.setText(0, p)
                item.setToolTip(0, path)
                item.setSizeHint(0, QtCore.QSize(20, 20))
                self._allItemsIdMap[path] = item
                cParent = item

            testCase = cParent
            testCase.setData(0, QtCore.Qt.UserRole, constants.ITEM_CATEGORY_TEST)
            self._setItemIconState(testCase, constants.TEST_RESULT_NONE)
            self._testCases.append(cParent)

            caseItem = testCase.parent()
            caseItem.setData(0, QtCore.Qt.UserRole, constants.ITEM_CATEGORY_SUITE)
            self._setItemIconState(caseItem, constants.TEST_RESULT_NONE)

            moduleItem = caseItem.parent()
            moduleItem.setData(0, QtCore.Qt.UserRole, constants.ITEM_CATEGORY_MODULE)
            self._setItemIconState(moduleItem, constants.TEST_RESULT_NONE)

            packageItem = moduleItem.parent()
            while packageItem is not self._rootTestItem and packageItem:
                packageItem.setData(
                    0, QtCore.Qt.UserRole, constants.ITEM_CATEGORY_PACKAGE
                )
                self._setItemIconState(packageItem, constants.TEST_RESULT_NONE)
                packageItem = packageItem.parent()

        self._uiStream.write("\n{}\n".format("-" * 20))
        if not self._testManager.hasLastListerError():
            self._uiStream.write("{} tests collected.\n\n".format(testCount))
        else:
            with self._uiStream.resultCtx(constants.TEST_RESULT_ERROR):
                msg = "Error collecting tests from {}.\n\n".format(
                    self._testManager.startDirOrModule()
                )
                self._uiStream.write(msg)

        if keepUiStates:
            self._viewStates.restore()
        else:
            self._resetExpandStates(self._rootTestItem)
예제 #16
0
def makeMainLayout(hostWidget=None):
    _lay = QtWidgets.QVBoxLayout(hostWidget)
    _lay.setContentsMargins(6, 6, 6, 6)
    _lay.setSpacing(3)
    return _lay
예제 #17
0
    def __init__(self, startDirOrModule=None, topDir=None, parent=None):
        parent = parent or dcc.findParentWindow()
        QtWidgets.QWidget.__init__(self, parent)
        self._uiStream = uistream.UiStream()

        self._initIcons()

        self._testManager = testmanager.TestManager(self, startDirOrModule,
                                                    topDir)

        self._mainLay = uiutils.makeMainLayout(self)
        self.setContentsMargins(0, 0, 0, 0)

        # Top layout ------------------------------
        self._dirLayout = uiutils.makeMinorHorizontalLayout()
        self._testRunnerActions = []
        self._makeDirWidgets()
        self._mainLay.addLayout(self._dirLayout)

        self._splitter = QtWidgets.QSplitter(self)
        self._mainLay.addWidget(self._splitter, 1)

        # left layout -----------------------------------
        self._leftWidget, leftLay = self._createSplitterContent()

        _topLayout = uiutils.makeMinorHorizontalLayout()
        self._makeTreeTopWidgets(_topLayout)
        leftLay.addLayout(_topLayout)

        self._view = unittesttree.UnitTestTreeView(self)
        self._view.runAllTest.connect(self._runAllTests)
        self._view.runTests.connect(self._runTests)
        self._view.runSetupOnly.connect(self._runTestSetupOnly)
        self._view.runWithoutTearDown.connect(self._runTestWithoutTearDown)
        self._view.searchNeeded.connect(self._prepareTreeSearch)
        self._view.itemSelectionChanged.connect(self._viewSelectionChanged)

        leftLay.addWidget(self._view)

        # right layout -----------------------------------
        self._rightWidget, rightLay = self._createSplitterContent()
        _logTopLayout = uiutils.makeMinorHorizontalLayout()
        self._logBrowser = logbrowser.LogBrowser(self)
        self._logBrowser.searchNeeded.connect(self._prepareLogSearch)
        self._makeLogBrowserTopWidgets(_logTopLayout)
        rightLay.addLayout(_logTopLayout, 0)
        rightLay.addWidget(self._logBrowser, 1)

        self._splitter.setSizes([230, 500])
        self._splitter.setStretchFactor(0, 0)
        self._splitter.setStretchFactor(1, 1)

        # bottom -----------------------------------
        self._statusLbl = statuslabel.StatusLabel(self)
        self._mainLay.addWidget(self._statusLbl)

        _btmLayout = uiutils.makeMinorHorizontalLayout()
        self._makeRunButtons(_btmLayout)
        self._mainLay.addLayout(_btmLayout)

        self.resize(QtCore.QSize(900, 500))
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose,
                          True)  # for reimport convenience.
        self.setTabOrder(self._rootDirLE, self._treeFilterLE)
        self.setTabOrder(self._treeFilterLE, self._view)
        self.setTabOrder(self._view, self._logBrowser)
        self.setWindowIcon(self._iutestIcon)
        self.setWindowFlags(QtCore.Qt.Window)

        self._updateWindowTitle()
        self._loadLastDirsFromSettings()
        self._restorePanelVisState()

        self.resetUiTestManager()

        QtCore.QTimer.singleShot(0, self._initialLoad)