forked from qt-creator/qt-creator
Squish: Redo running test cases
Start allowing interactions with the AUT which enables interrupting and debugging the test cases. Use a debugger perspective for interaction and provide a control bar which is visible while running test cases. Change-Id: I2c9fde51263516c38e814c91241d3ed3489ecacb Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
add_qtc_plugin(Squish
|
add_qtc_plugin(Squish
|
||||||
PLUGIN_DEPENDS
|
PLUGIN_DEPENDS
|
||||||
Core
|
Core Debugger TextEditor
|
||||||
DEPENDS ExtensionSystem Utils
|
DEPENDS ExtensionSystem Utils
|
||||||
SOURCES
|
SOURCES
|
||||||
deletesymbolicnamedialog.cpp deletesymbolicnamedialog.h
|
deletesymbolicnamedialog.cpp deletesymbolicnamedialog.h
|
||||||
@@ -15,6 +15,7 @@ add_qtc_plugin(Squish
|
|||||||
squishfilehandler.cpp squishfilehandler.h
|
squishfilehandler.cpp squishfilehandler.h
|
||||||
squishnavigationwidget.cpp squishnavigationwidget.h
|
squishnavigationwidget.cpp squishnavigationwidget.h
|
||||||
squishoutputpane.cpp squishoutputpane.h
|
squishoutputpane.cpp squishoutputpane.h
|
||||||
|
squishperspective.cpp squishperspective.h
|
||||||
squishplugin.cpp squishplugin.h
|
squishplugin.cpp squishplugin.h
|
||||||
squishresultmodel.cpp squishresultmodel.h
|
squishresultmodel.cpp squishresultmodel.h
|
||||||
squishsettings.cpp squishsettings.h
|
squishsettings.cpp squishsettings.h
|
||||||
|
@@ -4,56 +4,60 @@ QtcPlugin {
|
|||||||
name: "Squish"
|
name: "Squish"
|
||||||
|
|
||||||
Depends { name: "Core" }
|
Depends { name: "Core" }
|
||||||
|
Depends { name: "Debugger" }
|
||||||
|
Depends { name: "TextEditor" }
|
||||||
Depends { name: "Utils" }
|
Depends { name: "Utils" }
|
||||||
|
|
||||||
Depends { name: "Qt.widgets" }
|
Depends { name: "Qt.widgets" }
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
"squish.qrc",
|
|
||||||
"squishplugin_global.h",
|
|
||||||
"squishconstants.h",
|
|
||||||
"squishplugin.cpp",
|
|
||||||
"squishplugin.h",
|
|
||||||
"squishsettings.cpp",
|
|
||||||
"squishsettings.h",
|
|
||||||
"squishnavigationwidget.cpp",
|
|
||||||
"squishnavigationwidget.h",
|
|
||||||
"squishoutputpane.cpp",
|
|
||||||
"squishoutputpane.h",
|
|
||||||
"squishtesttreemodel.cpp",
|
|
||||||
"squishtesttreemodel.h",
|
|
||||||
"squishtesttreeview.cpp",
|
|
||||||
"squishtesttreeview.h",
|
|
||||||
"squishfilehandler.cpp",
|
|
||||||
"squishfilehandler.h",
|
|
||||||
"opensquishsuitesdialog.cpp",
|
|
||||||
"opensquishsuitesdialog.h",
|
|
||||||
"squishutils.cpp",
|
|
||||||
"squishutils.h",
|
|
||||||
"squishtools.cpp",
|
|
||||||
"squishtools.h",
|
|
||||||
"squishtr.h",
|
|
||||||
"squishxmloutputhandler.cpp",
|
|
||||||
"squishxmloutputhandler.h",
|
|
||||||
"testresult.cpp",
|
|
||||||
"testresult.h",
|
|
||||||
"squishresultmodel.cpp",
|
|
||||||
"squishresultmodel.h",
|
|
||||||
"deletesymbolicnamedialog.cpp",
|
"deletesymbolicnamedialog.cpp",
|
||||||
"deletesymbolicnamedialog.h",
|
"deletesymbolicnamedialog.h",
|
||||||
"objectsmapdocument.cpp",
|
"objectsmapdocument.cpp",
|
||||||
"objectsmapdocument.h",
|
"objectsmapdocument.h",
|
||||||
"objectsmaptreeitem.cpp",
|
|
||||||
"objectsmaptreeitem.h",
|
|
||||||
"propertytreeitem.cpp",
|
|
||||||
"propertytreeitem.h",
|
|
||||||
"objectsmapeditorwidget.cpp",
|
|
||||||
"objectsmapeditorwidget.h",
|
|
||||||
"objectsmapeditor.cpp",
|
"objectsmapeditor.cpp",
|
||||||
"objectsmapeditor.h",
|
"objectsmapeditor.h",
|
||||||
|
"objectsmapeditorwidget.cpp",
|
||||||
|
"objectsmapeditorwidget.h",
|
||||||
|
"objectsmaptreeitem.cpp",
|
||||||
|
"objectsmaptreeitem.h",
|
||||||
|
"opensquishsuitesdialog.cpp",
|
||||||
|
"opensquishsuitesdialog.h",
|
||||||
"propertyitemdelegate.cpp",
|
"propertyitemdelegate.cpp",
|
||||||
"propertyitemdelegate.h",
|
"propertyitemdelegate.h",
|
||||||
|
"propertytreeitem.cpp",
|
||||||
|
"propertytreeitem.h",
|
||||||
|
"squish.qrc",
|
||||||
|
"squishconstants.h",
|
||||||
|
"squishfilehandler.cpp",
|
||||||
|
"squishfilehandler.h",
|
||||||
|
"squishnavigationwidget.cpp",
|
||||||
|
"squishnavigationwidget.h",
|
||||||
|
"squishoutputpane.cpp",
|
||||||
|
"squishoutputpane.h",
|
||||||
|
"squishperspective.cpp",
|
||||||
|
"squishperspective.h",
|
||||||
|
"squishplugin.cpp",
|
||||||
|
"squishplugin.h",
|
||||||
|
"squishplugin_global.h",
|
||||||
|
"squishresultmodel.cpp",
|
||||||
|
"squishresultmodel.h",
|
||||||
|
"squishsettings.cpp",
|
||||||
|
"squishsettings.h",
|
||||||
|
"squishtesttreemodel.cpp",
|
||||||
|
"squishtesttreemodel.h",
|
||||||
|
"squishtesttreeview.cpp",
|
||||||
|
"squishtesttreeview.h",
|
||||||
|
"squishtools.cpp",
|
||||||
|
"squishtools.h",
|
||||||
|
"squishtr.h",
|
||||||
|
"squishutils.cpp",
|
||||||
|
"squishutils.h",
|
||||||
|
"squishxmloutputhandler.cpp",
|
||||||
|
"squishxmloutputhandler.h",
|
||||||
"symbolnameitemdelegate.cpp",
|
"symbolnameitemdelegate.cpp",
|
||||||
"symbolnameitemdelegate.h"
|
"symbolnameitemdelegate.h",
|
||||||
|
"testresult.cpp",
|
||||||
|
"testresult.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
457
src/plugins/squish/squishperspective.cpp
Normal file
457
src/plugins/squish/squishperspective.cpp
Normal file
@@ -0,0 +1,457 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "squishperspective.h"
|
||||||
|
|
||||||
|
#include "squishtools.h"
|
||||||
|
#include "squishtr.h"
|
||||||
|
#include "squishxmloutputhandler.h"
|
||||||
|
|
||||||
|
#include <debugger/analyzer/analyzermanager.h>
|
||||||
|
#include <debugger/debuggericons.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <utils/itemviews.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/theme/theme.h>
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace Squish {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
static QString stateName(SquishPerspective::State state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case SquishPerspective::State::None: return "None";
|
||||||
|
case SquishPerspective::State::Starting: return "Starting";
|
||||||
|
case SquishPerspective::State::Running: return "Running";
|
||||||
|
case SquishPerspective::State::RunRequested: return "RunRequested";
|
||||||
|
case SquishPerspective::State::StepInRequested: return "StepInRequested";
|
||||||
|
case SquishPerspective::State::StepOverRequested: return "StepOverRequested";
|
||||||
|
case SquishPerspective::State::StepReturnRequested: return "StepReturnRequested";
|
||||||
|
case SquishPerspective::State::Interrupted: return "Interrupted";
|
||||||
|
case SquishPerspective::State::InterruptRequested: return "InterruptedRequested";
|
||||||
|
case SquishPerspective::State::Canceling: return "Canceling";
|
||||||
|
case SquishPerspective::State::Canceled: return "Canceled";
|
||||||
|
case SquishPerspective::State::CancelRequested: return "CancelRequested";
|
||||||
|
case SquishPerspective::State::CancelRequestedWhileInterrupted: return "CancelRequestedWhileInterrupted";
|
||||||
|
case SquishPerspective::State::Finished: return "Finished";
|
||||||
|
}
|
||||||
|
return "ThouShallNotBeHere";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IconType { StopRecord, Play, Pause, StepIn, StepOver, StepReturn, Stop };
|
||||||
|
|
||||||
|
static QIcon iconForType(IconType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case StopRecord:
|
||||||
|
return QIcon();
|
||||||
|
case Play:
|
||||||
|
return Debugger::Icons::DEBUG_CONTINUE_SMALL_TOOLBAR.icon();
|
||||||
|
case Pause:
|
||||||
|
return Utils::Icons::INTERRUPT_SMALL.icon();
|
||||||
|
case StepIn:
|
||||||
|
return Debugger::Icons::STEP_INTO_TOOLBAR.icon();
|
||||||
|
case StepOver:
|
||||||
|
return Debugger::Icons::STEP_OVER_TOOLBAR.icon();
|
||||||
|
case StepReturn:
|
||||||
|
return Debugger::Icons::STEP_OUT_TOOLBAR.icon();
|
||||||
|
case Stop:
|
||||||
|
return Utils::Icons::STOP_SMALL.icon();
|
||||||
|
}
|
||||||
|
return QIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static QString customStyleSheet(bool extended)
|
||||||
|
{
|
||||||
|
static const QString red = Utils::creatorTheme()->color(
|
||||||
|
Utils::Theme::ProgressBarColorError).name();
|
||||||
|
static const QString green = Utils::creatorTheme()->color(
|
||||||
|
Utils::Theme::ProgressBarColorFinished).name();
|
||||||
|
if (!extended)
|
||||||
|
return "QProgressBar {text-align:left; border:0px}";
|
||||||
|
return QString("QProgressBar {background:%1; text-align:left; border:0px}"
|
||||||
|
"QProgressBar::chunk {background:%2; border:0px}").arg(red, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QStringList splitDebugContent(const QString &content)
|
||||||
|
{
|
||||||
|
if (content.isEmpty())
|
||||||
|
return {};
|
||||||
|
QStringList symbols;
|
||||||
|
int delimiter = -1;
|
||||||
|
int start = 0;
|
||||||
|
do {
|
||||||
|
delimiter = content.indexOf(',', delimiter + 1);
|
||||||
|
if (delimiter > 0 && content.at(delimiter - 1) == '\\')
|
||||||
|
continue;
|
||||||
|
symbols.append(content.mid(start, delimiter - start));
|
||||||
|
start = delimiter + 1;
|
||||||
|
} while (delimiter >= 0);
|
||||||
|
return symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant LocalsItem::data(int column, int role) const
|
||||||
|
{
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
switch (column) {
|
||||||
|
case 0: return name;
|
||||||
|
case 1: return type;
|
||||||
|
case 2: return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TreeItem::data(column, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SquishControlBar : public QDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SquishControlBar(SquishPerspective *perspective);
|
||||||
|
|
||||||
|
void increaseFailCounter() { ++m_fails; updateProgressBar(); }
|
||||||
|
void increasePassCounter() { ++m_passes; updateProgressBar(); }
|
||||||
|
void updateProgressText(const QString &label);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *) override
|
||||||
|
{
|
||||||
|
m_perspective->onStopTriggered();
|
||||||
|
}
|
||||||
|
void resizeEvent(QResizeEvent *) override
|
||||||
|
{
|
||||||
|
updateProgressText(m_labelText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateProgressBar();
|
||||||
|
|
||||||
|
SquishPerspective *m_perspective = nullptr;
|
||||||
|
QToolBar *m_toolBar = nullptr;
|
||||||
|
QProgressBar *m_progress = nullptr;
|
||||||
|
QString m_labelText;
|
||||||
|
int m_passes = 0;
|
||||||
|
int m_fails = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
SquishControlBar::SquishControlBar(SquishPerspective *perspective)
|
||||||
|
: QDialog()
|
||||||
|
, m_perspective(perspective)
|
||||||
|
{
|
||||||
|
setWindowTitle(Tr::tr("Control Bar"));
|
||||||
|
setWindowFlags(Qt::Widget | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
mainLayout->addWidget(m_toolBar = new QToolBar(this));
|
||||||
|
// for now
|
||||||
|
m_toolBar->addAction(perspective->m_pausePlayAction);
|
||||||
|
m_toolBar->addAction(perspective->m_stopAction);
|
||||||
|
|
||||||
|
mainLayout->addWidget(m_progress = new QProgressBar(this));
|
||||||
|
m_progress->setMinimumHeight(48);
|
||||||
|
m_progress->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
|
||||||
|
m_progress->setStyleSheet(customStyleSheet(false));
|
||||||
|
m_progress->setFormat(QString());
|
||||||
|
m_progress->setValue(0);
|
||||||
|
QPalette palette = Utils::creatorTheme()->palette();
|
||||||
|
m_progress->setPalette(palette);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishControlBar::updateProgressBar()
|
||||||
|
{
|
||||||
|
const int allCounted = m_passes + m_fails;
|
||||||
|
if (allCounted == 0)
|
||||||
|
return;
|
||||||
|
if (allCounted == 1)
|
||||||
|
m_progress->setStyleSheet(customStyleSheet(true));
|
||||||
|
|
||||||
|
m_progress->setRange(0, allCounted);
|
||||||
|
m_progress->setValue(m_passes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishControlBar::updateProgressText(const QString &label)
|
||||||
|
{
|
||||||
|
const QString status = m_progress->fontMetrics().elidedText(label, Qt::ElideMiddle,
|
||||||
|
m_progress->width());
|
||||||
|
if (!status.isEmpty()) {
|
||||||
|
m_labelText = label;
|
||||||
|
m_progress->setFormat(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SquishPerspective::SquishPerspective()
|
||||||
|
: Utils::Perspective("Squish.Perspective", Tr::tr("Squish"))
|
||||||
|
{
|
||||||
|
Core::ICore::addPreCloseListener([this]{
|
||||||
|
destroyControlBar();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::initPerspective()
|
||||||
|
{
|
||||||
|
m_pausePlayAction = new QAction(this);
|
||||||
|
m_pausePlayAction->setIcon(iconForType(Pause));
|
||||||
|
m_pausePlayAction->setToolTip(Tr::tr("Interrupt"));
|
||||||
|
m_pausePlayAction->setEnabled(false);
|
||||||
|
m_stepInAction = new QAction(this);
|
||||||
|
m_stepInAction->setIcon(iconForType(StepIn));
|
||||||
|
m_stepInAction->setToolTip(Tr::tr("Step Into"));
|
||||||
|
m_stepInAction->setEnabled(false);
|
||||||
|
m_stepOverAction = new QAction(this);
|
||||||
|
m_stepOverAction->setIcon(iconForType(StepOver));
|
||||||
|
m_stepOverAction->setToolTip(Tr::tr("Step Over"));
|
||||||
|
m_stepOverAction->setEnabled(false);
|
||||||
|
m_stepOutAction = new QAction(this);
|
||||||
|
m_stepOutAction->setIcon(iconForType(StepReturn));
|
||||||
|
m_stepOutAction->setToolTip(Tr::tr("Step Out"));
|
||||||
|
m_stepOutAction->setEnabled(false);
|
||||||
|
m_stopAction = Debugger::createStopAction();
|
||||||
|
m_stopAction->setEnabled(false);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
mainLayout->setSpacing(1);
|
||||||
|
|
||||||
|
m_localsModel.setHeader({Tr::tr("Name"), Tr::tr("Type"), Tr::tr("Value")});
|
||||||
|
auto localsView = new Utils::TreeView;
|
||||||
|
localsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
localsView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
localsView->setModel(&m_localsModel);
|
||||||
|
localsView->setRootIsDecorated(true);
|
||||||
|
mainLayout->addWidget(localsView);
|
||||||
|
QWidget *mainWidget = new QWidget;
|
||||||
|
mainWidget->setObjectName("SquishLocalsView");
|
||||||
|
mainWidget->setWindowTitle(Tr::tr("Squish Locals"));
|
||||||
|
mainWidget->setLayout(mainLayout);
|
||||||
|
|
||||||
|
addToolBarAction(m_pausePlayAction);
|
||||||
|
addToolBarAction(m_stepInAction);
|
||||||
|
addToolBarAction(m_stepOverAction);
|
||||||
|
addToolBarAction(m_stepOutAction);
|
||||||
|
addToolBarAction(m_stopAction);
|
||||||
|
addToolbarSeparator();
|
||||||
|
m_status = new QLabel;
|
||||||
|
addToolBarWidget(m_status);
|
||||||
|
|
||||||
|
addWindow(mainWidget, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea);
|
||||||
|
|
||||||
|
connect(m_pausePlayAction, &QAction::triggered, this, &SquishPerspective::onPausePlayTriggered);
|
||||||
|
connect(m_stepInAction, &QAction::triggered, this, [this] {
|
||||||
|
setState(State::StepInRequested);
|
||||||
|
});
|
||||||
|
connect(m_stepOverAction, &QAction::triggered, this, [this] {
|
||||||
|
setState(State::StepOverRequested);
|
||||||
|
});
|
||||||
|
connect(m_stepOutAction, &QAction::triggered, this, [this] {
|
||||||
|
setState(State::StepReturnRequested);
|
||||||
|
});
|
||||||
|
connect(m_stopAction, &QAction::triggered, this, &SquishPerspective::onStopTriggered);
|
||||||
|
|
||||||
|
connect(SquishTools::instance(), &SquishTools::localsUpdated,
|
||||||
|
this, &SquishPerspective::onLocalsUpdated);
|
||||||
|
connect(SquishTools::instance(), &SquishTools::symbolUpdated,
|
||||||
|
this, &SquishPerspective::onLocalsUpdated);
|
||||||
|
connect(localsView, &QTreeView::expanded, this, [this](const QModelIndex &idx) {
|
||||||
|
LocalsItem *item = m_localsModel.itemForIndex(idx);
|
||||||
|
if (QTC_GUARD(item)) {
|
||||||
|
if (item->expanded)
|
||||||
|
return;
|
||||||
|
item->expanded = true;
|
||||||
|
SquishTools::instance()->requestExpansion(item->name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::onStopTriggered()
|
||||||
|
{
|
||||||
|
m_pausePlayAction->setEnabled(false);
|
||||||
|
m_stopAction->setEnabled(false);
|
||||||
|
setState(m_state == State::Interrupted ? State::CancelRequestedWhileInterrupted
|
||||||
|
: State::CancelRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::onPausePlayTriggered()
|
||||||
|
{
|
||||||
|
if (m_state == State::Interrupted)
|
||||||
|
setState(State::RunRequested);
|
||||||
|
else if (m_state == State::Running)
|
||||||
|
setState(State::InterruptRequested);
|
||||||
|
else
|
||||||
|
qDebug() << "###state: " << stateName(m_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::onLocalsUpdated(const QString &output)
|
||||||
|
{
|
||||||
|
static const QRegularExpression regex("\\+(?<name>.+):\\{(?<content>.*)\\}");
|
||||||
|
static const QRegularExpression inner("(?<type>.+)#(?<exp>\\+*+)(?<name>[^=]+)(=(?<value>.+))?");
|
||||||
|
const QRegularExpressionMatch match = regex.match(output);
|
||||||
|
LocalsItem *parent = nullptr;
|
||||||
|
|
||||||
|
bool singleSymbol = match.hasMatch();
|
||||||
|
if (singleSymbol) {
|
||||||
|
const QString name = match.captured("name");
|
||||||
|
parent = m_localsModel.findNonRootItem([name](LocalsItem *it) {
|
||||||
|
return it->name == name;
|
||||||
|
});
|
||||||
|
if (!parent)
|
||||||
|
return;
|
||||||
|
parent->removeChildren();
|
||||||
|
} else {
|
||||||
|
m_localsModel.clear();
|
||||||
|
parent = m_localsModel.rootItem();
|
||||||
|
}
|
||||||
|
const QStringList symbols = splitDebugContent(singleSymbol ? match.captured("content")
|
||||||
|
: output);
|
||||||
|
for (const QString &part : symbols) {
|
||||||
|
const QRegularExpressionMatch iMatch = inner.match(part);
|
||||||
|
QTC_ASSERT(iMatch.hasMatch(), qDebug() << part; continue);
|
||||||
|
if (iMatch.captured("value").startsWith('<'))
|
||||||
|
continue;
|
||||||
|
LocalsItem *l = new LocalsItem(iMatch.captured("name"),
|
||||||
|
iMatch.captured("type"),
|
||||||
|
iMatch.captured("value").replace("\\,", ",")); // TODO
|
||||||
|
if (!iMatch.captured("exp").isEmpty())
|
||||||
|
l->appendChild(new LocalsItem); // add pseudo child
|
||||||
|
parent->appendChild(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::updateStatus(const QString &status)
|
||||||
|
{
|
||||||
|
m_status->setText(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::showControlBar(SquishXmlOutputHandler *xmlOutputHandler)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_controlBar, return);
|
||||||
|
m_controlBar = new SquishControlBar(this);
|
||||||
|
|
||||||
|
connect(xmlOutputHandler, &SquishXmlOutputHandler::increasePassCounter,
|
||||||
|
m_controlBar, &SquishControlBar::increasePassCounter);
|
||||||
|
connect(xmlOutputHandler, &SquishXmlOutputHandler::increaseFailCounter,
|
||||||
|
m_controlBar, &SquishControlBar::increaseFailCounter);
|
||||||
|
connect (xmlOutputHandler, &SquishXmlOutputHandler::updateStatus,
|
||||||
|
m_controlBar, &SquishControlBar::updateProgressText);
|
||||||
|
|
||||||
|
const QRect rect = Core::ICore::dialogParent()->screen()->availableGeometry();
|
||||||
|
m_controlBar->move(rect.width() - m_controlBar->width() - 10, 10);
|
||||||
|
m_controlBar->showNormal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::destroyControlBar()
|
||||||
|
{
|
||||||
|
if (!m_controlBar)
|
||||||
|
return;
|
||||||
|
delete m_controlBar;
|
||||||
|
m_controlBar = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishPerspective::setState(State state)
|
||||||
|
{
|
||||||
|
if (m_state == state) // ignore triggering the state again
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isStateTransitionValid(state)) {
|
||||||
|
qDebug() << "Illegal state transition" << stateName(m_state) << "->" << stateName(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = state;
|
||||||
|
m_localsModel.clear();
|
||||||
|
emit stateChanged(state);
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case State::Running:
|
||||||
|
case State::Interrupted:
|
||||||
|
m_pausePlayAction->setEnabled(true);
|
||||||
|
if (m_state == State::Interrupted) {
|
||||||
|
m_pausePlayAction->setIcon(iconForType(Play));
|
||||||
|
m_pausePlayAction->setToolTip(Tr::tr("Continue"));
|
||||||
|
m_stepInAction->setEnabled(true);
|
||||||
|
m_stepOverAction->setEnabled(true);
|
||||||
|
m_stepOutAction->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
m_pausePlayAction->setIcon(iconForType(Pause));
|
||||||
|
m_pausePlayAction->setToolTip(Tr::tr("Interrupt"));
|
||||||
|
m_stepInAction->setEnabled(false);
|
||||||
|
m_stepOverAction->setEnabled(false);
|
||||||
|
m_stepOutAction->setEnabled(false);
|
||||||
|
}
|
||||||
|
m_stopAction->setEnabled(true);
|
||||||
|
break;
|
||||||
|
case State::RunRequested:
|
||||||
|
case State::Starting:
|
||||||
|
case State::StepInRequested:
|
||||||
|
case State::StepOverRequested:
|
||||||
|
case State::StepReturnRequested:
|
||||||
|
case State::InterruptRequested:
|
||||||
|
case State::CancelRequested:
|
||||||
|
case State::CancelRequestedWhileInterrupted:
|
||||||
|
case State::Canceled:
|
||||||
|
case State::Finished:
|
||||||
|
m_pausePlayAction->setIcon(iconForType(Pause));
|
||||||
|
m_pausePlayAction->setToolTip(Tr::tr("Interrupt"));
|
||||||
|
m_pausePlayAction->setEnabled(false);
|
||||||
|
m_stepInAction->setEnabled(false);
|
||||||
|
m_stepOverAction->setEnabled(false);
|
||||||
|
m_stepOutAction->setEnabled(false);
|
||||||
|
m_stopAction->setEnabled(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SquishPerspective::isStateTransitionValid(State newState) const
|
||||||
|
{
|
||||||
|
if (newState == State::Finished || newState == State::CancelRequested)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case State::None:
|
||||||
|
return newState == State::Starting;
|
||||||
|
case State::Starting:
|
||||||
|
return newState == State::RunRequested;
|
||||||
|
case State::Running:
|
||||||
|
return newState == State::Interrupted
|
||||||
|
|| newState == State::InterruptRequested;
|
||||||
|
case State::RunRequested:
|
||||||
|
case State::StepInRequested:
|
||||||
|
case State::StepOverRequested:
|
||||||
|
case State::StepReturnRequested:
|
||||||
|
return newState == State::Running;
|
||||||
|
case State::Interrupted:
|
||||||
|
return newState == State::RunRequested
|
||||||
|
|| newState == State::StepInRequested
|
||||||
|
|| newState == State::StepOverRequested
|
||||||
|
|| newState == State::StepReturnRequested
|
||||||
|
|| newState == State::CancelRequestedWhileInterrupted;
|
||||||
|
case State::InterruptRequested:
|
||||||
|
return newState == State::Interrupted;
|
||||||
|
case State::Canceling:
|
||||||
|
return newState == State::Canceled;
|
||||||
|
case State::Canceled:
|
||||||
|
return newState == State::None;
|
||||||
|
case State::CancelRequested:
|
||||||
|
case State::CancelRequestedWhileInterrupted:
|
||||||
|
return newState == State::Canceling;
|
||||||
|
case State::Finished:
|
||||||
|
return newState == State::Starting;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Squish
|
82
src/plugins/squish/squishperspective.h
Normal file
82
src/plugins/squish/squishperspective.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <debugger/debuggermainwindow.h>
|
||||||
|
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
|
namespace Squish {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class SquishXmlOutputHandler;
|
||||||
|
|
||||||
|
class LocalsItem : public Utils::TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LocalsItem() = default;
|
||||||
|
LocalsItem(const QString &n, const QString &t, const QString &v) : name(n), type(t), value(v) {}
|
||||||
|
QVariant data(int column, int role) const override;
|
||||||
|
QString name;
|
||||||
|
QString type;
|
||||||
|
QString value;
|
||||||
|
bool expanded = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SquishPerspective : public Utils::Perspective
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum class State {
|
||||||
|
None,
|
||||||
|
Starting,
|
||||||
|
Running,
|
||||||
|
RunRequested,
|
||||||
|
StepInRequested,
|
||||||
|
StepOverRequested,
|
||||||
|
StepReturnRequested,
|
||||||
|
Interrupted,
|
||||||
|
InterruptRequested,
|
||||||
|
Canceling,
|
||||||
|
Canceled,
|
||||||
|
CancelRequested,
|
||||||
|
CancelRequestedWhileInterrupted,
|
||||||
|
Finished
|
||||||
|
};
|
||||||
|
|
||||||
|
SquishPerspective();
|
||||||
|
void initPerspective();
|
||||||
|
|
||||||
|
State state() const { return m_state; }
|
||||||
|
void setState(State state);
|
||||||
|
void updateStatus(const QString &status);
|
||||||
|
|
||||||
|
void showControlBar(SquishXmlOutputHandler *xmlOutputHandler);
|
||||||
|
void destroyControlBar();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void stateChanged(State state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onStopTriggered();
|
||||||
|
void onPausePlayTriggered();
|
||||||
|
void onLocalsUpdated(const QString &output);
|
||||||
|
bool isStateTransitionValid(State newState) const;
|
||||||
|
|
||||||
|
QAction *m_pausePlayAction = nullptr;
|
||||||
|
QAction *m_stepInAction = nullptr;
|
||||||
|
QAction *m_stepOverAction = nullptr;
|
||||||
|
QAction *m_stepOutAction = nullptr;
|
||||||
|
QAction *m_stopAction = nullptr;
|
||||||
|
QLabel *m_status = nullptr;
|
||||||
|
class SquishControlBar *m_controlBar = nullptr;
|
||||||
|
Utils::TreeModel<LocalsItem> m_localsModel;
|
||||||
|
State m_state = State::None;
|
||||||
|
|
||||||
|
friend class SquishControlBar;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Squish
|
||||||
|
|
@@ -102,6 +102,13 @@ bool SquishPlugin::initialize(const QStringList &, QString *)
|
|||||||
|
|
||||||
ExtensionSystem::IPlugin::ShutdownFlag SquishPlugin::aboutToShutdown()
|
ExtensionSystem::IPlugin::ShutdownFlag SquishPlugin::aboutToShutdown()
|
||||||
{
|
{
|
||||||
|
if (dd->m_squishTools) {
|
||||||
|
if (dd->m_squishTools->shutdown())
|
||||||
|
return SynchronousShutdown;
|
||||||
|
connect(dd->m_squishTools, &SquishTools::shutdownFinished,
|
||||||
|
this, &ExtensionSystem::IPlugin::asynchronousShutdownFinished);
|
||||||
|
return AsynchronousShutdown;
|
||||||
|
}
|
||||||
return SynchronousShutdown;
|
return SynchronousShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -73,6 +73,12 @@ SquishSettings::SquishSettings()
|
|||||||
verbose.setLabel(Tr::tr("Verbose log"));
|
verbose.setLabel(Tr::tr("Verbose log"));
|
||||||
verbose.setDefaultValue(false);
|
verbose.setDefaultValue(false);
|
||||||
|
|
||||||
|
registerAspect(&minimizeIDE);
|
||||||
|
minimizeIDE.setSettingsKey("MinimizeIDE");
|
||||||
|
minimizeIDE.setLabel(Tr::tr("Minimize IDE"));
|
||||||
|
minimizeIDE.setToolTip(Tr::tr("Minimize IDE automatically while running or recording test cases."));
|
||||||
|
minimizeIDE.setDefaultValue(true);
|
||||||
|
|
||||||
connect(&local, &BoolAspect::volatileValueChanged,
|
connect(&local, &BoolAspect::volatileValueChanged,
|
||||||
this, [this] (bool checked) {
|
this, [this] (bool checked) {
|
||||||
serverHost.setEnabled(!checked);
|
serverHost.setEnabled(!checked);
|
||||||
@@ -100,6 +106,7 @@ SquishSettingsPage::SquishSettingsPage(SquishSettings *settings)
|
|||||||
s.licensePath, br,
|
s.licensePath, br,
|
||||||
Span {2, Row { s.local, s.serverHost, s.serverPort } }, br,
|
Span {2, Row { s.local, s.serverHost, s.serverPort } }, br,
|
||||||
s.verbose, br,
|
s.verbose, br,
|
||||||
|
s.minimizeIDE, br,
|
||||||
};
|
};
|
||||||
Column { Row { grid }, st }.attachTo(widget);
|
Column { Row { grid }, st }.attachTo(widget);
|
||||||
});
|
});
|
||||||
|
@@ -28,6 +28,7 @@ public:
|
|||||||
Utils::IntegerAspect serverPort;
|
Utils::IntegerAspect serverPort;
|
||||||
Utils::BoolAspect local;
|
Utils::BoolAspect local;
|
||||||
Utils::BoolAspect verbose;
|
Utils::BoolAspect verbose;
|
||||||
|
Utils::BoolAspect minimizeIDE;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SquishSettingsPage final : public Core::IOptionsPage
|
class SquishSettingsPage final : public Core::IOptionsPage
|
||||||
|
@@ -11,10 +11,16 @@
|
|||||||
|
|
||||||
#include <QDebug> // TODO remove
|
#include <QDebug> // TODO remove
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <debugger/breakhandler.h>
|
||||||
|
#include <debugger/debuggerconstants.h>
|
||||||
|
#include <debugger/debuggericons.h>
|
||||||
|
#include <texteditor/textmark.h>
|
||||||
|
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
@@ -30,6 +36,17 @@ using namespace Utils;
|
|||||||
namespace Squish {
|
namespace Squish {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class SquishLocationMark : public TextEditor::TextMark
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SquishLocationMark(const FilePath &filePath, int line)
|
||||||
|
: TextEditor::TextMark(filePath, line, Id("Squish.LocationMark"))
|
||||||
|
{
|
||||||
|
setIcon(Debugger::Icons::LOCATION.icon());
|
||||||
|
setPriority(HighPriority);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// make this configurable?
|
// make this configurable?
|
||||||
static const QString resultsDirectory = QFileInfo(QDir::home(), ".squishQC/Test Results")
|
static const QString resultsDirectory = QFileInfo(QDir::home(), ".squishQC/Test Results")
|
||||||
.absoluteFilePath();
|
.absoluteFilePath();
|
||||||
@@ -47,6 +64,11 @@ SquishTools::SquishTools(QObject *parent)
|
|||||||
connect(this, &SquishTools::squishTestRunFinished,
|
connect(this, &SquishTools::squishTestRunFinished,
|
||||||
outputPane, &SquishOutputPane::onTestRunFinished);
|
outputPane, &SquishOutputPane::onTestRunFinished);
|
||||||
|
|
||||||
|
m_runnerProcess.setProcessMode(ProcessMode::Writer);
|
||||||
|
|
||||||
|
m_runnerProcess.setStdOutLineCallback([this](const QString &line) {
|
||||||
|
onRunnerStdOutput(line);
|
||||||
|
});
|
||||||
connect(&m_runnerProcess, &QtcProcess::readyReadStandardError,
|
connect(&m_runnerProcess, &QtcProcess::readyReadStandardError,
|
||||||
this, &SquishTools::onRunnerErrorOutput);
|
this, &SquishTools::onRunnerErrorOutput);
|
||||||
connect(&m_runnerProcess, &QtcProcess::done,
|
connect(&m_runnerProcess, &QtcProcess::done,
|
||||||
@@ -59,9 +81,16 @@ SquishTools::SquishTools(QObject *parent)
|
|||||||
connect(&m_serverProcess, &QtcProcess::done,
|
connect(&m_serverProcess, &QtcProcess::done,
|
||||||
this, &SquishTools::onServerFinished);
|
this, &SquishTools::onServerFinished);
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
m_perspective.initPerspective();
|
||||||
|
connect(&m_perspective, &SquishPerspective::stateChanged,
|
||||||
|
this, &SquishTools::onPerspectiveStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
SquishTools::~SquishTools() = default;
|
SquishTools::~SquishTools()
|
||||||
|
{
|
||||||
|
if (m_locationMarker) // happens when QC is closed while Squish is executed
|
||||||
|
delete m_locationMarker;
|
||||||
|
}
|
||||||
|
|
||||||
SquishTools *SquishTools::instance()
|
SquishTools *SquishTools::instance()
|
||||||
{
|
{
|
||||||
@@ -76,8 +105,10 @@ struct SquishToolsSettings
|
|||||||
FilePath squishPath;
|
FilePath squishPath;
|
||||||
FilePath serverPath;
|
FilePath serverPath;
|
||||||
FilePath runnerPath;
|
FilePath runnerPath;
|
||||||
|
FilePath processComPath;
|
||||||
bool isLocalServer = true;
|
bool isLocalServer = true;
|
||||||
bool verboseLog = false;
|
bool verboseLog = false;
|
||||||
|
bool minimizeIDE = true;
|
||||||
QString serverHost = "localhost";
|
QString serverHost = "localhost";
|
||||||
int serverPort = 9999;
|
int serverPort = 9999;
|
||||||
FilePath licenseKeyPath;
|
FilePath licenseKeyPath;
|
||||||
@@ -95,6 +126,8 @@ struct SquishToolsSettings
|
|||||||
HostOsInfo::withExecutableSuffix("squishserver")).absoluteFilePath();
|
HostOsInfo::withExecutableSuffix("squishserver")).absoluteFilePath();
|
||||||
runnerPath = squishBin.pathAppended(
|
runnerPath = squishBin.pathAppended(
|
||||||
HostOsInfo::withExecutableSuffix("squishrunner")).absoluteFilePath();
|
HostOsInfo::withExecutableSuffix("squishrunner")).absoluteFilePath();
|
||||||
|
processComPath = squishBin.pathAppended(
|
||||||
|
HostOsInfo::withExecutableSuffix("processcomm")).absoluteFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
isLocalServer = squishSettings->local.value();
|
isLocalServer = squishSettings->local.value();
|
||||||
@@ -102,14 +135,20 @@ struct SquishToolsSettings
|
|||||||
serverPort = squishSettings->serverPort.value();
|
serverPort = squishSettings->serverPort.value();
|
||||||
verboseLog = squishSettings->verbose.value();
|
verboseLog = squishSettings->verbose.value();
|
||||||
licenseKeyPath = squishSettings->licensePath.filePath();
|
licenseKeyPath = squishSettings->licensePath.filePath();
|
||||||
|
minimizeIDE = squishSettings->minimizeIDE.value();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// make sure to execute setup() to populate with current settings before using it
|
||||||
|
static SquishToolsSettings toolsSettings;
|
||||||
|
|
||||||
void SquishTools::runTestCases(const QString &suitePath,
|
void SquishTools::runTestCases(const QString &suitePath,
|
||||||
const QStringList &testCases,
|
const QStringList &testCases,
|
||||||
const QStringList &additionalServerArgs,
|
const QStringList &additionalServerArgs,
|
||||||
const QStringList &additionalRunnerArgs)
|
const QStringList &additionalRunnerArgs)
|
||||||
{
|
{
|
||||||
|
if (m_shutdownInitiated)
|
||||||
|
return;
|
||||||
if (m_state != Idle) {
|
if (m_state != Idle) {
|
||||||
QMessageBox::critical(Core::ICore::dialogParent(),
|
QMessageBox::critical(Core::ICore::dialogParent(),
|
||||||
Tr::tr("Error"),
|
Tr::tr("Error"),
|
||||||
@@ -142,6 +181,8 @@ void SquishTools::runTestCases(const QString &suitePath,
|
|||||||
connect(this, &SquishTools::resultOutputCreated,
|
connect(this, &SquishTools::resultOutputCreated,
|
||||||
m_xmlOutputHandler.get(), &SquishXmlOutputHandler::outputAvailable,
|
m_xmlOutputHandler.get(), &SquishXmlOutputHandler::outputAvailable,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
connect(m_xmlOutputHandler.get(), &SquishXmlOutputHandler::updateStatus,
|
||||||
|
&m_perspective, &SquishPerspective::updateStatus);
|
||||||
|
|
||||||
m_squishRunnerMode = TestingMode;
|
m_squishRunnerMode = TestingMode;
|
||||||
emit squishTestRunStarted();
|
emit squishTestRunStarted();
|
||||||
@@ -150,6 +191,8 @@ void SquishTools::runTestCases(const QString &suitePath,
|
|||||||
|
|
||||||
void SquishTools::queryServerSettings()
|
void SquishTools::queryServerSettings()
|
||||||
{
|
{
|
||||||
|
if (m_shutdownInitiated)
|
||||||
|
return;
|
||||||
if (m_state != Idle) {
|
if (m_state != Idle) {
|
||||||
QMessageBox::critical(Core::ICore::dialogParent(),
|
QMessageBox::critical(Core::ICore::dialogParent(),
|
||||||
Tr::tr("Error"),
|
Tr::tr("Error"),
|
||||||
@@ -164,6 +207,8 @@ void SquishTools::queryServerSettings()
|
|||||||
|
|
||||||
void SquishTools::writeServerSettingsChanges(const QList<QStringList> &changes)
|
void SquishTools::writeServerSettingsChanges(const QList<QStringList> &changes)
|
||||||
{
|
{
|
||||||
|
if (m_shutdownInitiated)
|
||||||
|
return;
|
||||||
if (m_state != Idle) {
|
if (m_state != Idle) {
|
||||||
QMessageBox::critical(Core::ICore::dialogParent(),
|
QMessageBox::critical(Core::ICore::dialogParent(),
|
||||||
Tr::tr("Error"),
|
Tr::tr("Error"),
|
||||||
@@ -175,7 +220,6 @@ void SquishTools::writeServerSettingsChanges(const QList<QStringList> &changes)
|
|||||||
startSquishServer(ServerConfigChangeRequested);
|
startSquishServer(ServerConfigChangeRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SquishTools::setState(SquishTools::State state)
|
void SquishTools::setState(SquishTools::State state)
|
||||||
{
|
{
|
||||||
// TODO check whether state transition is legal
|
// TODO check whether state transition is legal
|
||||||
@@ -186,6 +230,7 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
m_request = None;
|
m_request = None;
|
||||||
m_suitePath = QString();
|
m_suitePath = QString();
|
||||||
m_testCases.clear();
|
m_testCases.clear();
|
||||||
|
m_currentTestCasePath.clear();
|
||||||
m_reportFiles.clear();
|
m_reportFiles.clear();
|
||||||
m_additionalRunnerArguments.clear();
|
m_additionalRunnerArguments.clear();
|
||||||
m_additionalServerArguments.clear();
|
m_additionalServerArguments.clear();
|
||||||
@@ -211,10 +256,13 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
emit squishTestRunFinished();
|
emit squishTestRunFinished();
|
||||||
m_squishRunnerMode = NoMode;
|
m_squishRunnerMode = NoMode;
|
||||||
}
|
}
|
||||||
|
if (toolsSettings.minimizeIDE)
|
||||||
restoreQtCreatorWindows();
|
restoreQtCreatorWindows();
|
||||||
|
m_perspective.destroyControlBar();
|
||||||
break;
|
break;
|
||||||
case ServerStopped:
|
case ServerStopped:
|
||||||
m_state = Idle;
|
m_state = Idle;
|
||||||
|
emit shutdownFinished();
|
||||||
if (m_request == ServerConfigChangeRequested) {
|
if (m_request == ServerConfigChangeRequested) {
|
||||||
if (m_serverProcess.result() == ProcessResult::FinishedWithError) {
|
if (m_serverProcess.result() == ProcessResult::FinishedWithError) {
|
||||||
emit configChangesFailed(m_serverProcess.error());
|
emit configChangesFailed(m_serverProcess.error());
|
||||||
@@ -232,7 +280,9 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
emit squishTestRunFinished();
|
emit squishTestRunFinished();
|
||||||
m_squishRunnerMode = NoMode;
|
m_squishRunnerMode = NoMode;
|
||||||
}
|
}
|
||||||
|
if (toolsSettings.minimizeIDE)
|
||||||
restoreQtCreatorWindows();
|
restoreQtCreatorWindows();
|
||||||
|
m_perspective.destroyControlBar();
|
||||||
} else if (m_request == KillOldBeforeRunRunner) {
|
} else if (m_request == KillOldBeforeRunRunner) {
|
||||||
startSquishServer(RunTestRequested);
|
startSquishServer(RunTestRequested);
|
||||||
} else if (m_request == KillOldBeforeRecordRunner) {
|
} else if (m_request == KillOldBeforeRecordRunner) {
|
||||||
@@ -245,6 +295,9 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
break;
|
break;
|
||||||
case ServerStopFailed:
|
case ServerStopFailed:
|
||||||
m_serverProcess.close();
|
m_serverProcess.close();
|
||||||
|
if (toolsSettings.minimizeIDE)
|
||||||
|
restoreQtCreatorWindows();
|
||||||
|
m_perspective.destroyControlBar();
|
||||||
m_state = Idle;
|
m_state = Idle;
|
||||||
break;
|
break;
|
||||||
case RunnerStartFailed:
|
case RunnerStartFailed:
|
||||||
@@ -252,7 +305,8 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
if (m_squishRunnerMode == QueryMode) {
|
if (m_squishRunnerMode == QueryMode) {
|
||||||
m_request = ServerStopRequested;
|
m_request = ServerStopRequested;
|
||||||
stopSquishServer();
|
stopSquishServer();
|
||||||
} else if (m_testCases.isEmpty()) {
|
} else if (m_testCases.isEmpty()
|
||||||
|
|| (m_perspective.state() == SquishPerspective::State::Canceled)) {
|
||||||
m_request = ServerStopRequested;
|
m_request = ServerStopRequested;
|
||||||
stopSquishServer();
|
stopSquishServer();
|
||||||
QString error;
|
QString error;
|
||||||
@@ -265,6 +319,7 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
logrotateTestResults();
|
logrotateTestResults();
|
||||||
} else {
|
} else {
|
||||||
m_xmlOutputHandler->clearForNextRun();
|
m_xmlOutputHandler->clearForNextRun();
|
||||||
|
m_perspective.setState(SquishPerspective::State::Starting);
|
||||||
startSquishRunner();
|
startSquishRunner();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -273,11 +328,10 @@ void SquishTools::setState(SquishTools::State state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure to execute setup() to populate with current settings before using it
|
|
||||||
static SquishToolsSettings toolsSettings;
|
|
||||||
|
|
||||||
void SquishTools::startSquishServer(Request request)
|
void SquishTools::startSquishServer(Request request)
|
||||||
{
|
{
|
||||||
|
if (m_shutdownInitiated)
|
||||||
|
return;
|
||||||
m_request = request;
|
m_request = request;
|
||||||
if (m_serverProcess.state() != QProcess::NotRunning) {
|
if (m_serverProcess.state() != QProcess::NotRunning) {
|
||||||
if (QMessageBox::question(Core::ICore::dialogParent(),
|
if (QMessageBox::question(Core::ICore::dialogParent(),
|
||||||
@@ -327,10 +381,15 @@ void SquishTools::startSquishServer(Request request)
|
|||||||
toolsSettings.serverPath = squishServer;
|
toolsSettings.serverPath = squishServer;
|
||||||
|
|
||||||
if (m_squishRunnerMode == TestingMode) {
|
if (m_squishRunnerMode == TestingMode) {
|
||||||
if (true) // TODO squish setting of minimize QC on squish run/record
|
if (toolsSettings.minimizeIDE)
|
||||||
minimizeQtCreatorWindows();
|
minimizeQtCreatorWindows();
|
||||||
else
|
else
|
||||||
m_lastTopLevelWindows.clear();
|
m_lastTopLevelWindows.clear();
|
||||||
|
if (QTC_GUARD(m_xmlOutputHandler))
|
||||||
|
m_perspective.showControlBar(m_xmlOutputHandler.get());
|
||||||
|
|
||||||
|
m_perspective.select();
|
||||||
|
m_perspective.setState(SquishPerspective::State::Starting);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
@@ -392,16 +451,17 @@ void SquishTools::startSquishRunner()
|
|||||||
args << "--port" << QString::number(m_serverPort);
|
args << "--port" << QString::number(m_serverPort);
|
||||||
args << "--debugLog" << "alpw"; // TODO make this configurable?
|
args << "--debugLog" << "alpw"; // TODO make this configurable?
|
||||||
|
|
||||||
const QFileInfo testCasePath(QDir(m_suitePath), m_testCases.takeFirst());
|
m_currentTestCasePath = FilePath::fromString(m_suitePath) / m_testCases.takeFirst();
|
||||||
args << "--testcase" << testCasePath.absoluteFilePath();
|
args << "--testcase" << m_currentTestCasePath.toString();
|
||||||
args << "--suitedir" << m_suitePath;
|
args << "--suitedir" << m_suitePath;
|
||||||
|
args << "--debug" << "--ide";
|
||||||
|
|
||||||
args << m_additionalRunnerArguments;
|
args << m_additionalRunnerArguments;
|
||||||
|
|
||||||
const QString caseReportFilePath = QFileInfo(QString::fromLatin1("%1/%2/%3/results.xml")
|
const QString caseReportFilePath = QFileInfo(QString::fromLatin1("%1/%2/%3/results.xml")
|
||||||
.arg(m_currentResultsDirectory,
|
.arg(m_currentResultsDirectory,
|
||||||
QDir(m_suitePath).dirName(),
|
QDir(m_suitePath).dirName(),
|
||||||
testCasePath.baseName()))
|
m_currentTestCasePath.baseName()))
|
||||||
.absoluteFilePath();
|
.absoluteFilePath();
|
||||||
m_reportFiles.append(caseReportFilePath);
|
m_reportFiles.append(caseReportFilePath);
|
||||||
|
|
||||||
@@ -442,6 +502,11 @@ void SquishTools::onRunnerFinished()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_shutdownInitiated) {
|
||||||
|
m_perspective.setState(SquishPerspective::State::Finished);
|
||||||
|
m_perspective.updateStatus(Tr::tr("Test run finished."));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_resultsFileWatcher) {
|
if (m_resultsFileWatcher) {
|
||||||
delete m_resultsFileWatcher;
|
delete m_resultsFileWatcher;
|
||||||
m_resultsFileWatcher = nullptr;
|
m_resultsFileWatcher = nullptr;
|
||||||
@@ -585,10 +650,180 @@ void SquishTools::onRunnerErrorOutput()
|
|||||||
const QList<QByteArray> lines = output.split('\n');
|
const QList<QByteArray> lines = output.split('\n');
|
||||||
for (const QByteArray &line : lines) {
|
for (const QByteArray &line : lines) {
|
||||||
const QByteArray trimmed = line.trimmed();
|
const QByteArray trimmed = line.trimmed();
|
||||||
if (!trimmed.isEmpty())
|
if (!trimmed.isEmpty()) {
|
||||||
emit logOutputReceived("Runner: " + QLatin1String(trimmed));
|
emit logOutputReceived("Runner: " + QLatin1String(trimmed));
|
||||||
|
if (trimmed.startsWith("QSocketNotifier: Invalid socket")) {
|
||||||
|
// we've lost connection to the AUT - if Interrupted, try to cancel the runner
|
||||||
|
if (m_perspective.state() == SquishPerspective::State::Interrupted)
|
||||||
|
m_perspective.setState(SquishPerspective::State::CancelRequestedWhileInterrupted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::onRunnerStdOutput(const QString &lineIn)
|
||||||
|
{
|
||||||
|
if (m_request == RunnerQueryRequested) // only handle test runs here
|
||||||
|
return;
|
||||||
|
|
||||||
|
int fileLine = -1;
|
||||||
|
int fileColumn = -1;
|
||||||
|
QString fileName;
|
||||||
|
// we might enter this function by invoking it directly instead of getting signaled
|
||||||
|
bool isPrompt = false;
|
||||||
|
QString line = lineIn;
|
||||||
|
line.chop(1); // line has a newline
|
||||||
|
if (line.startsWith("SDBG:"))
|
||||||
|
line = line.mid(5);
|
||||||
|
if (line.isEmpty()) // we have a prompt
|
||||||
|
isPrompt = true;
|
||||||
|
else if (line.startsWith("symb")) { // symbols information (locals)
|
||||||
|
isPrompt = true;
|
||||||
|
// paranoia
|
||||||
|
if (!line.endsWith("}"))
|
||||||
|
return;
|
||||||
|
if (line.at(4) == '.') { // single symbol information
|
||||||
|
line = line.mid(5);
|
||||||
|
emit symbolUpdated(line);
|
||||||
|
} else { // lline.at(4) == ':' // all locals
|
||||||
|
line = line.mid(6);
|
||||||
|
line.chop(1);
|
||||||
|
emit localsUpdated(line);
|
||||||
|
}
|
||||||
|
} else if (line.startsWith("@line")) { // location information (interrupted)
|
||||||
|
isPrompt = true;
|
||||||
|
// paranoia
|
||||||
|
if (!line.endsWith(":"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QStringList locationParts = line.split(',');
|
||||||
|
QTC_ASSERT(locationParts.size() == 3, return);
|
||||||
|
fileLine = locationParts[0].mid(6).toInt();
|
||||||
|
fileColumn = locationParts[1].mid(7).toInt();
|
||||||
|
fileName = locationParts[2].trimmed();
|
||||||
|
fileName.chop(1); // remove the colon
|
||||||
|
const FilePath fp = FilePath::fromString(fileName);
|
||||||
|
if (fp.isRelativePath())
|
||||||
|
fileName = m_currentTestCasePath.resolvePath(fileName).toString();
|
||||||
|
}
|
||||||
|
if (isPrompt)
|
||||||
|
handlePrompt(fileName, fileLine, fileColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: add/removal of breakpoints while debugging not handled yet
|
||||||
|
// FIXME: enabled state of breakpoints
|
||||||
|
void SquishTools::setBreakpoints()
|
||||||
|
{
|
||||||
|
using namespace Debugger::Internal;
|
||||||
|
const GlobalBreakpoints globalBPs = BreakpointManager::globalBreakpoints();
|
||||||
|
for (const GlobalBreakpoint &gb : globalBPs) {
|
||||||
|
if (!gb->isEnabled())
|
||||||
|
continue;
|
||||||
|
auto fileName = Utils::FilePath::fromUserInput(
|
||||||
|
gb->data(BreakpointFileColumn, Qt::DisplayRole).toString()).toUserOutput();
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
continue;
|
||||||
|
// mask backslashes and spaces
|
||||||
|
fileName.replace('\\', "\\\\");
|
||||||
|
fileName.replace(' ', "\\x20");
|
||||||
|
auto line = gb->data(BreakpointLineColumn, Qt::DisplayRole).toInt();
|
||||||
|
QString cmd = "break ";
|
||||||
|
cmd.append(fileName);
|
||||||
|
cmd.append(':');
|
||||||
|
cmd.append(QString::number(line));
|
||||||
|
cmd.append('\n');
|
||||||
|
m_runnerProcess.write(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::handlePrompt(const QString &fileName, int line, int column)
|
||||||
|
{
|
||||||
|
const SquishPerspective::State state = m_perspective.state();
|
||||||
|
switch (state) {
|
||||||
|
case SquishPerspective::State::Starting:
|
||||||
|
setBreakpoints();
|
||||||
|
m_perspective.setState(SquishPerspective::State::RunRequested);
|
||||||
|
break;
|
||||||
|
case SquishPerspective::State::RunRequested:
|
||||||
|
case SquishPerspective::State::StepInRequested:
|
||||||
|
case SquishPerspective::State::StepOverRequested:
|
||||||
|
case SquishPerspective::State::StepReturnRequested:
|
||||||
|
if (m_requestVarsTimer) {
|
||||||
|
delete m_requestVarsTimer;
|
||||||
|
m_requestVarsTimer = nullptr;
|
||||||
|
}
|
||||||
|
if (state == SquishPerspective::State::RunRequested)
|
||||||
|
m_runnerProcess.write("continue\n");
|
||||||
|
else if (state == SquishPerspective::State::StepInRequested)
|
||||||
|
m_runnerProcess.write("step\n");
|
||||||
|
else if (state == SquishPerspective::State::StepOverRequested)
|
||||||
|
m_runnerProcess.write("next\n");
|
||||||
|
else // SquishPerspective::State::StepReturnRequested
|
||||||
|
m_runnerProcess.write("return\n");
|
||||||
|
clearLocationMarker();
|
||||||
|
if (state == SquishPerspective::State::RunRequested && toolsSettings.minimizeIDE)
|
||||||
|
minimizeQtCreatorWindows();
|
||||||
|
m_perspective.setState(SquishPerspective::State::Running);
|
||||||
|
break;
|
||||||
|
case SquishPerspective::State::CancelRequested:
|
||||||
|
case SquishPerspective::State::CancelRequestedWhileInterrupted:
|
||||||
|
m_runnerProcess.write("exit\n");
|
||||||
|
clearLocationMarker();
|
||||||
|
m_perspective.setState(SquishPerspective::State::Canceling);
|
||||||
|
break;
|
||||||
|
case SquishPerspective::State::Canceling:
|
||||||
|
m_runnerProcess.write("quit\n");
|
||||||
|
m_perspective.setState(SquishPerspective::State::Canceled);
|
||||||
|
break;
|
||||||
|
case SquishPerspective::State::Canceled:
|
||||||
|
QTC_CHECK(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (line != -1 && column != -1) {
|
||||||
|
m_perspective.setState(SquishPerspective::State::Interrupted);
|
||||||
|
restoreQtCreatorWindows();
|
||||||
|
// if we're returning from a function we might end up without a file information
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
m_runnerProcess.write("next\n");
|
||||||
|
} else {
|
||||||
|
// request local variables
|
||||||
|
m_runnerProcess.write("print variables\n");
|
||||||
|
const FilePath filePath = FilePath::fromString(fileName);
|
||||||
|
Core::EditorManager::openEditorAt({filePath, line, column});
|
||||||
|
updateLocationMarker(filePath, line);
|
||||||
|
}
|
||||||
|
} else { // it's just some output coming from the server
|
||||||
|
if (m_perspective.state() == SquishPerspective::State::Interrupted && !m_requestVarsTimer) {
|
||||||
|
// FIXME: this should be easier, but when interrupted and AUT is closed
|
||||||
|
// runner does not get notified until continued/canceled
|
||||||
|
m_requestVarsTimer = new QTimer(this);
|
||||||
|
m_requestVarsTimer->setSingleShot(true);
|
||||||
|
m_requestVarsTimer->setInterval(1000);
|
||||||
|
connect(m_requestVarsTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
m_runnerProcess.write("print variables\n");
|
||||||
|
});
|
||||||
|
m_requestVarsTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::requestExpansion(const QString &name)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_perspective.state() == SquishPerspective::State::Interrupted, return);
|
||||||
|
m_runnerProcess.write("print variables +" + name + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SquishTools::shutdown()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_shutdownInitiated, return true);
|
||||||
|
m_shutdownInitiated = true;
|
||||||
|
if (m_runnerProcess.isRunning())
|
||||||
|
terminateRunner();
|
||||||
|
if (m_serverProcess.isRunning())
|
||||||
|
m_serverProcess.stop();
|
||||||
|
return !(m_serverProcess.isRunning() || m_runnerProcess.isRunning());
|
||||||
|
}
|
||||||
|
|
||||||
void SquishTools::onResultsDirChanged(const QString &filePath)
|
void SquishTools::onResultsDirChanged(const QString &filePath)
|
||||||
{
|
{
|
||||||
@@ -636,27 +871,94 @@ void SquishTools::logrotateTestResults()
|
|||||||
|
|
||||||
void SquishTools::minimizeQtCreatorWindows()
|
void SquishTools::minimizeQtCreatorWindows()
|
||||||
{
|
{
|
||||||
m_lastTopLevelWindows = QApplication::topLevelWindows();
|
const QWindowList topLevelWindows = QApplication::topLevelWindows();
|
||||||
QWindowList toBeRemoved;
|
for (QWindow *window : topLevelWindows) {
|
||||||
for (QWindow *window : qAsConst(m_lastTopLevelWindows)) {
|
if (window->flags() & Qt::WindowStaysOnTopHint)
|
||||||
if (window->isVisible())
|
continue;
|
||||||
|
if (window->isVisible()) {
|
||||||
window->showMinimized();
|
window->showMinimized();
|
||||||
else
|
if (!m_lastTopLevelWindows.contains(window)) {
|
||||||
toBeRemoved.append(window);
|
m_lastTopLevelWindows.append(window);
|
||||||
}
|
connect(window, &QWindow::destroyed, this, [this, window]() {
|
||||||
|
|
||||||
for (QWindow *window : qAsConst(toBeRemoved))
|
|
||||||
m_lastTopLevelWindows.removeOne(window);
|
m_lastTopLevelWindows.removeOne(window);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SquishTools::restoreQtCreatorWindows()
|
void SquishTools::restoreQtCreatorWindows()
|
||||||
{
|
{
|
||||||
for (QWindow *window : qAsConst(m_lastTopLevelWindows)) {
|
for (QWindow *window : qAsConst(m_lastTopLevelWindows)) {
|
||||||
|
window->raise();
|
||||||
window->requestActivate();
|
window->requestActivate();
|
||||||
window->showNormal();
|
window->showNormal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SquishTools::updateLocationMarker(const Utils::FilePath &file, int line)
|
||||||
|
{
|
||||||
|
if (QTC_GUARD(!m_locationMarker)) {
|
||||||
|
m_locationMarker = new SquishLocationMark(file, line);
|
||||||
|
} else {
|
||||||
|
m_locationMarker->updateFileName(file);
|
||||||
|
m_locationMarker->move(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::clearLocationMarker()
|
||||||
|
{
|
||||||
|
delete m_locationMarker;
|
||||||
|
m_locationMarker = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::onPerspectiveStateChanged(SquishPerspective::State state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case SquishPerspective::State::InterruptRequested:
|
||||||
|
if (m_runnerProcess.processId() != -1)
|
||||||
|
interruptRunner();
|
||||||
|
break;
|
||||||
|
case SquishPerspective::State::CancelRequested:
|
||||||
|
if (m_runnerProcess.processId() != -1)
|
||||||
|
terminateRunner();
|
||||||
|
break;
|
||||||
|
case SquishPerspective::State::RunRequested:
|
||||||
|
case SquishPerspective::State::StepInRequested:
|
||||||
|
case SquishPerspective::State::StepOverRequested:
|
||||||
|
case SquishPerspective::State::StepReturnRequested:
|
||||||
|
case SquishPerspective::State::CancelRequestedWhileInterrupted:
|
||||||
|
handlePrompt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::interruptRunner()
|
||||||
|
{
|
||||||
|
const CommandLine cmd(toolsSettings.processComPath,
|
||||||
|
{QString::number(m_runnerProcess.processId()), "break"});
|
||||||
|
QtcProcess process;
|
||||||
|
process.setCommand(cmd);
|
||||||
|
process.start();
|
||||||
|
process.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SquishTools::terminateRunner()
|
||||||
|
{
|
||||||
|
m_testCases.clear();
|
||||||
|
m_currentTestCasePath.clear();
|
||||||
|
m_perspective.updateStatus(Tr::tr("User stop initiated."));
|
||||||
|
// should we terminate the AUT instead of the runner?!?
|
||||||
|
const CommandLine cmd(toolsSettings.processComPath,
|
||||||
|
{QString::number(m_runnerProcess.processId()), "terminate"});
|
||||||
|
QtcProcess process;
|
||||||
|
process.setCommand(cmd);
|
||||||
|
process.start();
|
||||||
|
process.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
bool SquishTools::isValidToStartRunner()
|
bool SquishTools::isValidToStartRunner()
|
||||||
{
|
{
|
||||||
if (!m_serverProcess.isRunning()) {
|
if (!m_serverProcess.isRunning()) {
|
||||||
|
@@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "squishperspective.h"
|
||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QWindowList>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -51,6 +52,9 @@ public:
|
|||||||
const QStringList &additionalRunnerArgs = QStringList());
|
const QStringList &additionalRunnerArgs = QStringList());
|
||||||
void queryServerSettings();
|
void queryServerSettings();
|
||||||
void writeServerSettingsChanges(const QList<QStringList> &changes);
|
void writeServerSettingsChanges(const QList<QStringList> &changes);
|
||||||
|
void requestExpansion(const QString &name);
|
||||||
|
|
||||||
|
bool shutdown();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void logOutputReceived(const QString &output);
|
void logOutputReceived(const QString &output);
|
||||||
@@ -60,6 +64,9 @@ signals:
|
|||||||
void queryFinished(const QByteArray &output);
|
void queryFinished(const QByteArray &output);
|
||||||
void configChangesFailed(QProcess::ProcessError error);
|
void configChangesFailed(QProcess::ProcessError error);
|
||||||
void configChangesWritten();
|
void configChangesWritten();
|
||||||
|
void localsUpdated(const QString &output);
|
||||||
|
void symbolUpdated(const QString &output);
|
||||||
|
void shutdownFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Request {
|
enum Request {
|
||||||
@@ -84,17 +91,26 @@ private:
|
|||||||
void onRunnerFinished();
|
void onRunnerFinished();
|
||||||
void onServerOutput();
|
void onServerOutput();
|
||||||
void onServerErrorOutput();
|
void onServerErrorOutput();
|
||||||
void onRunnerOutput();
|
void onRunnerOutput(); // runner's results file
|
||||||
void onRunnerErrorOutput();
|
void onRunnerErrorOutput(); // runner's error stream
|
||||||
|
void onRunnerStdOutput(const QString &line); // runner's output stream
|
||||||
|
void setBreakpoints();
|
||||||
|
void handlePrompt(const QString &fileName = {}, int line = -1, int column = -1);
|
||||||
void onResultsDirChanged(const QString &filePath);
|
void onResultsDirChanged(const QString &filePath);
|
||||||
static void logrotateTestResults();
|
static void logrotateTestResults();
|
||||||
void minimizeQtCreatorWindows();
|
void minimizeQtCreatorWindows();
|
||||||
void restoreQtCreatorWindows();
|
void restoreQtCreatorWindows();
|
||||||
|
void updateLocationMarker(const Utils::FilePath &file, int line);
|
||||||
|
void clearLocationMarker();
|
||||||
|
void onPerspectiveStateChanged(SquishPerspective::State state);
|
||||||
|
void interruptRunner();
|
||||||
|
void terminateRunner();
|
||||||
bool isValidToStartRunner();
|
bool isValidToStartRunner();
|
||||||
bool setupRunnerPath();
|
bool setupRunnerPath();
|
||||||
void setupAndStartSquishRunnerProcess(const QStringList &arg,
|
void setupAndStartSquishRunnerProcess(const QStringList &arg,
|
||||||
const QString &caseReportFilePath = {});
|
const QString &caseReportFilePath = {});
|
||||||
|
|
||||||
|
SquishPerspective m_perspective;
|
||||||
std::unique_ptr<SquishXmlOutputHandler> m_xmlOutputHandler;
|
std::unique_ptr<SquishXmlOutputHandler> m_xmlOutputHandler;
|
||||||
Utils::QtcProcess m_serverProcess;
|
Utils::QtcProcess m_serverProcess;
|
||||||
Utils::QtcProcess m_runnerProcess;
|
Utils::QtcProcess m_runnerProcess;
|
||||||
@@ -106,14 +122,18 @@ private:
|
|||||||
QStringList m_testCases;
|
QStringList m_testCases;
|
||||||
QStringList m_reportFiles;
|
QStringList m_reportFiles;
|
||||||
QString m_currentResultsDirectory;
|
QString m_currentResultsDirectory;
|
||||||
|
Utils::FilePath m_currentTestCasePath;
|
||||||
QFile *m_currentResultsXML = nullptr;
|
QFile *m_currentResultsXML = nullptr;
|
||||||
QFileSystemWatcher *m_resultsFileWatcher = nullptr;
|
QFileSystemWatcher *m_resultsFileWatcher = nullptr;
|
||||||
QStringList m_additionalServerArguments;
|
QStringList m_additionalServerArguments;
|
||||||
QStringList m_additionalRunnerArguments;
|
QStringList m_additionalRunnerArguments;
|
||||||
QList<QStringList> m_serverConfigChanges;
|
QList<QStringList> m_serverConfigChanges;
|
||||||
QWindowList m_lastTopLevelWindows;
|
QWindowList m_lastTopLevelWindows;
|
||||||
|
class SquishLocationMark *m_locationMarker = nullptr;
|
||||||
|
QTimer *m_requestVarsTimer = nullptr;
|
||||||
enum RunnerMode { NoMode, TestingMode, QueryMode} m_squishRunnerMode = NoMode;
|
enum RunnerMode { NoMode, TestingMode, QueryMode} m_squishRunnerMode = NoMode;
|
||||||
qint64 m_readResultsCount;
|
qint64 m_readResultsCount;
|
||||||
|
bool m_shutdownInitiated = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -232,6 +232,7 @@ void SquishXmlOutputHandler::outputAvailable(const QByteArray &output)
|
|||||||
result.setLine(line);
|
result.setLine(line);
|
||||||
testCaseRootItem = new SquishResultItem(result);
|
testCaseRootItem = new SquishResultItem(result);
|
||||||
emit resultItemCreated(testCaseRootItem);
|
emit resultItemCreated(testCaseRootItem);
|
||||||
|
emit updateStatus(result.text());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -245,6 +246,7 @@ void SquishXmlOutputHandler::outputAvailable(const QByteArray &output)
|
|||||||
TestResult result(Result::End, QString(), time);
|
TestResult result(Result::End, QString(), time);
|
||||||
SquishResultItem *item = new SquishResultItem(result);
|
SquishResultItem *item = new SquishResultItem(result);
|
||||||
testCaseRootItem->appendChild(item);
|
testCaseRootItem->appendChild(item);
|
||||||
|
emit updateStatus(result.text());
|
||||||
} else if (currentName == "description") {
|
} else if (currentName == "description") {
|
||||||
if (!prepend && !details.trimmed().isEmpty()) {
|
if (!prepend && !details.trimmed().isEmpty()) {
|
||||||
logDetailsList.append(details.trimmed());
|
logDetailsList.append(details.trimmed());
|
||||||
@@ -254,17 +256,36 @@ void SquishXmlOutputHandler::outputAvailable(const QByteArray &output)
|
|||||||
&& currentName != "test"
|
&& currentName != "test"
|
||||||
&& currentName != "result"
|
&& currentName != "result"
|
||||||
&& currentName != "SquishReport") {
|
&& currentName != "SquishReport") {
|
||||||
|
QTC_ASSERT(testCaseRootItem, break);
|
||||||
TestResult result(type, logDetails, time);
|
TestResult result(type, logDetails, time);
|
||||||
if (logDetails.isEmpty() && !logDetailsList.isEmpty())
|
if (logDetails.isEmpty() && !logDetailsList.isEmpty())
|
||||||
result.setText(logDetailsList.takeFirst());
|
result.setText(logDetailsList.takeFirst());
|
||||||
result.setFile(file);
|
result.setFile(file);
|
||||||
result.setLine(line);
|
result.setLine(line);
|
||||||
SquishResultItem *item = new SquishResultItem(result);
|
SquishResultItem *item = new SquishResultItem(result);
|
||||||
|
emit updateStatus(result.text());
|
||||||
|
|
||||||
|
switch (result.type()) {
|
||||||
|
case Result::Pass:
|
||||||
|
case Result::ExpectedFail:
|
||||||
|
emit increasePassCounter();
|
||||||
|
break;
|
||||||
|
case Result::Error:
|
||||||
|
case Result::Fail:
|
||||||
|
case Result::Fatal:
|
||||||
|
case Result::UnexpectedPass:
|
||||||
|
emit increaseFailCounter();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!logDetailsList.isEmpty()) {
|
if (!logDetailsList.isEmpty()) {
|
||||||
for (const QString &detail : qAsConst(logDetailsList)) {
|
for (const QString &detail : qAsConst(logDetailsList)) {
|
||||||
TestResult childResult(Result::Detail, detail);
|
TestResult childResult(Result::Detail, detail);
|
||||||
SquishResultItem *childItem = new SquishResultItem(childResult);
|
SquishResultItem *childItem = new SquishResultItem(childResult);
|
||||||
item->appendChild(childItem);
|
item->appendChild(childItem);
|
||||||
|
emit updateStatus(childResult.text());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testCaseRootItem->appendChild(item);
|
testCaseRootItem->appendChild(item);
|
||||||
|
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "testresult.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
@@ -27,6 +25,9 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void resultItemCreated(SquishResultItem *resultItem);
|
void resultItemCreated(SquishResultItem *resultItem);
|
||||||
|
void updateStatus(const QString &text);
|
||||||
|
void increasePassCounter();
|
||||||
|
void increaseFailCounter();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void outputAvailable(const QByteArray &output);
|
void outputAvailable(const QByteArray &output);
|
||||||
|
Reference in New Issue
Block a user