Provide 'Run This Test' context menu entry

This menu entry will be added only if current selected test (function)
is not an unnamed Quick Test. Otherwise it's now possible to execute
a particular test case or just a single test function by using the
context menu. This avoids the need of (de)selecting inside the model.

Change-Id: I857a3ffe72c72a9dbb06e948045cfe2c7843935d
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
Christian Stenger
2015-04-16 14:04:36 +02:00
parent 8260b79458
commit e9b2840327
4 changed files with 99 additions and 1 deletions

View File

@@ -89,7 +89,27 @@ void TestNavigationWidget::contextMenuEvent(QContextMenuEvent *event)
const bool enabled = !TestRunner::instance()->isTestRunning()
&& m_model->parser()->state() == TestCodeParser::Idle;
const bool hasTests = m_model->hasTests();
QMenu menu;
QAction *runThisTest = 0;
const QModelIndexList list = m_view->selectionModel()->selectedIndexes();
if (list.size() == 1) {
const QModelIndex index = list.first();
QRect rect(m_view->visualRect(index));
if (rect.contains(event->pos())) {
// do not provide this menu entry for unnamed Quick Tests as it makes no sense
int type = index.data(TypeRole).toInt();
const QString &unnamed = tr(Constants::UNNAMED_QUICKTESTS);
if ((type == TestTreeItem::TEST_FUNCTION && index.parent().data().toString() != unnamed)
|| (type == TestTreeItem::TEST_CLASS && index.data().toString() != unnamed)) {
runThisTest = new QAction(tr("Run This Test"), &menu);
runThisTest->setEnabled(enabled);
connect(runThisTest, &QAction::triggered,
this, &TestNavigationWidget::onRunThisTestTriggered);
}
}
}
QAction *runAll = Core::ActionManager::command(Constants::ACTION_RUN_ALL_ID)->action();
QAction *runSelected = Core::ActionManager::command(Constants::ACTION_RUN_SELECTED_ID)->action();
QAction *selectAll = new QAction(tr("Select All"), &menu);
@@ -106,6 +126,10 @@ void TestNavigationWidget::contextMenuEvent(QContextMenuEvent *event)
deselectAll->setEnabled(enabled && hasTests);
rescan->setEnabled(enabled);
if (runThisTest) {
menu.addAction(runThisTest);
menu.addSeparator();
}
menu.addAction(runAll);
menu.addAction(runSelected);
menu.addSeparator();
@@ -210,6 +234,26 @@ void TestNavigationWidget::initializeFilterMenu()
m_filterMenu->addAction(action);
}
void TestNavigationWidget::onRunThisTestTriggered()
{
const QModelIndexList selected = m_view->selectionModel()->selectedIndexes();
// paranoia
if (selected.isEmpty())
return;
const QModelIndex sourceIndex = m_sortFilterModel->mapToSource(selected.first());
if (!sourceIndex.isValid())
return;
TestTreeItem *item = static_cast<TestTreeItem *>(sourceIndex.internalPointer());
if (item->type() == TestTreeItem::TEST_CLASS || item->type() == TestTreeItem::TEST_FUNCTION) {
if (TestConfiguration *configuration = m_model->getTestConfiguration(item)) {
TestRunner *runner = TestRunner::instance();
runner->setSelectedTests( {configuration} );
runner->runTests();
}
}
}
TestNavigationWidgetFactory::TestNavigationWidgetFactory()
{
setDisplayName(tr("Tests"));

View File

@@ -69,6 +69,7 @@ private slots:
private:
void initializeFilterMenu();
void onRunThisTestTriggered();
TestTreeModel *m_model;
TestTreeSortFilterModel *m_sortFilterModel;

View File

@@ -255,6 +255,8 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const
default:
return false;
}
case TypeRole:
return item->type();
}
// TODO ?
@@ -506,6 +508,55 @@ QList<TestConfiguration *> TestTreeModel::getSelectedTests() const
return result;
}
TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) const
{
QTC_ASSERT(item != 0, return 0);
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
QTC_ASSERT(project, return 0);
TestConfiguration *config = 0;
switch (item->type()) {
case TestTreeItem::TEST_CLASS: {
if (item->parent() == m_quickTestRootItem) {
// Quick Test TestCase
QStringList testFunctions;
for (int row = 0, count = item->childCount(); row < count; ++row) {
testFunctions << item->name() + QLatin1String("::") + item->child(row)->name();
}
config = new TestConfiguration(QString(), testFunctions);
config->setMainFilePath(item->mainFile());
config->setProject(project);
} else {
// normal auto test
config = new TestConfiguration(item->name(), QStringList(), item->childCount());
config->setMainFilePath(item->filePath());
config->setProject(project);
}
break;
}
case TestTreeItem::TEST_FUNCTION: {
const TestTreeItem *parent = item->parent();
if (parent->parent() == m_quickTestRootItem) {
// it's a Quick Test function of a named TestCase
QStringList testFunction(parent->name() + QLatin1String("::") + item->name());
config = new TestConfiguration(QString(), testFunction);
config->setMainFilePath(parent->mainFile());
config->setProject(project);
} else {
// normal auto test
config = new TestConfiguration(parent->name(), QStringList() << item->name());
config->setMainFilePath(parent->filePath());
config->setProject(project);
}
break;
}
// not supported items
default:
return 0;
}
return config;
}
QString TestTreeModel::getMainFileForUnnamedQuickTest(const QString &qmlFile) const
{
const TestTreeItem *unnamed = unnamedQuickTests();

View File

@@ -31,7 +31,8 @@ namespace {
enum ItemRole {
// AnnotationRole = Qt::UserRole + 1,
LinkRole = Qt::UserRole + 2, // can be removed if AnnotationRole comes back
ItalicRole // used only inside the delegate
ItalicRole, // used only inside the delegate
TypeRole
};
}
@@ -71,6 +72,7 @@ public:
bool hasTests() const;
QList<TestConfiguration *> getAllTestCases() const;
QList<TestConfiguration *> getSelectedTests() const;
TestConfiguration *getTestConfiguration(const TestTreeItem *item) const;
QString getMainFileForUnnamedQuickTest(const QString &qmlFile) const;
void qmlFilesForMainFile(const QString &mainFile, QSet<QString> *filePaths) const;
QList<QString> getUnnamedQuickTestFunctions() const;