forked from qt-creator/qt-creator
		
	AutoTest: Persist check state to project settings
Make it easier to switch between projects and restore the former check states of the found test items if we have these information. Change-Id: I99a5357388c36aa8cce6f5f82184d6ab2a8bf6e8 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
		@@ -40,6 +40,7 @@ add_qtc_plugin(AutoTest
 | 
			
		||||
    gtest/gtesttreeitem.cpp gtest/gtesttreeitem.h
 | 
			
		||||
    gtest/gtestvisitors.cpp gtest/gtestvisitors.h
 | 
			
		||||
    iframeworksettings.h
 | 
			
		||||
    itemdatacache.h
 | 
			
		||||
    itestframework.cpp itestframework.h
 | 
			
		||||
    itestparser.cpp itestparser.h
 | 
			
		||||
    projectsettingswidget.cpp projectsettingswidget.h
 | 
			
		||||
 
 | 
			
		||||
@@ -79,6 +79,7 @@ HEADERS += \
 | 
			
		||||
    autotesticons.h \
 | 
			
		||||
    autotestplugin.h \
 | 
			
		||||
    iframeworksettings.h \
 | 
			
		||||
    itemdatacache.h \
 | 
			
		||||
    itestframework.h \
 | 
			
		||||
    itestparser.h \
 | 
			
		||||
    projectsettingswidget.h \
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ QtcPlugin {
 | 
			
		||||
        "autotestconstants.h",
 | 
			
		||||
        "autotestplugin.cpp",
 | 
			
		||||
        "autotestplugin.h",
 | 
			
		||||
        "itemdatacache.h",
 | 
			
		||||
        "projectsettingswidget.cpp",
 | 
			
		||||
        "projectsettingswidget.h",
 | 
			
		||||
        "testcodeparser.cpp",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										87
									
								
								src/plugins/autotest/itemdatacache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/plugins/autotest/itemdatacache.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
/****************************************************************************
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2020 The Qt Company Ltd.
 | 
			
		||||
** Contact: https://www.qt.io/licensing/
 | 
			
		||||
**
 | 
			
		||||
** This file is part of Qt Creator.
 | 
			
		||||
**
 | 
			
		||||
** Commercial License Usage
 | 
			
		||||
** Licensees holding valid commercial Qt licenses may use this file in
 | 
			
		||||
** accordance with the commercial license agreement provided with the
 | 
			
		||||
** Software or, alternatively, in accordance with the terms contained in
 | 
			
		||||
** a written agreement between you and The Qt Company. For licensing terms
 | 
			
		||||
** and conditions see https://www.qt.io/terms-conditions. For further
 | 
			
		||||
** information use the contact form at https://www.qt.io/contact-us.
 | 
			
		||||
**
 | 
			
		||||
** GNU General Public License Usage
 | 
			
		||||
** Alternatively, this file may be used under the terms of the GNU
 | 
			
		||||
** General Public License version 3 as published by the Free Software
 | 
			
		||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
 | 
			
		||||
** included in the packaging of this file. Please review the following
 | 
			
		||||
** information to ensure the GNU General Public License requirements will
 | 
			
		||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
 | 
			
		||||
**
 | 
			
		||||
****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "testtreeitem.h"
 | 
			
		||||
 | 
			
		||||
#include <utils/optional.h>
 | 
			
		||||
 | 
			
		||||
#include <QVariantHash>
 | 
			
		||||
 | 
			
		||||
namespace Autotest {
 | 
			
		||||
namespace Internal {
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
class ItemDataCache
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    void insert(TestTreeItem *item, const T &value) { m_cache[item->cacheName()] = {0, value}; }
 | 
			
		||||
    void evolve()
 | 
			
		||||
    {
 | 
			
		||||
        auto it = m_cache.begin(), end = m_cache.end();
 | 
			
		||||
        while (it != end)
 | 
			
		||||
            it = it->generation++ >= maxGen ? m_cache.erase(it) : ++it;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Utils::optional<T> get(TestTreeItem *item)
 | 
			
		||||
    {
 | 
			
		||||
        auto entry = m_cache.find(item->cacheName());
 | 
			
		||||
        if (entry == m_cache.end())
 | 
			
		||||
            return Utils::nullopt;
 | 
			
		||||
        entry->generation = 0;
 | 
			
		||||
        return Utils::make_optional(entry->value);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void clear() { m_cache.clear(); }
 | 
			
		||||
    bool isEmpty() const { return m_cache.isEmpty(); }
 | 
			
		||||
 | 
			
		||||
    QVariantHash toSettings() const
 | 
			
		||||
    {
 | 
			
		||||
        QVariantHash result;
 | 
			
		||||
        for (auto it = m_cache.cbegin(), end = m_cache.cend(); it != end; ++it)
 | 
			
		||||
            result.insert(it.key(), QVariant::fromValue(it.value().value));
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fromSettings(const QVariantHash &stored)
 | 
			
		||||
    {
 | 
			
		||||
        m_cache.clear();
 | 
			
		||||
        for (auto it = stored.cbegin(), end = stored.cend(); it != end; ++it)
 | 
			
		||||
            m_cache[it.key()] = {0, qvariant_cast<T>(it.value())};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr int maxGen = 10;
 | 
			
		||||
    struct Entry
 | 
			
		||||
    {
 | 
			
		||||
        int generation = 0;
 | 
			
		||||
        T value;
 | 
			
		||||
    };
 | 
			
		||||
    QHash<QString, Entry> m_cache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
} // namespace Autotest
 | 
			
		||||
@@ -25,10 +25,9 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "itemdatacache.h"
 | 
			
		||||
#include "testrunner.h"
 | 
			
		||||
 | 
			
		||||
#include "testtreemodel.h"
 | 
			
		||||
 | 
			
		||||
#include <coreplugin/inavigationwidgetfactory.h>
 | 
			
		||||
 | 
			
		||||
#include <utils/navigationtreeview.h>
 | 
			
		||||
@@ -49,8 +48,12 @@ class ProgressIndicator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Autotest {
 | 
			
		||||
 | 
			
		||||
class TestTreeModel;
 | 
			
		||||
 | 
			
		||||
namespace Internal {
 | 
			
		||||
 | 
			
		||||
class TestTreeSortFilterModel;
 | 
			
		||||
class TestTreeView;
 | 
			
		||||
 | 
			
		||||
class TestNavigationWidget : public QWidget
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ namespace Internal {
 | 
			
		||||
 | 
			
		||||
static const char SK_ACTIVE_FRAMEWORKS[]        = "AutoTest.ActiveFrameworks";
 | 
			
		||||
static const char SK_RUN_AFTER_BUILD[]          = "AutoTest.RunAfterBuild";
 | 
			
		||||
static const char SK_CHECK_STATES[]             = "AutoTest.CheckStates";
 | 
			
		||||
 | 
			
		||||
static Q_LOGGING_CATEGORY(LOG, "qtc.autotest.frameworkmanager", QtWarningMsg)
 | 
			
		||||
 | 
			
		||||
@@ -93,6 +94,7 @@ void TestProjectSettings::load()
 | 
			
		||||
    const QVariant runAfterBuild = m_project->namedSettings(SK_RUN_AFTER_BUILD);
 | 
			
		||||
    m_runAfterBuild = runAfterBuild.isValid() ? RunAfterBuildMode(runAfterBuild.toInt())
 | 
			
		||||
                                              : RunAfterBuildMode::None;
 | 
			
		||||
    m_checkStateCache.fromSettings(m_project->namedSettings(SK_CHECK_STATES).toHash());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestProjectSettings::save()
 | 
			
		||||
@@ -104,6 +106,8 @@ void TestProjectSettings::save()
 | 
			
		||||
        activeFrameworks.insert(it.key()->id().toString(), it.value());
 | 
			
		||||
    m_project->setNamedSettings(SK_ACTIVE_FRAMEWORKS, activeFrameworks);
 | 
			
		||||
    m_project->setNamedSettings(SK_RUN_AFTER_BUILD, int(m_runAfterBuild));
 | 
			
		||||
    if (!m_checkStateCache.isEmpty())
 | 
			
		||||
        m_project->setNamedSettings(SK_CHECK_STATES, m_checkStateCache.toSettings());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "testsettings.h"
 | 
			
		||||
#include "testtreemodel.h"
 | 
			
		||||
 | 
			
		||||
#include <projectexplorer/project.h>
 | 
			
		||||
 | 
			
		||||
@@ -50,6 +51,7 @@ public:
 | 
			
		||||
    { m_activeTestFrameworks = enabledFrameworks; }
 | 
			
		||||
    QMap<ITestFramework *, bool> activeFrameworks() const { return m_activeTestFrameworks; }
 | 
			
		||||
    void activateFramework(const Utils::Id &id, bool activate);
 | 
			
		||||
    Internal::ItemDataCache<Qt::CheckState> *checkStateCache() { return &m_checkStateCache; }
 | 
			
		||||
private:
 | 
			
		||||
    void load();
 | 
			
		||||
    void save();
 | 
			
		||||
@@ -58,6 +60,7 @@ private:
 | 
			
		||||
    bool m_useGlobalSettings = true;
 | 
			
		||||
    RunAfterBuildMode m_runAfterBuild = RunAfterBuildMode::None;
 | 
			
		||||
    QMap<ITestFramework *, bool> m_activeTestFrameworks;
 | 
			
		||||
    Internal::ItemDataCache<Qt::CheckState> m_checkStateCache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,8 @@ void TestTreeModel::setupParsingConnections()
 | 
			
		||||
    connect(sm, &SessionManager::startupProjectChanged, [this](Project *project) {
 | 
			
		||||
        synchronizeTestFrameworks(); // we might have project settings
 | 
			
		||||
        m_parser->onStartupProjectChanged(project);
 | 
			
		||||
        m_checkStateCache.clear(); // TODO persist to project settings?
 | 
			
		||||
        m_checkStateCache = project ? AutotestPlugin::projectSettings(project)->checkStateCache()
 | 
			
		||||
                                    : nullptr;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance();
 | 
			
		||||
@@ -294,12 +295,12 @@ void TestTreeModel::rebuild(const QList<Utils::Id> &frameworkIds)
 | 
			
		||||
 | 
			
		||||
void TestTreeModel::updateCheckStateCache()
 | 
			
		||||
{
 | 
			
		||||
    m_checkStateCache.evolve();
 | 
			
		||||
    m_checkStateCache->evolve();
 | 
			
		||||
 | 
			
		||||
    for (Utils::TreeItem *rootNode : *rootItem()) {
 | 
			
		||||
        rootNode->forAllChildren([this](Utils::TreeItem *child) {
 | 
			
		||||
            auto childItem = static_cast<TestTreeItem *>(child);
 | 
			
		||||
            m_checkStateCache.insert(childItem, childItem->checked());
 | 
			
		||||
            m_checkStateCache->insert(childItem, childItem->checked());
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -425,7 +426,7 @@ void TestTreeModel::insertItemInParent(TestTreeItem *item, TestTreeItem *root, b
 | 
			
		||||
        delete item;
 | 
			
		||||
    } else {
 | 
			
		||||
        // restore former check state if available
 | 
			
		||||
        Utils::optional<Qt::CheckState> cached = m_checkStateCache.get(item);
 | 
			
		||||
        Utils::optional<Qt::CheckState> cached = m_checkStateCache->get(item);
 | 
			
		||||
        if (cached.has_value())
 | 
			
		||||
            item->setData(0, cached.value(), Qt::CheckStateRole);
 | 
			
		||||
        else
 | 
			
		||||
@@ -515,7 +516,7 @@ void TestTreeModel::handleParseResult(const TestParseResult *result, TestTreeIte
 | 
			
		||||
    // restore former check state if available
 | 
			
		||||
    newItem->forAllChildren([this](Utils::TreeItem *child) {
 | 
			
		||||
        auto childItem = static_cast<TestTreeItem *>(child);
 | 
			
		||||
        Utils::optional<Qt::CheckState> cached = m_checkStateCache.get(childItem);
 | 
			
		||||
        Utils::optional<Qt::CheckState> cached = m_checkStateCache->get(childItem);
 | 
			
		||||
        if (cached.has_value())
 | 
			
		||||
            childItem->setData(0, cached.value(), Qt::CheckStateRole);
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@
 | 
			
		||||
 | 
			
		||||
#include "autotest_global.h"
 | 
			
		||||
 | 
			
		||||
#include "itemdatacache.h"
 | 
			
		||||
#include "testconfiguration.h"
 | 
			
		||||
#include "testtreeitem.h"
 | 
			
		||||
 | 
			
		||||
@@ -39,40 +40,6 @@ namespace Autotest {
 | 
			
		||||
namespace Internal {
 | 
			
		||||
class AutotestPluginPrivate;
 | 
			
		||||
class TestCodeParser;
 | 
			
		||||
 | 
			
		||||
template<class T>
 | 
			
		||||
class ItemDataCache
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    void insert(TestTreeItem *item, const T &value) { m_cache[item->cacheName()] = {0, value}; }
 | 
			
		||||
    void evolve()
 | 
			
		||||
    {
 | 
			
		||||
        auto it = m_cache.begin(), end = m_cache.end();
 | 
			
		||||
        while (it != end)
 | 
			
		||||
            it = it->generation++ >= maxGen ? m_cache.erase(it) : ++it;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Utils::optional<T> get(TestTreeItem *item)
 | 
			
		||||
    {
 | 
			
		||||
        auto entry = m_cache.find(item->cacheName());
 | 
			
		||||
        if (entry == m_cache.end())
 | 
			
		||||
            return Utils::nullopt;
 | 
			
		||||
        entry->generation = 0;
 | 
			
		||||
        return Utils::make_optional(entry->value);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void clear() { m_cache.clear(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr int maxGen = 10;
 | 
			
		||||
    struct Entry
 | 
			
		||||
    {
 | 
			
		||||
        int generation = 0;
 | 
			
		||||
        T value;
 | 
			
		||||
    };
 | 
			
		||||
    QHash<QString, Entry> m_cache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Internal
 | 
			
		||||
 | 
			
		||||
class TestParseResult;
 | 
			
		||||
@@ -139,7 +106,7 @@ private:
 | 
			
		||||
    QList<TestTreeItem *> testItemsByName(TestTreeItem *root, const QString &testName);
 | 
			
		||||
 | 
			
		||||
    Internal::TestCodeParser *m_parser = nullptr;
 | 
			
		||||
    Internal::ItemDataCache<Qt::CheckState> m_checkStateCache;
 | 
			
		||||
    Internal::ItemDataCache<Qt::CheckState> *m_checkStateCache = nullptr; // not owned
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace Internal {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user