QmlDesigner: Adapt project storage changes in updater

Task-number: QDS-5123
Task-number: QDS-4923
Task-number: QDS-4925
Change-Id: I79acbbdb11bf7a0529c1ef005e6b5e1fd0d12aa7
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2021-09-20 14:12:57 +02:00
parent 054e05951b
commit 091f157192
9 changed files with 199 additions and 66 deletions

View File

@@ -130,6 +130,11 @@ public:
, sourceId{sourceId} , sourceId{sourceId}
{} {}
explicit Module(QStringView name, SourceId sourceId = SourceId{})
: name{name}
, sourceId{sourceId}
{}
explicit Module(Utils::SmallStringView name, int sourceId) explicit Module(Utils::SmallStringView name, int sourceId)
: name{name} : name{name}
, sourceId{sourceId} , sourceId{sourceId}

View File

@@ -62,28 +62,31 @@ void ProjectUpdater::update()
SourcePath qmldirSourcePath{qmldirPath}; SourcePath qmldirSourcePath{qmldirPath};
SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath); SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath);
switch (fileState(qmlDirSourceId)) { switch (fileState(qmlDirSourceId, fileStatuses)) {
case FileState::Changed: { case FileState::Changed: {
QmlDirParser parser; QmlDirParser parser;
parser.parse(m_fileSystem.contentAsQString(qmldirPath)); parser.parse(m_fileSystem.contentAsQString(qmldirPath));
modules.emplace_back(parser.typeNamespace(), qmlDirSourceId);
sourceIds.push_back(qmlDirSourceId); sourceIds.push_back(qmlDirSourceId);
Utils::SmallString moduleName{parser.typeNamespace()}; Utils::SmallString moduleName{parser.typeNamespace()};
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId); SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
parseTypeInfos(parser.typeInfos(), directoryId, modules, types, sourceIds); parseTypeInfos(parser.typeInfos(), directoryId, imports, types, sourceIds, fileStatuses);
parseQmlComponents(createComponentReferences(parser.components()), parseQmlComponents(createComponentReferences(parser.components()),
directoryId, directoryId,
moduleName, moduleName,
modules, imports,
types, types,
sourceIds); sourceIds,
fileStatuses);
break; break;
} }
case FileState::NotChanged: { case FileState::NotChanged: {
SourceIds qmltypesSourceIds = m_projectStorage.fetchSourceDependencieIds(qmlDirSourceId); SourceIds qmltypesSourceIds = m_projectStorage.fetchSourceDependencieIds(qmlDirSourceId);
parseTypeInfos(qmltypesSourceIds, modules, types, sourceIds); parseTypeInfos(qmltypesSourceIds, imports, types, sourceIds, fileStatuses);
break; break;
} }
case FileState::NotExists: { case FileState::NotExists: {
@@ -102,9 +105,10 @@ void ProjectUpdater::update()
void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos, void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
SourceContextId directoryId, SourceContextId directoryId,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds) SourceIds &sourceIds,
FileStatuses &fileStatuses)
{ {
QString directory{m_pathCache.sourceContextPath(directoryId)}; QString directory{m_pathCache.sourceContextPath(directoryId)};
@@ -112,41 +116,44 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo}); SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo});
QString qmltypesPath = directory + "/" + typeInfo; QString qmltypesPath = directory + "/" + typeInfo;
parseTypeInfo(sourceId, qmltypesPath, modules, types, sourceIds); parseTypeInfo(sourceId, qmltypesPath, imports, types, sourceIds, fileStatuses);
} }
} }
void ProjectUpdater::parseTypeInfos(const SourceIds &qmltypesSourceIds, void ProjectUpdater::parseTypeInfos(const SourceIds &qmltypesSourceIds,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds) SourceIds &sourceIds,
FileStatuses &fileStatuses)
{ {
for (SourceId sourceId : qmltypesSourceIds) { for (SourceId sourceId : qmltypesSourceIds) {
QString qmltypesPath = m_pathCache.sourcePath(sourceId).toQString(); QString qmltypesPath = m_pathCache.sourcePath(sourceId).toQString();
parseTypeInfo(sourceId, qmltypesPath, modules, types, sourceIds); parseTypeInfo(sourceId, qmltypesPath, imports, types, sourceIds, fileStatuses);
} }
} }
void ProjectUpdater::parseTypeInfo(SourceId sourceId, void ProjectUpdater::parseTypeInfo(SourceId sourceId,
const QString &qmltypesPath, const QString &qmltypesPath,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds) SourceIds &sourceIds,
FileStatuses &fileStatuses)
{ {
if (fileState(sourceId) == FileState::Changed) { if (fileState(sourceId, fileStatuses) == FileState::Changed) {
sourceIds.push_back(sourceId); sourceIds.push_back(sourceId);
const auto content = m_fileSystem.contentAsQString(qmltypesPath); const auto content = m_fileSystem.contentAsQString(qmltypesPath);
m_qmlTypesParser.parse(content, modules, types, sourceIds); m_qmlTypesParser.parse(content, imports, types, sourceIds);
} }
} }
void ProjectUpdater::parseQmlComponents(ComponentReferences components, void ProjectUpdater::parseQmlComponents(ComponentReferences components,
SourceContextId directoryId, SourceContextId directoryId,
Utils::SmallStringView moduleName, Utils::SmallStringView moduleName,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds) SourceIds &sourceIds,
FileStatuses &fileStatuses)
{ {
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) { std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion) return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion)
@@ -166,22 +173,27 @@ void ProjectUpdater::parseQmlComponents(ComponentReferences components,
Utils::SmallString fileName{component.fileName}; Utils::SmallString fileName{component.fileName};
SourceId sourceId = m_pathCache.sourceId(directoryId, fileName); SourceId sourceId = m_pathCache.sourceId(directoryId, fileName);
if (fileState(sourceId, fileStatuses) != FileState::Changed)
continue;
sourceIds.push_back(sourceId); sourceIds.push_back(sourceId);
const auto content = m_fileSystem.contentAsQString(directory + "/" + component.fileName); const auto content = m_fileSystem.contentAsQString(directory + "/" + component.fileName);
auto type = m_qmlDocumentParser.parse(content); auto type = m_qmlDocumentParser.parse(content, imports);
type.typeName = fileName; type.typeName = fileName;
type.module.name = moduleName; type.module.name = moduleName;
type.accessSemantics = Storage::TypeAccessSemantics::Reference; type.accessSemantics = Storage::TypeAccessSemantics::Reference;
type.sourceId = sourceId; type.sourceId = sourceId;
type.exportedTypes.push_back(Storage::ExportedType{Utils::SmallString{component.typeName}}); type.exportedTypes.push_back(
Storage::ExportedType{Utils::SmallString{component.typeName},
Storage::Version{component.majorVersion, component.minorVersion}});
types.push_back(std::move(type)); types.push_back(std::move(type));
} }
} }
ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId) const ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId, FileStatuses &fileStatuses) const
{ {
auto currentFileStatus = m_fileStatusCache.find(sourceId); auto currentFileStatus = m_fileStatusCache.find(sourceId);
@@ -190,8 +202,10 @@ ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId) const
auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId); auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId);
if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) {
fileStatuses.push_back(currentFileStatus);
return FileState::Changed; return FileState::Changed;
}
return FileState::NotChanged; return FileState::NotChanged;
} }

