AutoTest: Add possibility to trigger test run from source

Change-Id: Iceed69747de64d76f34451d41f719c8dbdd81e44
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Pawel Rutka
2018-02-16 17:57:37 +01:00
committed by pawelrutka
parent 190c5083b7
commit c8f1da095d
10 changed files with 132 additions and 18 deletions

View File

@@ -11,6 +11,7 @@ QtcPlugin {
Depends { name: "QmlJSTools" } Depends { name: "QmlJSTools" }
Depends { name: "Utils" } Depends { name: "Utils" }
Depends { name: "Debugger" } Depends { name: "Debugger" }
Depends { name: "TextEditor" }
pluginTestDepends: [ pluginTestDepends: [
"QbsProjectManager", "QbsProjectManager",

View File

@@ -5,7 +5,8 @@ QTC_PLUGIN_DEPENDS += \
projectexplorer \ projectexplorer \
cpptools \ cpptools \
qmljstools \ qmljstools \
debugger debugger \
texteditor
QTC_LIB_DEPENDS += \ QTC_LIB_DEPENDS += \
cplusplus \ cplusplus \

View File

@@ -33,6 +33,8 @@ namespace Constants {
const char ACTION_SCAN_ID[] = "AutoTest.ScanAction"; const char ACTION_SCAN_ID[] = "AutoTest.ScanAction";
const char ACTION_RUN_ALL_ID[] = "AutoTest.RunAll"; const char ACTION_RUN_ALL_ID[] = "AutoTest.RunAll";
const char ACTION_RUN_SELECTED_ID[] = "AutoTest.RunSelected"; const char ACTION_RUN_SELECTED_ID[] = "AutoTest.RunSelected";
const char ACTION_RUN_UCURSOR[] = "AutoTest.RunUnderCursor";
const char ACTION_RUN_DBG_UCURSOR[] = "AutoTest.RunDebugUnderCursor";
const char MENU_ID[] = "AutoTest.Menu"; const char MENU_ID[] = "AutoTest.Menu";
const char AUTOTEST_ID[] = "AutoTest.ATP"; const char AUTOTEST_ID[] = "AutoTest.ATP";
const char AUTOTEST_CONTEXT[] = "Auto Tests"; const char AUTOTEST_CONTEXT[] = "Auto Tests";
@@ -41,7 +43,6 @@ const char TASK_PARSE[] = "AutoTest.Task.Parse";
const char AUTOTEST_SETTINGS_CATEGORY[] = "ZY.Tests"; const char AUTOTEST_SETTINGS_CATEGORY[] = "ZY.Tests";
const char AUTOTEST_SETTINGS_TR[] = QT_TRANSLATE_NOOP("AutoTest", "Testing"); const char AUTOTEST_SETTINGS_TR[] = QT_TRANSLATE_NOOP("AutoTest", "Testing");
const char FRAMEWORK_PREFIX[] = "AutoTest.Framework."; const char FRAMEWORK_PREFIX[] = "AutoTest.Framework.";
const char SETTINGSPAGE_PREFIX[] = "A.AutoTest."; const char SETTINGSPAGE_PREFIX[] = "A.AutoTest.";
const char SETTINGSGROUP[] = "Autotest"; const char SETTINGSGROUP[] = "Autotest";
} // namespace Constants } // namespace Constants

View File

@@ -47,16 +47,22 @@
#include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h> #include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/messagemanager.h>
#include <cppeditor/cppeditorconstants.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h> #include <projectexplorer/buildmanager.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorericons.h>
#include <texteditor/texteditor.h>
#include <utils/textutils.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QAction> #include <QAction>
#include <QList>
#include <QMessageBox> #include <QMessageBox>
#include <QMainWindow> #include <QMainWindow>
#include <QMenu> #include <QMenu>
#include <QTextCursor>
#include <QtPlugin> #include <QtPlugin>
#ifdef WITH_TESTS #ifdef WITH_TESTS
@@ -164,6 +170,29 @@ bool AutotestPlugin::initialize(const QStringList &arguments, QString *errorStri
void AutotestPlugin::extensionsInitialized() void AutotestPlugin::extensionsInitialized()
{ {
ActionContainer *contextMenu = ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT);
QTC_ASSERT(contextMenu, return);
QAction *action = new QAction(tr("&Run Test Under Cursor"), this);
action->setEnabled(false);
action->setIcon(Utils::Icons::RUN_SMALL_TOOLBAR.icon());
Command *command = ActionManager::registerAction(action, Constants::ACTION_RUN_UCURSOR);
connect(action, &QAction::triggered, std::bind(&AutotestPlugin::onRunUnderCursorTriggered, this,
TestRunMode::Run));
contextMenu->addSeparator();
contextMenu->addAction(command);
action = new QAction(tr("&Debug Test Under Cursor"), this);;
action->setEnabled(false);
action->setIcon(ProjectExplorer::Icons::DEBUG_START_SMALL.icon());
command = ActionManager::registerAction(action, Constants::ACTION_RUN_DBG_UCURSOR);
connect(action, &QAction::triggered, std::bind(&AutotestPlugin::onRunUnderCursorTriggered, this,
TestRunMode::Debug));
contextMenu->addAction(command);
contextMenu->addSeparator();
} }
ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown() ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown()
@@ -188,6 +217,35 @@ void AutotestPlugin::onRunSelectedTriggered()
runner->prepareToRunTests(TestRunMode::Run); runner->prepareToRunTests(TestRunMode::Run);
} }
void AutotestPlugin::onRunUnderCursorTriggered(TestRunMode mode)
{
QTextCursor cursor = Utils::Text::wordStartCursor(
TextEditor::BaseTextEditor::currentTextEditor()->editorWidget()->textCursor());
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
const QString text = cursor.selectedText();
if (text.isEmpty())
return; // Do not trigger when no name under cursor
const QList<TestTreeItem *> testsItems = TestTreeModel::instance()->testItemsByName(text);
if (testsItems.isEmpty())
return; // Wrong location triggered
QList<TestConfiguration *> testsToRun;
for (const TestTreeItem * item : testsItems){
if (TestConfiguration *cfg = item->asConfiguration(mode))
testsToRun << cfg;
}
if (testsToRun.isEmpty()) {
MessageManager::write(tr("Selected test was not found (%1).").arg(text), MessageManager::Flash);
return;
}
auto runner = TestRunner::instance();
runner->setSelectedTests(testsToRun);
runner->prepareToRunTests(mode);
}
void AutotestPlugin::updateMenuItemsEnabledState() void AutotestPlugin::updateMenuItemsEnabledState()
{ {
const bool canScan = !TestRunner::instance()->isTestRunning() const bool canScan = !TestRunner::instance()->isTestRunning()
@@ -200,6 +258,13 @@ void AutotestPlugin::updateMenuItemsEnabledState()
ActionManager::command(Constants::ACTION_RUN_ALL_ID)->action()->setEnabled(canRun); ActionManager::command(Constants::ACTION_RUN_ALL_ID)->action()->setEnabled(canRun);
ActionManager::command(Constants::ACTION_RUN_SELECTED_ID)->action()->setEnabled(canRun); ActionManager::command(Constants::ACTION_RUN_SELECTED_ID)->action()->setEnabled(canRun);
ActionManager::command(Constants::ACTION_SCAN_ID)->action()->setEnabled(canScan); ActionManager::command(Constants::ACTION_SCAN_ID)->action()->setEnabled(canScan);
ActionContainer *contextMenu = ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT);
if (!contextMenu)
return; // When no context menu, actions do not exists
ActionManager::command(Constants::ACTION_RUN_UCURSOR)->action()->setEnabled(canRun);
ActionManager::command(Constants::ACTION_RUN_DBG_UCURSOR)->action()->setEnabled(canRun);
} }
QList<QObject *> AutotestPlugin::createTestObjects() const QList<QObject *> AutotestPlugin::createTestObjects() const

