QmlDesigner: Add interface to manually trigger project storage update

It is triggering the path watcher to check if the directory was updated
and then update the updater.

Task-number: QDS-15136
Change-Id: I80d654c5e476a47f75c6ebda3fa86dfe69226cb4
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2025-04-03 15:35:20 +02:00
parent 1b38d1d6cc
commit 5c3f3cc592
24 changed files with 239 additions and 66 deletions

View File

@@ -391,6 +391,7 @@ extend_qtc_library(QmlDesignerCore
projectstorageinfotypes.h
projectstorageobserver.h
projectstoragepathwatcher.h
projectstoragetriggerupdateinterface.h
projectstoragepathwatcherinterface.h
projectstoragepathwatchernotifierinterface.h
projectstoragepathwatcher.h

View File

@@ -281,6 +281,7 @@ public:
NotNullPointer<const ProjectStorageType> projectStorage() const;
const PathCacheType &pathCache() const;
PathCacheType &pathCache();
ProjectStorageTriggerUpdateInterface &projectStorageTriggerUpdate() const;
void emitInstancePropertyChange(AbstractView *view,
const QList<QPair<ModelNode, PropertyName>> &propertyList);

View File

@@ -42,6 +42,7 @@ constexpr bool useProjectStorage()
#endif
}
class SourcePathStorage;
class ProjectStorageTriggerUpdateInterface;
using PathCache = SourcePathCache<SourcePathStorage, std::shared_mutex>;
#ifdef QDS_MODEL_USE_PROJECTSTORAGEINTERFACE
@@ -52,11 +53,11 @@ using PathCacheType = SourcePathCacheInterface;
using ProjectStorageType = ProjectStorage;
using PathCacheType = SourcePathCache<SourcePathStorage, std::shared_mutex>;
#endif
struct ProjectStorageDependencies
{
ProjectStorageType &storage;
PathCacheType &cache;
ProjectStorageTriggerUpdateInterface &triggerUpdate;
};
enum class PropertyType {

View File

@@ -85,6 +85,7 @@ ModelPrivate::ModelPrivate(Model *model,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: projectStorage{&projectStorageDependencies.storage}
, pathCache{&projectStorageDependencies.cache}
, projectStorageTriggerUpdate{&projectStorageDependencies.triggerUpdate}
, m_model{model}
, m_resourceManagement{std::move(resourceManagement)}
{
@@ -110,6 +111,7 @@ ModelPrivate::ModelPrivate(Model *model,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: projectStorage{&projectStorageDependencies.storage}
, pathCache{&projectStorageDependencies.cache}
, projectStorageTriggerUpdate{&projectStorageDependencies.triggerUpdate}
, m_model{model}
, m_resourceManagement{std::move(resourceManagement)}
{
@@ -1771,7 +1773,7 @@ Model::Model(const TypeName &typeName,
ModelPointer Model::createModel(const TypeName &typeName,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
{
return Model::create({*d->projectStorage, *d->pathCache},
return Model::create({*d->projectStorage, *d->pathCache, *d->projectStorageTriggerUpdate},
typeName,
imports(),
fileUrl(),
@@ -2018,6 +2020,11 @@ PathCacheType &Model::pathCache()
return *d->pathCache;
}
ProjectStorageTriggerUpdateInterface &Model::projectStorageTriggerUpdate() const
{
return *d->projectStorageTriggerUpdate;
}
void Model::emitInstancePropertyChange(AbstractView *view,
const QList<QPair<ModelNode, PropertyName>> &propertyList)
{

View File

@@ -347,6 +347,7 @@ private:
public:
NotNullPointer<ProjectStorageType> projectStorage = nullptr;
NotNullPointer<PathCacheType> pathCache = nullptr;
NotNullPointer<ProjectStorageTriggerUpdateInterface> projectStorageTriggerUpdate = nullptr;
ModelTracing::AsynchronousToken traceToken = ModelTracing::category().beginAsynchronous("Model");
private:

View File

@@ -8,6 +8,7 @@
#include "projectstoragepathwatcherinterface.h"
#include "projectstoragepathwatchernotifierinterface.h"
#include "projectstoragepathwatchertypes.h"
#include "projectstoragetriggerupdateinterface.h"
#include <sourcepathstorage/storagecache.h>
@@ -34,7 +35,8 @@ void set_greedy_intersection_call(
}
template<typename FileSystemWatcher, typename Timer, class SourcePathCache>
class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface
class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface,
public ProjectStorageTriggerUpdateInterface
{
public:
ProjectStoragePathWatcher(SourcePathCache &pathCache,
@@ -83,6 +85,13 @@ public:
removeUnusedEntries(entires, notContainsId);
}
void checkForChangeInDirectory(SourceContextIds sourceContextIds) override
{
std::ranges::sort(sourceContextIds);
addChangedPathForFilePath(sourceContextIds);
}
void removeIds(const ProjectPartIds &ids) override
{
auto removedEntries = removeIdsFromWatchedEntries(ids);
@@ -279,10 +288,7 @@ public:
return notWatchedPaths(uniquePaths(entries));
}
const WatcherEntries &watchedEntries() const
{
return m_watchedEntries;
}
const WatcherEntries &watchedEntries() const { return m_watchedEntries; }
WatcherEntries removeIdsFromWatchedEntries(const ProjectPartIds &ids)
{

View File

@@ -0,0 +1,23 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "projectstorageids.h"
namespace QmlDesigner {
class ProjectStorageTriggerUpdateInterface
{
public:
ProjectStorageTriggerUpdateInterface() = default;
ProjectStorageTriggerUpdateInterface(const ProjectStorageTriggerUpdateInterface &) = delete;
ProjectStorageTriggerUpdateInterface &operator=(const ProjectStorageTriggerUpdateInterface &) = delete;
virtual void checkForChangeInDirectory(SourceContextIds sourceContextIds) = 0;
protected:
~ProjectStorageTriggerUpdateInterface() = default;
};
} // namespace QmlDesigner

View File

@@ -366,14 +366,21 @@ namespace {
return nullptr;
}
[[maybe_unused]] ProjectStorageTriggerUpdateInterface *dummyTriggerUpdate()
{
return nullptr;
}
} // namespace
ProjectStorageDependencies QmlDesignerProjectManager::projectStorageDependencies()
{
if constexpr (useProjectStorage()) {
return {m_projectData->projectStorageData->storage, m_data->pathCache};
return {m_projectData->projectStorageData->storage,
m_data->pathCache,
m_projectData->projectStorageData->pathWatcher};
} else {
return {*dummyProjectStorage(), *dummyPathCache()};
return {*dummyProjectStorage(), *dummyPathCache(), *dummyTriggerUpdate()};
}
}

View File

@@ -28,6 +28,7 @@ add_qtc_library(TestMocks OBJECT
projectstorageobservermock.h
projectstoragepathwatchermock.h
projectstoragepathwatchernotifiermock.h
projectstoragetriggerupdatemock.h
qmldocumentparsermock.h
qmltypesparsermock.h
sourcepathcachemock.h sourcepathcachemock.cpp

View File

@@ -0,0 +1,19 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "../utils/googletest.h"
#include <projectstorage/projectstoragetriggerupdateinterface.h>
class ProjectStorageTriggerUpdateMock : public QmlDesigner::ProjectStorageTriggerUpdateInterface
{
public:
virtual ~ProjectStorageTriggerUpdateMock() = default;
MOCK_METHOD(void,
checkForChangeInDirectory,
(QmlDesigner::SourceContextIds sourceContextIds),
(override));
};

View File

@@ -342,6 +342,7 @@ extend_qtc_library(TestDesignerCore
projectstorageinfotypes.h
projectstorageobserver.h
projectstoragepathwatcher.h
projectstoragetriggerupdateinterface.h
projectstoragepathwatcherinterface.h
projectstoragepathwatchernotifierinterface.h
projectstoragepathwatcher.h

View File

@@ -5,6 +5,7 @@
#include <mocks/abstractviewmock.h>
#include <mocks/modelresourcemanagementmock.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <strippedstring-matcher.h>
@@ -173,10 +174,11 @@ protected:
protected:
inline static QSharedPointer<const QmlJS::SimpleReaderNode> simpleReaderNode;
NiceMock<AbstractViewMock> viewMock;
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
NiceMock<ModelResourceManagementMock> resourceManagementMock;
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
-1,
-1,

View File

@@ -5,7 +5,9 @@
#include <mocks/abstractviewmock.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <modelutils.h>
#include <nodemetainfo.h>
#include <nodeproperty.h>
@@ -18,11 +20,12 @@ using QmlDesigner::Storage::ModuleKind;
class ModelUtilsWithModel : public ::testing::Test
{
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/model.qml"};
QmlDesigner::SourceId sourceId = pathCacheMock.createSourceId("/path/foo.qml");
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
QmlDesigner::ModuleId moduleId = projectStorageMock.moduleId("QtQuick", ModuleKind::QmlLibrary);
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
{QmlDesigner::Import::createLibraryImport("QML"),
QmlDesigner::Import::createLibraryImport("QtQuick"),

View File

@@ -7,6 +7,7 @@
#include <model.h>
#include <nodeproperty.h>
#include <projectstoragemock.h>
#include <projectstoragetriggerupdatemock.h>
#include <sourcepathcachemock.h>
#include <variantproperty.h>
@@ -103,9 +104,10 @@ protected:
const QmlDesigner::GroupType groupType = GetParam();
const QmlDesigner::PropertyName groupName = GroupId(groupType);
QmlDesigner::DSThemeGroup group;
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/model.qm"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"QtObject",
{Import::createLibraryImport("QM"),
Import::createLibraryImport("QtQuick")},

View File

@@ -5,6 +5,7 @@
#include <mocks/abstractviewmock.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <abstractview.h>
@@ -183,12 +184,14 @@ public:
}
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
NiceMock<MockFunction<ModelNode(const ModelNode &)>> goIntoComponentMock;
QmlDesigner::ModelPointer designerModel{
QmlDesigner::Model::create(QmlDesigner::ProjectStorageDependencies{projectStorageMock,
pathCacheMock},
pathCacheMock,
projectStorageTriggerUpdateMock},
"Item",
{QmlDesigner::Import::createLibraryImport("QtQml.Models"),
QmlDesigner::Import::createLibraryImport("QtQuick")},
@@ -204,7 +207,7 @@ protected:
ModelNode element2;
ModelNode element3;
QmlDesigner::ModelPointer componentModel{
QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
QmlDesigner::Model::create({projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"ListModel",
{QmlDesigner::Import::createLibraryImport("QtQml.Models"),
QmlDesigner::Import::createLibraryImport("QtQuick")},

View File

@@ -6,6 +6,7 @@
#include <matchers/info_exportedtypenames-matcher.h>
#include <matchers/projectstorage-matcher.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <designercore/include/model.h>
@@ -105,9 +106,10 @@ protected:
}
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCache{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCache.sourceId, "/path"};
QmlDesigner::Model model{{projectStorageMock, pathCache},
QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock},
"Item",
{QmlDesigner::Import::createLibraryImport("QML"),
QmlDesigner::Import::createLibraryImport("QtQuick"),

View File

@@ -6,6 +6,7 @@
#include <matchers/info_exportedtypenames-matcher.h>
#include <matchers/qvariant-matcher.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <designercore/include/model.h>
@@ -41,9 +42,10 @@ protected:
}
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCache{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCache.sourceId, "/path"};
QmlDesigner::Model model{{projectStorageMock, pathCache},
QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock},
"Item",
{QmlDesigner::Import::createLibraryImport("QML"),
QmlDesigner::Import::createLibraryImport("QtQuick"),

View File

@@ -6,6 +6,7 @@
#include <mocks/externaldependenciesmock.h>
#include <mocks/modelresourcemanagementmock.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <model/auxiliarypropertystorageview.h>
@@ -40,17 +41,18 @@ protected:
inline static std::unique_ptr<StaticData> staticData;
Sqlite::Database &database = staticData->database;
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
NiceMock<ModelResourceManagementMock> resourceManagementMock;
QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
pathCacheMock.path.toQString(),
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock)};
QmlDesigner::Model model2{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model2{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
pathCacheMock.path.toQString(),

View File

@@ -9,6 +9,7 @@
#include <mocks/modelresourcemanagementmock.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstorageobservermock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <bindingproperty.h>
@@ -119,13 +120,14 @@ protected:
}
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
NiceMock<ModelResourceManagementMock> resourceManagementMock;
QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")};
NiceMock<AbstractViewMock> viewMock;
QUrl fileUrl = QUrl::fromLocalFile(pathCacheMock.path.toQString());
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
QUrl::fromLocalFile(pathCacheMock.path.toQString()),
@@ -147,60 +149,60 @@ class Model_Creation : public Model
TEST_F(Model_Creation, root_node_has_item_type_name)
{
auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto model = QmlDesigner::Model::create(
{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock));
std::make_unique<ModelResourceManagementMockWrapper>(resourceManagementMock));
ASSERT_THAT(model->rootModelNode().type(), Eq("Item"));
}
TEST_F(Model_Creation, root_node_has_item_meta_info)
{
auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto model = QmlDesigner::Model::create(
{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock));
std::make_unique<ModelResourceManagementMockWrapper>(resourceManagementMock));
ASSERT_THAT(model->rootModelNode().metaInfo(), model->qtQuickItemMetaInfo());
}
TEST_F(Model_Creation, file_url)
{
auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto model = QmlDesigner::Model::create(
{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock));
std::make_unique<ModelResourceManagementMockWrapper>(resourceManagementMock));
ASSERT_THAT(model->fileUrl().toLocalFile(), Eq(pathCacheMock.path.toQString()));
}
TEST_F(Model_Creation, file_url_source_id)
{
auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto model = QmlDesigner::Model::create(
{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock));
std::make_unique<ModelResourceManagementMockWrapper>(resourceManagementMock));
ASSERT_THAT(model->fileUrlSourceId(), pathCacheMock.sourceId);
}
TEST_F(Model_Creation, imports)
{
auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto model = QmlDesigner::Model::create(
{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,
std::make_unique<ModelResourceManagementMockWrapper>(
resourceManagementMock));
std::make_unique<ModelResourceManagementMockWrapper>(resourceManagementMock));
ASSERT_THAT(model->imports(), UnorderedElementsAreArray(imports));
}
@@ -645,7 +647,8 @@ TEST_F(Model_ResourceManagment,
TEST_F(Model_ResourceManagment, by_default_remove_model_node_removes_node)
{
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"};
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"QtQuick.Item"};
NiceMock<AbstractViewMock> viewMock;
newModel.attachView(&viewMock);
auto node = createNodeWithParent(viewMock.rootModelNode());
@@ -657,7 +660,8 @@ TEST_F(Model_ResourceManagment, by_default_remove_model_node_removes_node)
TEST_F(Model_ResourceManagment, by_default_remove_properties_removes_property)
{
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"};
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"QtQuick.Item"};
NiceMock<AbstractViewMock> viewMock;
newModel.attachView(&viewMock);
rootNode = viewMock.rootModelNode();
@@ -671,7 +675,9 @@ TEST_F(Model_ResourceManagment, by_default_remove_properties_removes_property)
TEST_F(Model_ResourceManagment, by_default_remove_model_node_in_factory_method_calls_removes_node)
{
model.detachView(&viewMock);
auto newModel = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto newModel = QmlDesigner::Model::create({projectStorageMock,
pathCacheMock,
projectStorageTriggerUpdateMock},
"Item",
imports,
pathCacheMock.path.toQString());
@@ -686,7 +692,9 @@ TEST_F(Model_ResourceManagment, by_default_remove_model_node_in_factory_method_c
TEST_F(Model_ResourceManagment, by_default_remove_properties_in_factory_method_calls_remove_property)
{
model.detachView(&viewMock);
auto newModel = QmlDesigner::Model::create({projectStorageMock, pathCacheMock},
auto newModel = QmlDesigner::Model::create({projectStorageMock,
pathCacheMock,
projectStorageTriggerUpdateMock},
"Item",
imports,
pathCacheMock.path.toQString());
@@ -780,7 +788,8 @@ TEST_F(Model_ResourceManagment, remove_model_nodes_bypasses_model_resource_manag
TEST_F(Model_ResourceManagment, by_default_remove_model_nodes_in_factory_method_calls_removes_node)
{
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"};
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"QtQuick.Item"};
NiceMock<AbstractViewMock> viewMock;
newModel.attachView(&viewMock);
rootNode = viewMock.rootModelNode();
@@ -874,7 +883,8 @@ TEST_F(Model_ResourceManagment, remove_properties_bypasses_model_resource_manage
TEST_F(Model_ResourceManagment, by_default_remove_properties_in_factory_method_calls_removes_properties)
{
model.detachView(&viewMock);
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"};
QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"QtQuick.Item"};
newModel.attachView(&viewMock);
rootNode = viewMock.rootModelNode();
auto property = createProperty(rootNode, "yi");
@@ -1131,14 +1141,24 @@ TEST_F(Model_MetaInfo, add_project_storage_observer_to_project_storage)
{
EXPECT_CALL(projectStorageMock, addObserver(_));
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
-1,
-1,
nullptr,
{}};
}
TEST_F(Model_MetaInfo, remove_project_storage_observer_from_project_storage)
{
EXPECT_CALL(projectStorageMock, removeObserver(_)).Times(2); // the fixture model is calling it too
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
-1,
-1,
nullptr,
{}};
}
TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view)
@@ -1148,7 +1168,12 @@ TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view)
ProjectStorageObserverMock observerMock;
QmlDesigner::ProjectStorageObserver *observer = nullptr;
ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; });
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
-1,
-1,
nullptr,
{}};
model.attachView(&viewMock);
EXPECT_CALL(viewMock, refreshMetaInfos(typeIds));
@@ -1163,7 +1188,12 @@ TEST_F(Model_MetaInfo, added_exported_type_names_are_changed_callback_is_calling
ProjectStorageObserverMock observerMock;
QmlDesigner::ProjectStorageObserver *observer = nullptr;
ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; });
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
-1,
-1,
nullptr,
{}};
model.attachView(&viewMock);
EXPECT_CALL(viewMock, exportedTypeNamesChanged(added, IsEmpty()));
@@ -1178,7 +1208,12 @@ TEST_F(Model_MetaInfo, removed_exported_type_names_are_changed_callback_is_calli
ProjectStorageObserverMock observerMock;
QmlDesigner::ProjectStorageObserver *observer = nullptr;
ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; });
QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
-1,
-1,
nullptr,
{}};
model.attachView(&viewMock);
EXPECT_CALL(viewMock, exportedTypeNamesChanged(IsEmpty(), removed));
@@ -1355,7 +1390,7 @@ TEST_F(Model_ViewManagement, dont_call_modelAttached_if_node_instance_view_is_al
TEST_F(Model_ViewManagement, detach_node_instance_view_from_other_model_before_attach_to_new_model)
{
InSequence s;
QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock},
QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,
@@ -1401,7 +1436,7 @@ TEST_F(Model_ViewManagement, attach_view_is_not_calling_modelAttached_if_it_is_a
TEST_F(Model_ViewManagement, view_is_detached_before_it_is_attached_ot_new_model)
{
InSequence s;
QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock},
QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
fileUrl,

View File

@@ -4,6 +4,7 @@
#include "../utils/googletest.h"
#include "../mocks/projectstoragemock.h"
#include "../mocks/projectstoragetriggerupdatemock.h"
#include "../mocks/sourcepathcachemock.h"
#include <designercore/include/model.h>
@@ -15,9 +16,10 @@ namespace {
class ModelNode : public testing::Test
{
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCache{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCache.sourceId, "/path"};
QmlDesigner::Model model{{projectStorageMock, pathCache}, "Item"};
QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item"};
QmlDesigner::ModelNode rootNode = model.rootModelNode();
};

View File

@@ -6,6 +6,7 @@
#include "../mocks/abstractviewmock.h"
#include "../mocks/modelresourcemanagementmock.h"
#include "../mocks/projectstoragemock.h"
#include "../mocks/projectstoragetriggerupdatemock.h"
#include "../mocks/sourcepathcachemock.h"
#include <include/bindingproperty.h>
@@ -71,10 +72,11 @@ protected:
protected:
NiceMock<AbstractViewMock> viewMock;
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
QmlDesigner::ModelResourceManagement management;
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
{QmlDesigner::Import::createLibraryImport("QtQtuick")},
QUrl::fromLocalFile(pathCacheMock.path.toQString())};

View File

@@ -4,6 +4,7 @@
#include <abstractviewmock.h>
#include <googletest.h>
#include <projectstoragemock.h>
#include <projectstoragetriggerupdatemock.h>
#include <sourcepathcachemock.h>
#include <model.h>
@@ -73,11 +74,13 @@ protected:
}
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<SourcePathCacheMockWithPaths> pathCache{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCache.sourceId, "/path"};
QmlDesigner::ModelPointer model{
QmlDesigner::Model::create(QmlDesigner::ProjectStorageDependencies{projectStorageMock,
pathCache},
pathCache,
projectStorageTriggerUpdateMock},
"Item",
{QmlDesigner::Import::createLibraryImport("QtQuick")},
QUrl::fromLocalFile(pathCache.path.toQString()))};

View File

@@ -7,6 +7,7 @@
#include <mocks/abstractviewmock.h>
#include <mocks/modelresourcemanagementmock.h>
#include <mocks/projectstoragemock.h>
#include <mocks/projectstoragetriggerupdatemock.h>
#include <mocks/sourcepathcachemock.h>
#include <rewriterview.h>
#include <textmodifiermock.h>
@@ -26,13 +27,14 @@ protected:
~RewriterView() { model.setRewriterView(nullptr); }
protected:
NiceMock<ProjectStorageTriggerUpdateMock> projectStorageTriggerUpdateMock;
NiceMock<ExternalDependenciesMock> externalDependenciesMock;
NiceMock<TextModifierMock> textModifierMock;
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/foo.qml"};
NiceMock<ProjectStorageMockWithQtQuick> projectStorageMock{pathCacheMock.sourceId, "/path"};
NiceMock<ModelResourceManagementMock> resourceManagementMock;
QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")};
QmlDesigner::Model model{{projectStorageMock, pathCacheMock},
QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock},
"Item",
imports,
QUrl::fromLocalFile(pathCacheMock.path.toQString()),

View File

@@ -415,6 +415,51 @@ TEST_F(ProjectStoragePathWatcher, no_duplicate_path_changes)
mockQFileSytemWatcher.directoryChanged(sourceContextPath);
}
TEST_F(ProjectStoragePathWatcher, trigger_manual_two_notify_file_changes)
{
watcher.updateIdPaths(
{{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}},
{projectChunkId3, {sourceIds[4]}}});
ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0])))
.WillByDefault(Return(FileStatus{sourceIds[0], 1, 2}));
ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[1])))
.WillByDefault(Return(FileStatus{sourceIds[1], 1, 2}));
ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3])))
.WillByDefault(Return(FileStatus{sourceIds[3], 1, 2}));
EXPECT_CALL(notifier,
pathsWithIdsChanged(
ElementsAre(IdPaths{projectChunkId1, {sourceIds[0], sourceIds[1]}},
IdPaths{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}})));
watcher.checkForChangeInDirectory({sourceIds[0].contextId(), sourceIds[1].contextId()});
}
TEST_F(ProjectStoragePathWatcher, trigger_manual_notify_for_path_changes)
{
watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0])))
.WillByDefault(Return(FileStatus{sourceIds[0], 1, 2}));
ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3])))
.WillByDefault(Return(FileStatus{sourceIds[3], 1, 2}));
EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0])));
watcher.checkForChangeInDirectory({sourceIds[0].contextId()});
}
TEST_F(ProjectStoragePathWatcher, trigger_manual_no_notify_for_unwatched_path_changes)
{
watcher.updateIdPaths({{projectChunkId1, {sourceIds[3]}}, {projectChunkId2, {sourceIds[3]}}});
EXPECT_CALL(notifier, pathsChanged(IsEmpty()));
watcher.checkForChangeInDirectory({sourceIds[0].contextId()});
}
TEST_F(ProjectStoragePathWatcher, update_context_id_paths_adds_entry_in_new_directory)
{
watcher.updateIdPaths({