View File

@@ -25,6 +25,7 @@
#pragma once #pragma once
#include "filestatus.h"
#include "nonlockingmutex.h" #include "nonlockingmutex.h"
#include "projectstorageids.h" #include "projectstorageids.h"
#include "projectstoragetypes.h" #include "projectstoragetypes.h"
@@ -85,26 +86,30 @@ private:
void parseTypeInfos(const QStringList &typeInfos, void parseTypeInfos(const QStringList &typeInfos,
SourceContextId directoryId, SourceContextId directoryId,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds); SourceIds &sourceIds,
FileStatuses &fileStatuses);
void parseTypeInfos(const SourceIds &qmltypesSourceIds, void parseTypeInfos(const SourceIds &qmltypesSourceIds,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds); SourceIds &sourceIds,
FileStatuses &fileStatuses);
void parseTypeInfo(SourceId sourceId, void parseTypeInfo(SourceId sourceId,
const QString &qmltypesPath, const QString &qmltypesPath,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds); SourceIds &sourceIds,
FileStatuses &fileStatuses);
void parseQmlComponents(ComponentReferences components, void parseQmlComponents(ComponentReferences components,
SourceContextId directoryId, SourceContextId directoryId,
Utils::SmallStringView moduleName, Utils::SmallStringView moduleName,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds); SourceIds &sourceIds,
FileStatuses &fileStatuses);
FileState fileState(SourceId sourceId) const; FileState fileState(SourceId sourceId, FileStatuses &fileStatuses) const;
private: private:
ProjectManagerInterface &m_projectManager; ProjectManagerInterface &m_projectManager;