View File

@@ -37,6 +37,7 @@ class TestNavigationWidgetFactory;
class TestResultsPane; class TestResultsPane;
struct TestSettings; struct TestSettings;
class TestSettingsPage; class TestSettingsPage;
enum class TestRunMode;
class AutotestPlugin : public ExtensionSystem::IPlugin class AutotestPlugin : public ExtensionSystem::IPlugin
{ {
@@ -59,6 +60,7 @@ private:
void initializeMenuEntries(); void initializeMenuEntries();
void onRunAllTriggered(); void onRunAllTriggered();
void onRunSelectedTriggered(); void onRunSelectedTriggered();
void onRunUnderCursorTriggered(TestRunMode mode);
QList<QObject *> createTestObjects() const override; QList<QObject *> createTestObjects() const override;
const QSharedPointer<TestSettings> m_settings; const QSharedPointer<TestSettings> m_settings;
TestFrameworkManager *m_frameworkManager = nullptr; TestFrameworkManager *m_frameworkManager = nullptr;

View File

@@ -110,19 +110,7 @@ void TestRunner::setSelectedTests(const QList<TestConfiguration *> &selected)
void TestRunner::runTest(TestRunMode mode, const TestTreeItem *item) void TestRunner::runTest(TestRunMode mode, const TestTreeItem *item)
{ {
TestConfiguration *configuration; TestConfiguration *configuration = item->asConfiguration(mode);
switch (mode) {
case TestRunMode::Run:
case TestRunMode::RunWithoutDeploy:
configuration = item->testConfiguration();
break;
case TestRunMode::Debug:
case TestRunMode::DebugWithoutDeploy:
configuration = item->debugConfiguration();
break;
default:
configuration = nullptr;
}
if (configuration) { if (configuration) {
setSelectedTests({configuration}); setSelectedTests({configuration});

View File

@@ -236,6 +236,20 @@ TestTreeItem *TestTreeItem::findChildByNameAndFile(const QString &name, const QS
}); });
} }
TestConfiguration *TestTreeItem::asConfiguration(TestRunMode mode) const
{
switch (mode) {
case TestRunMode::Run:
case TestRunMode::RunWithoutDeploy:
return testConfiguration();
case TestRunMode::Debug:
case TestRunMode::DebugWithoutDeploy:
return debugConfiguration();
default:
return nullptr;
}
}
QList<TestConfiguration *> TestTreeItem::getAllTestConfigurations() const QList<TestConfiguration *> TestTreeItem::getAllTestConfigurations() const
{ {
return QList<TestConfiguration *>(); return QList<TestConfiguration *>();

View File

@@ -48,10 +48,11 @@ namespace Internal {
class TestParseResult; class TestParseResult;
class TestConfiguration; class TestConfiguration;
enum class TestRunMode;
class TestTreeItem : public Utils::TreeItem class TestTreeItem : public Utils::TreeItem
{ {
public: public:
enum Type enum Type
{ {
Root, Root,
@@ -108,6 +109,7 @@ public:
virtual bool canProvideDebugConfiguration() const { return false; } virtual bool canProvideDebugConfiguration() const { return false; }
virtual TestConfiguration *testConfiguration() const { return 0; } virtual TestConfiguration *testConfiguration() const { return 0; }
virtual TestConfiguration *debugConfiguration() const { return 0; } virtual TestConfiguration *debugConfiguration() const { return 0; }
TestConfiguration *asConfiguration(TestRunMode mode) const;
virtual QList<TestConfiguration *> getAllTestConfigurations() const; virtual QList<TestConfiguration *> getAllTestConfigurations() const;
virtual QList<TestConfiguration *> getSelectedTestConfigurations() const; virtual QList<TestConfiguration *> getSelectedTestConfigurations() const;
virtual bool lessThan(const TestTreeItem *other, SortMode mode) const; virtual bool lessThan(const TestTreeItem *other, SortMode mode) const;

View File

@@ -158,6 +158,45 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const
return result; return result;
} }
QList<TestTreeItem *> TestTreeModel::testItemsByName(TestTreeItem *root, const QString &testName)
{
QList<TestTreeItem *> result;
for (int row = 0, count = root->childCount(); row < count; ++row){
TestTreeItem *node = root->childItem(row);
if (node->type() == TestTreeItem::TestCase) {
if (node->name() == testName) {
result << node;
continue; // prioritize Tests over TestCases
}
TestTreeItem *testCase = node->findChildBy([testName](const TestTreeItem *it) {
QTC_ASSERT(it, return false);
return it->type() == TestTreeItem::TestFunctionOrSet && it->name() == testName;
}); // collect only actual tests, not special functions like init, cleanup etc,
if (!testCase)
continue;
result << testCase;
} else {
result << testItemsByName(node, testName);
}
}
return result;
}
QList<TestTreeItem *> TestTreeModel::testItemsByName(const QString &testName)
{
QList<TestTreeItem *> result;
for (Utils::TreeItem *frameworkRoot : *rootItem())
result << testItemsByName(static_cast<TestTreeItem *>(frameworkRoot), testName);
return result;
}
void TestTreeModel::syncTestFrameworks() void TestTreeModel::syncTestFrameworks()
{ {
// remove all currently registered // remove all currently registered

View File

@@ -54,7 +54,7 @@ public:
bool hasTests() const; bool hasTests() const;
QList<TestConfiguration *> getAllTestCases() const; QList<TestConfiguration *> getAllTestCases() const;
QList<TestConfiguration *> getSelectedTests() const; QList<TestConfiguration *> getSelectedTests() const;
QList<TestTreeItem *> testItemsByName(const QString &testName);
void syncTestFrameworks(); void syncTestFrameworks();
void rebuild(const QList<Core::Id> &frameworkIds); void rebuild(const QList<Core::Id> &frameworkIds);
@@ -91,6 +91,7 @@ private:
void revalidateCheckState(TestTreeItem *item); void revalidateCheckState(TestTreeItem *item);
explicit TestTreeModel(QObject *parent = 0); explicit TestTreeModel(QObject *parent = 0);
void setupParsingConnections(); void setupParsingConnections();
QList<TestTreeItem *> testItemsByName(TestTreeItem *root, const QString &testName);
TestCodeParser *m_parser; TestCodeParser *m_parser;
}; };