View File

@@ -34,7 +34,7 @@ namespace QmlDesigner {
class QmlDocumentParserInterface class QmlDocumentParserInterface
{ {
public: public:
virtual Storage::Type parse(const QString &sourceContent) = 0; virtual Storage::Type parse(const QString &sourceContent, Storage::Imports &imports) = 0;
protected: protected:
~QmlDocumentParserInterface() = default; ~QmlDocumentParserInterface() = default;

View File

@@ -35,7 +35,7 @@ class QmlTypesParserInterface
{ {
public: public:
virtual void parse(const QString &sourceContent, virtual void parse(const QString &sourceContent,
Storage::Modules &modules, Storage::Imports &imports,
Storage::Types &types, Storage::Types &types,
SourceIds &sourceIds) SourceIds &sourceIds)
= 0; = 0;

View File

@@ -1080,7 +1080,8 @@ std::ostream &operator<<(std::ostream &out, Version version)
std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType) std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType)
{ {
return out << "(\"" << exportedType.name << "\")"; return out << "(\"" << exportedType.name << "\""
<< ", " << exportedType.version << ")";
} }
std::ostream &operator<<(std::ostream &out, const NativeType &nativeType) std::ostream &operator<<(std::ostream &out, const NativeType &nativeType)

View File

@@ -77,13 +77,40 @@ MATCHER_P3(IsPropertyDeclaration,
&& propertyDeclaration.traits == traits; && propertyDeclaration.traits == traits;
} }
MATCHER_P(IsExportedType, MATCHER_P3(IsExportedType,
name, name,
std::string(negation ? "isn't " : "is ") + PrintToString(Storage::ExportedType{name})) majorVersion,
minorVersion,
std::string(negation ? "isn't " : "is ")
+ PrintToString(Storage::ExportedType{name,
Storage::Version{majorVersion, minorVersion}}))
{ {
const Storage::ExportedType &type = arg; const Storage::ExportedType &type = arg;
return type.name == name; return type.name == name && type.version == Storage::Version{majorVersion, minorVersion};
}
MATCHER_P2(IsModule,
name,
sourceId,
std::string(negation ? "isn't " : "is ") + PrintToString(Storage::Module{name, sourceId}))
{
const Storage::Module &module = arg;
return module.name == name && module.sourceId == sourceId;
}
MATCHER_P3(IsFileStatus,
sourceId,
size,
lastModified,
std::string(negation ? "isn't " : "is ")
+ PrintToString(FileStatus{sourceId, size, lastModified}))
{
const FileStatus &fileStatus = arg;
return fileStatus.sourceId == sourceId && fileStatus.size == size
&& fileStatus.lastModified == lastModified;
} }
class ProjectStorageUpdater : public testing::Test class ProjectStorageUpdater : public testing::Test
@@ -113,6 +140,19 @@ public:
ON_CALL(projectManagerMock, qtQmlDirs()).WillByDefault(Return(QStringList{"/path/qmldir"})); ON_CALL(projectManagerMock, qtQmlDirs()).WillByDefault(Return(QStringList{"/path/qmldir"}));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
.WillByDefault(Return(qmldir)); .WillByDefault(Return(qmldir));
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 12}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId1)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId2)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 13}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 2}));
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId3)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 2}));
} }
protected: protected:
@@ -143,6 +183,9 @@ protected:
SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes"); SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes");
SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml");
SourceId qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First.2.qml");
SourceId qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml");
}; };
TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent) TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
@@ -232,8 +275,15 @@ TEST_F(ProjectStorageUpdater, ParseQmlTypes)
updater.update(); updater.update();
} }
TEST_F(ProjectStorageUpdater, DISABLED_SynchronizeIsEmptyForNoChange) TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
{ {
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypesPathSourceId)))
.WillByDefault(Return(FileStatus{qmltypesPathSourceId, 21, 421}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
.WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
.WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
EXPECT_CALL(projectStorageMock, EXPECT_CALL(projectStorageMock,
synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty())); synchronize(IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty(), IsEmpty()));
@@ -244,20 +294,23 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
{ {
auto qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); auto qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
auto qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); auto qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
Storage::Import import{"Qml", Storage::Version{2, 3}, qmltypesPathSourceId};
QString qmltypes{"Module {\ndependencies: []}"}; QString qmltypes{"Module {\ndependencies: []}"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
.WillByDefault(Return(qmltypes)); .WillByDefault(Return(qmltypes));
ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _))
.WillByDefault([&](auto, auto &moduleDependencies, auto &types, auto &sourceIds) { .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) {
types.push_back(objectType); types.push_back(objectType);
imports.push_back(import);
}); });
EXPECT_CALL(projectStorageMock, EXPECT_CALL(projectStorageMock,
synchronize(_, synchronize(ElementsAre(IsModule("Example", qmlDirPathSourceId)),
_, ElementsAre(import),
ElementsAre(Eq(objectType)), ElementsAre(Eq(objectType)),
UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId), UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId),
_)); UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
IsFileStatus(qmltypesPathSourceId, 21, 421))));
updater.update(); updater.update();
} }
@@ -268,7 +321,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
.WillByDefault(Return(qmltypes)); .WillByDefault(Return(qmltypes));
ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)) ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _))
.WillByDefault([&](auto, auto &moduleDependencies, auto &types, auto &sourceIds) { .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) {
types.push_back(objectType); types.push_back(objectType);
}); });
ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId))) ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId)))
@@ -313,30 +366,30 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
.WillByDefault(Return(qmlDocument3)); .WillByDefault(Return(qmlDocument3));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1)); EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1, _));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2)); EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2, _));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument3)); EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument3, _));
updater.update(); updater.update();
} }
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments) TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
{ {
QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstTypeV2 2.2 " Storage::Module exampleModule{"Example"};
QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstType 2.2 "
"First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"}; "First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"};
QString qmlDocument1{"First{}"}; QString qmlDocument1{"First{}"};
QString qmlDocument2{"Second{}"}; QString qmlDocument2{"Second{}"};
QString qmlDocument3{"Third{}"}; QString qmlDocument3{"Third{}"};
auto qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml");
auto qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First.2.qml");
auto qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml");
Storage::Type firstType; Storage::Type firstType;
firstType.prototype = Storage::ImportedType{"Object"}; firstType.prototype = Storage::ImportedType{"Object"};
Storage::Type secondType; Storage::Type secondType;
secondType.prototype = Storage::ImportedType{"Object2"}; secondType.prototype = Storage::ImportedType{"Object2"};
Storage::Type thirdType; Storage::Type thirdType;
thirdType.prototype = Storage::ImportedType{"Object3"}; thirdType.prototype = Storage::ImportedType{"Object3"};
auto firstQmlDocumentSourceId = sourcePathCache.sourceId("/path/First.qml"); Storage::Import import1{"Qml", Storage::Version{2, 3}, qmlDocumentSourceId1};
Storage::Import import2{"Qml", Storage::Version{}, qmlDocumentSourceId2};
Storage::Import import3{"Qml", Storage::Version{2}, qmlDocumentSourceId3};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
.WillByDefault(Return(qmlDocument1)); .WillByDefault(Return(qmlDocument1));
@@ -344,25 +397,77 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
.WillByDefault(Return(qmlDocument2)); .WillByDefault(Return(qmlDocument2));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
.WillByDefault(Return(qmlDocument3)); .WillByDefault(Return(qmlDocument3));
ON_CALL(qmlDocumentParserMock, parse(qmlDocument1)).WillByDefault(Return(firstType)); ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _)).WillByDefault([&](auto, auto &imports) {
ON_CALL(qmlDocumentParserMock, parse(qmlDocument2)).WillByDefault(Return(secondType)); imports.push_back(import1);
ON_CALL(qmlDocumentParserMock, parse(qmlDocument3)).WillByDefault(Return(thirdType)); return firstType;
});
ON_CALL(qmlDocumentParserMock, parse(qmlDocument2, _)).WillByDefault([&](auto, auto &imports) {
imports.push_back(import2);
return secondType;
});
ON_CALL(qmlDocumentParserMock, parse(qmlDocument3, _)).WillByDefault([&](auto, auto &imports) {
imports.push_back(import3);
return thirdType;
});
EXPECT_CALL(projectStorageMock, EXPECT_CALL(projectStorageMock,
synchronize(_, synchronize(ElementsAre(IsModule("Example", qmlDirPathSourceId)),
_, UnorderedElementsAre(import1, import2, import3),
Contains(AllOf(IsStorageType(Storage::Module{"Example"}, UnorderedElementsAre(
AllOf(IsStorageType(Storage::Module{"Example"},
"First.qml", "First.qml",
Storage::ImportedType{"Object"}, Storage::ImportedType{"Object"},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
firstQmlDocumentSourceId), qmlDocumentSourceId1),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType("FirstType"))))), ElementsAre(IsExportedType("FirstType", 1, 0)))),
AllOf(IsStorageType(Storage::Module{"Example"},
"First.2.qml",
Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference,
qmlDocumentSourceId2),
Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType("FirstType", 2, 2)))),
AllOf(IsStorageType(Storage::Module{"Example"},
"Second.qml",
Storage::ImportedType{"Object3"},
TypeAccessSemantics::Reference,
qmlDocumentSourceId3),
Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType("SecondType", 2, 2))))),
UnorderedElementsAre(qmlDirPathSourceId, UnorderedElementsAre(qmlDirPathSourceId,
qmlDocumentSourceId1, qmlDocumentSourceId1,
qmlDocumentSourceId2, qmlDocumentSourceId2,
qmlDocumentSourceId3), qmlDocumentSourceId3),
_)); UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
IsFileStatus(qmlDocumentSourceId1, 22, 12),
IsFileStatus(qmlDocumentSourceId2, 22, 13),
IsFileStatus(qmlDocumentSourceId3, 22, 14))));
updater.update();
}
TEST_F(ProjectStorageUpdater, SynchronizeModules)
{
SourceId qmlDirPathSourceId2 = sourcePathCache.sourceId("/path2/qmldir");
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId2)))
.WillByDefault(Return(FileStatus{qmlDirPathSourceId2, 22, 423}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId2)))
.WillByDefault(Return(FileStatus{qmlDirPathSourceId2, 2, 421}));
QString qmldir2{"module Example2\n"};
ON_CALL(projectManagerMock, qtQmlDirs())
.WillByDefault(Return(QStringList{"/path/qmldir", "/path2/qmldir"}));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path2/qmldir")))).WillByDefault(Return(qmldir2));
EXPECT_CALL(projectStorageMock,
synchronize(UnorderedElementsAre(IsModule("Example", qmlDirPathSourceId),
IsModule("Example2", qmlDirPathSourceId2)),
_,
_,
_,
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
IsFileStatus(qmltypesPathSourceId, 21, 421),
IsFileStatus(qmlDirPathSourceId2, 22, 423))));
updater.update(); updater.update();
} }

View File

@@ -32,5 +32,8 @@
class QmlDocumentParserMock : public QmlDesigner::QmlDocumentParserInterface class QmlDocumentParserMock : public QmlDesigner::QmlDocumentParserInterface
{ {
public: public:
MOCK_METHOD(QmlDesigner::Storage::Type, parse, (const QString &), (override)); MOCK_METHOD(QmlDesigner::Storage::Type,
parse,
(const QString &, QmlDesigner::Storage::Imports &),
(override));
}; };

View File

@@ -35,7 +35,7 @@ public:
MOCK_METHOD(void, MOCK_METHOD(void,
parse, parse,
(const QString &sourceContent, (const QString &sourceContent,
QmlDesigner::Storage::Modules &modules, QmlDesigner::Storage::Imports &imports,
QmlDesigner::Storage::Types &types, QmlDesigner::Storage::Types &types,
QmlDesigner::SourceIds &sourceIds), QmlDesigner::SourceIds &sourceIds),
(override)); (override));