forked from qt-creator/qt-creator
QmlDesigner: Add Import Synchronization
Task-number: QDS-4460 Change-Id: Icd419baa7881fe882539f10d335ab6b3d36bc7b5 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -82,7 +82,8 @@ enum class BasicIdType {
|
|||||||
StorageCacheIndex,
|
StorageCacheIndex,
|
||||||
FunctionDeclaration,
|
FunctionDeclaration,
|
||||||
SignalDeclaration,
|
SignalDeclaration,
|
||||||
EnumerationDeclaration
|
EnumerationDeclaration,
|
||||||
|
Import
|
||||||
};
|
};
|
||||||
|
|
||||||
using TypeId = BasicId<BasicIdType::Type>;
|
using TypeId = BasicId<BasicIdType::Type>;
|
||||||
@@ -106,4 +107,7 @@ using SourceContextIds = std::vector<SourceContextId>;
|
|||||||
using SourceId = BasicId<BasicIdType::SourceId, int>;
|
using SourceId = BasicId<BasicIdType::SourceId, int>;
|
||||||
using SourceIds = std::vector<SourceId>;
|
using SourceIds = std::vector<SourceId>;
|
||||||
|
|
||||||
|
using ImportId = BasicId<BasicIdType::Import>;
|
||||||
|
using ImportIds = std::vector<ImportId>;
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -75,6 +75,16 @@ public:
|
|||||||
transaction.commit();
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void synchronizeImports(Storage::Imports imports)
|
||||||
|
{
|
||||||
|
Sqlite::ImmediateTransaction transaction{database};
|
||||||
|
|
||||||
|
synchronizeImportsAndUpdatesImportIds(imports);
|
||||||
|
synchronizeImportDependencies(createSortedImportDependecies(imports));
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
}
|
||||||
|
|
||||||
TypeId upsertType(Utils::SmallStringView name,
|
TypeId upsertType(Utils::SmallStringView name,
|
||||||
TypeId prototypeId,
|
TypeId prototypeId,
|
||||||
Storage::TypeAccessSemantics accessSemantics,
|
Storage::TypeAccessSemantics accessSemantics,
|
||||||
@@ -255,7 +265,149 @@ public:
|
|||||||
return writeSourceId(sourceContextId, sourceName);
|
return writeSourceId(sourceContextId, sourceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto fetchAllImports() const
|
||||||
|
{
|
||||||
|
Storage::Imports imports;
|
||||||
|
imports.reserve(128);
|
||||||
|
|
||||||
|
auto callback = [&](Utils::SmallStringView name, int version, int sourceId, long long importId) {
|
||||||
|
auto &lastImport = imports.emplace_back(name,
|
||||||
|
Storage::VersionNumber{version},
|
||||||
|
SourceId{sourceId});
|
||||||
|
|
||||||
|
lastImport.importDependencies = selectImportsForThatDependentOnThisImportIdStatement
|
||||||
|
.template values<Storage::BasicImport>(6, importId);
|
||||||
|
|
||||||
|
return Sqlite::CallbackControl::Continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
selectAllImportsStatement.readCallbackWithTransaction(callback);
|
||||||
|
|
||||||
|
return imports;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ImportDependency
|
||||||
|
{
|
||||||
|
ImportDependency(ImportId id, ImportId dependencyId)
|
||||||
|
: id{id}
|
||||||
|
, dependencyId{dependencyId}
|
||||||
|
{}
|
||||||
|
|
||||||
|
ImportDependency(long long id, long long dependencyId)
|
||||||
|
: id{id}
|
||||||
|
, dependencyId{dependencyId}
|
||||||
|
{}
|
||||||
|
|
||||||
|
ImportId id;
|
||||||
|
ImportId dependencyId;
|
||||||
|
|
||||||
|
friend bool operator<(ImportDependency first, ImportDependency second)
|
||||||
|
{
|
||||||
|
return std::tie(first.id, first.dependencyId) < std::tie(second.id, second.dependencyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(ImportDependency first, ImportDependency second)
|
||||||
|
{
|
||||||
|
return first.id == second.id && first.dependencyId == second.dependencyId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void synchronizeImportsAndUpdatesImportIds(Storage::Imports &imports)
|
||||||
|
{
|
||||||
|
auto compareKey = [](auto &&first, auto &&second) {
|
||||||
|
auto nameCompare = Sqlite::compare(first.name, second.name);
|
||||||
|
|
||||||
|
if (nameCompare != 0)
|
||||||
|
return nameCompare;
|
||||||
|
|
||||||
|
return first.version.version - second.version.version;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::sort(imports.begin(), imports.end(), [&](auto &&first, auto &&second) {
|
||||||
|
return compareKey(first, second) < 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto range = selectAllImportsStatement.template range<Storage::ImportView>();
|
||||||
|
|
||||||
|
auto insert = [&](Storage::Import &import) {
|
||||||
|
import.importId = insertImportStatement.template value<ImportId>(import.name,
|
||||||
|
import.version.version,
|
||||||
|
&import.sourceId);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto update = [&](const Storage::ImportView &importView, Storage::Import &import) {
|
||||||
|
if (importView.sourceId.id != import.sourceId.id)
|
||||||
|
updateImportStatement.write(&importView.importId, &import.sourceId);
|
||||||
|
import.importId = importView.importId;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto remove = [&](const Storage::ImportView &importView) {
|
||||||
|
deleteImportStatement.write(&importView.importId);
|
||||||
|
};
|
||||||
|
|
||||||
|
Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ImportDependency> createSortedImportDependecies(const Storage::Imports &imports) const
|
||||||
|
{
|
||||||
|
std::vector<ImportDependency> importDependecies;
|
||||||
|
importDependecies.reserve(imports.size() * 5);
|
||||||
|
|
||||||
|
for (const Storage::Import &import : imports) {
|
||||||
|
for (const Storage::BasicImport &importDependency : import.importDependencies) {
|
||||||
|
auto importIdForDependency = fetchImportId(importDependency);
|
||||||
|
|
||||||
|
if (!importIdForDependency)
|
||||||
|
throw ImportDoesNotExists{};
|
||||||
|
|
||||||
|
importDependecies.emplace_back(import.importId, importIdForDependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(importDependecies.begin(), importDependecies.end());
|
||||||
|
importDependecies.erase(std::unique(importDependecies.begin(), importDependecies.end()),
|
||||||
|
importDependecies.end());
|
||||||
|
|
||||||
|
return importDependecies;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizeImportDependencies(const std::vector<ImportDependency> &importDependecies)
|
||||||
|
{
|
||||||
|
auto compareKey = [](ImportDependency first, ImportDependency second) {
|
||||||
|
auto idCompare = first.id.id - second.id.id;
|
||||||
|
|
||||||
|
if (idCompare != 0)
|
||||||
|
return idCompare;
|
||||||
|
|
||||||
|
return first.dependencyId.id - second.dependencyId.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto range = selectAllImportDependenciesStatement.template range<ImportDependency>();
|
||||||
|
|
||||||
|
auto insert = [&](ImportDependency dependency) {
|
||||||
|
insertImportDependencyStatement.write(&dependency.id, &dependency.dependencyId);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto update = [](ImportDependency, ImportDependency) {};
|
||||||
|
|
||||||
|
auto remove = [&](ImportDependency dependency) {
|
||||||
|
deleteImportDependencyStatement.write(&dependency.id, &dependency.dependencyId);
|
||||||
|
};
|
||||||
|
|
||||||
|
Sqlite::insertUpdateDelete(range, importDependecies, compareKey, insert, update, remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportId fetchImportId(const Storage::BasicImport &import) const
|
||||||
|
{
|
||||||
|
if (import.version) {
|
||||||
|
return selectImportIdByNameAndVersionStatement
|
||||||
|
.template value<ImportId>(import.name, import.version.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectImportIdByNameStatement.template value<ImportId>(import.name);
|
||||||
|
}
|
||||||
|
|
||||||
void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, const SourceIds &sourceIds)
|
void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, const SourceIds &sourceIds)
|
||||||
{
|
{
|
||||||
auto updatedTypeIdValues = Utils::transform<std::vector>(updatedTypeIds, [](TypeId typeId) {
|
auto updatedTypeIdValues = Utils::transform<std::vector>(updatedTypeIds, [](TypeId typeId) {
|
||||||
@@ -638,6 +790,8 @@ private:
|
|||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
Sqlite::ExclusiveTransaction transaction{database};
|
Sqlite::ExclusiveTransaction transaction{database};
|
||||||
|
|
||||||
|
createImportsTable(database);
|
||||||
|
createImportDependeciesTable(database);
|
||||||
createSourceContextsTable(database);
|
createSourceContextsTable(database);
|
||||||
createSourcesTable(database);
|
createSourcesTable(database);
|
||||||
createTypesTable(database);
|
createTypesTable(database);
|
||||||
@@ -791,6 +945,35 @@ private:
|
|||||||
|
|
||||||
table.initialize(database);
|
table.initialize(database);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void createImportsTable(Database &database)
|
||||||
|
{
|
||||||
|
Sqlite::Table table;
|
||||||
|
table.setUseIfNotExists(true);
|
||||||
|
table.setName("imports");
|
||||||
|
table.addColumn("importId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
|
auto &nameColumn = table.addColumn("name");
|
||||||
|
auto &versionColumn = table.addColumn("version");
|
||||||
|
table.addColumn("sourceId");
|
||||||
|
|
||||||
|
table.addUniqueIndex({nameColumn, versionColumn});
|
||||||
|
|
||||||
|
table.initialize(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createImportDependeciesTable(Database &database)
|
||||||
|
{
|
||||||
|
Sqlite::Table table;
|
||||||
|
table.setUseIfNotExists(true);
|
||||||
|
table.setUseWithoutRowId(true);
|
||||||
|
table.setName("importDependencies");
|
||||||
|
auto &importIdColumn = table.addColumn("importId");
|
||||||
|
auto &parentImportIdColumn = table.addColumn("parentImportId");
|
||||||
|
|
||||||
|
table.addPrimaryKeyContraint({importIdColumn, parentImportIdColumn});
|
||||||
|
|
||||||
|
table.initialize(database);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -974,6 +1157,28 @@ public:
|
|||||||
database};
|
database};
|
||||||
WriteStatement deleteEnumerationDeclarationStatement{
|
WriteStatement deleteEnumerationDeclarationStatement{
|
||||||
"DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database};
|
"DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database};
|
||||||
|
mutable ReadWriteStatement<1> insertImportStatement{
|
||||||
|
"INSERT INTO imports(name, version, sourceId) VALUES(?1, ?2, ?3) RETURNING importId",
|
||||||
|
database};
|
||||||
|
WriteStatement updateImportStatement{"UPDATE imports SET sourceId=?2 WHERE importId=?1", database};
|
||||||
|
WriteStatement deleteImportStatement{"DELETE FROM imports WHERE importId=?", database};
|
||||||
|
mutable ReadStatement<1> selectImportIdByNameStatement{
|
||||||
|
"SELECT importId FROM imports WHERE name=? ORDER BY version DESC LIMIT 1", database};
|
||||||
|
mutable ReadStatement<1> selectImportIdByNameAndVersionStatement{
|
||||||
|
"SELECT importId FROM imports WHERE name=? AND version=?", database};
|
||||||
|
mutable ReadStatement<4> selectAllImportsStatement{
|
||||||
|
"SELECT name, version, sourceId, importId FROM imports ORDER BY name, version", database};
|
||||||
|
WriteStatement insertImportDependencyStatement{
|
||||||
|
"INSERT INTO importDependencies(importId, parentImportId) VALUES(?1, ?2)", database};
|
||||||
|
WriteStatement deleteImportDependencyStatement{
|
||||||
|
"DELETE FROM importDependencies WHERE importId=?1 AND parentImportId=?2", database};
|
||||||
|
mutable ReadStatement<2> selectAllImportDependenciesStatement{
|
||||||
|
"SELECT importId, parentImportId FROM importDependencies ORDER BY importId, parentImportId",
|
||||||
|
database};
|
||||||
|
mutable ReadStatement<2> selectImportsForThatDependentOnThisImportIdStatement{
|
||||||
|
"SELECT name, version FROM importDependencies JOIN imports ON "
|
||||||
|
"importDependencies.parentImportId = imports.importId WHERE importDependencies.importId=?",
|
||||||
|
database};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -71,4 +71,10 @@ public:
|
|||||||
const char *what() const noexcept override { return "The source id is invalid!"; }
|
const char *what() const noexcept override { return "The source id is invalid!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ImportDoesNotExists : std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const char *what() const noexcept override { return "The simport does not exist!"; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -60,7 +60,7 @@ public:
|
|||||||
: version{version}
|
: version{version}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
explicit operator bool() { return version >= 0; }
|
explicit operator bool() const { return version >= 0; }
|
||||||
|
|
||||||
friend bool operator==(VersionNumber first, VersionNumber second) noexcept
|
friend bool operator==(VersionNumber first, VersionNumber second) noexcept
|
||||||
{
|
{
|
||||||
@@ -432,4 +432,84 @@ public:
|
|||||||
|
|
||||||
using Types = std::vector<Type>;
|
using Types = std::vector<Type>;
|
||||||
|
|
||||||
|
class BasicImport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit BasicImport(Utils::SmallStringView name, VersionNumber version = VersionNumber{})
|
||||||
|
: name{name}
|
||||||
|
, version{version}
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit BasicImport(Utils::SmallStringView name, int version)
|
||||||
|
: name{name}
|
||||||
|
, version{version}
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const BasicImport &first, const BasicImport &second)
|
||||||
|
{
|
||||||
|
return first.name == second.name && first.version == second.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::PathString name;
|
||||||
|
VersionNumber version;
|
||||||
|
};
|
||||||
|
|
||||||
|
using BasicImports = std::vector<BasicImport>;
|
||||||
|
|
||||||
|
class Import : public BasicImport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Import(Utils::SmallStringView name,
|
||||||
|
VersionNumber version = VersionNumber{},
|
||||||
|
SourceId sourceId = SourceId{},
|
||||||
|
BasicImports importDependencies = {})
|
||||||
|
: BasicImport(name, version)
|
||||||
|
, importDependencies{std::move(importDependencies)}
|
||||||
|
, sourceId{sourceId}
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit Import(Utils::SmallStringView name, int version, int sourceId)
|
||||||
|
: BasicImport(name, version)
|
||||||
|
, sourceId{sourceId}
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const Import &first, const Import &second)
|
||||||
|
{
|
||||||
|
return static_cast<const BasicImport &>(first) == static_cast<const BasicImport &>(second)
|
||||||
|
&& first.sourceId == second.sourceId
|
||||||
|
&& first.importDependencies == second.importDependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
BasicImports importDependencies;
|
||||||
|
SourceId sourceId;
|
||||||
|
ImportId importId;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Imports = std::vector<Import>;
|
||||||
|
|
||||||
|
class ImportView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ImportView(Utils::SmallStringView name, int version, int sourceId, long long importId)
|
||||||
|
: name{name}
|
||||||
|
, version{version}
|
||||||
|
, sourceId{sourceId}
|
||||||
|
, importId{importId}
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const ImportView &first, const ImportView &second)
|
||||||
|
{
|
||||||
|
return first.name == second.name
|
||||||
|
&& first.version == second.version & first.sourceId == second.sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallStringView name;
|
||||||
|
VersionNumber version;
|
||||||
|
SourceId sourceId;
|
||||||
|
ImportId importId;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner::Storage
|
} // namespace QmlDesigner::Storage
|
||||||
|
@@ -1732,6 +1732,17 @@ std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumer
|
|||||||
<< enumerationDeclaration.enumeratorDeclarations << ")";
|
<< enumerationDeclaration.enumeratorDeclarations << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const BasicImport &import)
|
||||||
|
{
|
||||||
|
return out << "(" << import.name << ", " << import.version << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const Import &import)
|
||||||
|
{
|
||||||
|
return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ", "
|
||||||
|
<< import.importDependencies << ")";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Storage
|
} // namespace Storage
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
@@ -407,6 +407,8 @@ class ParameterDeclaration;
|
|||||||
class SignalDeclaration;
|
class SignalDeclaration;
|
||||||
class EnumerationDeclaration;
|
class EnumerationDeclaration;
|
||||||
class EnumeratorDeclaration;
|
class EnumeratorDeclaration;
|
||||||
|
class BasicImport;
|
||||||
|
class Import;
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics);
|
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics);
|
||||||
std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
|
std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
|
||||||
@@ -420,6 +422,8 @@ std::ostream &operator<<(std::ostream &out, const ParameterDeclaration ¶mete
|
|||||||
std::ostream &operator<<(std::ostream &out, const SignalDeclaration &signalDeclaration);
|
std::ostream &operator<<(std::ostream &out, const SignalDeclaration &signalDeclaration);
|
||||||
std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumerationDeclaration);
|
std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumerationDeclaration);
|
||||||
std::ostream &operator<<(std::ostream &out, const EnumeratorDeclaration &enumeratorDeclaration);
|
std::ostream &operator<<(std::ostream &out, const EnumeratorDeclaration &enumeratorDeclaration);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const BasicImport &import);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const Import &import);
|
||||||
|
|
||||||
} // namespace Storage
|
} // namespace Storage
|
||||||
|
|
||||||
|
@@ -119,6 +119,28 @@ MATCHER_P3(IsPropertyDeclaration,
|
|||||||
&& propertyDeclaration.traits == traits;
|
&& propertyDeclaration.traits == traits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MATCHER_P2(IsBasicImport,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
std::string(negation ? "isn't " : "is ") + PrintToString(Storage::Import{name, version}))
|
||||||
|
{
|
||||||
|
const Storage::BasicImport &import = arg;
|
||||||
|
|
||||||
|
return import.name == name && import.version == version;
|
||||||
|
}
|
||||||
|
|
||||||
|
MATCHER_P3(IsImport,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
sourceId,
|
||||||
|
std::string(negation ? "isn't " : "is ")
|
||||||
|
+ PrintToString(Storage::Import{name, version, sourceId}))
|
||||||
|
{
|
||||||
|
const Storage::Import &import = arg;
|
||||||
|
|
||||||
|
return import.name == name && import.version == version && &import.sourceId == &sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
class ProjectStorage : public testing::Test
|
class ProjectStorage : public testing::Test
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -528,6 +550,24 @@ protected:
|
|||||||
Storage::ExportedType{"Qml.Object", Storage::Version{5, 1}}}}};
|
Storage::ExportedType{"Qml.Object", Storage::Version{5, 1}}}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto createImports()
|
||||||
|
{
|
||||||
|
importSourceId1 = sourcePathCache.sourceId(importPath1);
|
||||||
|
importSourceId2 = sourcePathCache.sourceId(importPath2);
|
||||||
|
importSourceId3 = sourcePathCache.sourceId(importPath3);
|
||||||
|
|
||||||
|
return Storage::Imports{Storage::Import{"Qml", Storage::VersionNumber{2}, importSourceId1, {}},
|
||||||
|
Storage::Import{"QtQuick",
|
||||||
|
Storage::VersionNumber{},
|
||||||
|
importSourceId2,
|
||||||
|
{Storage::Import{"Qml", Storage::VersionNumber{2}}}},
|
||||||
|
Storage::Import{"/path/to",
|
||||||
|
Storage::VersionNumber{},
|
||||||
|
SourceId{},
|
||||||
|
{Storage::Import{"QtQuick"},
|
||||||
|
Storage::Import{"Qml", Storage::VersionNumber{2}}}}};
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
|
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
|
||||||
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
||||||
@@ -541,6 +581,12 @@ protected:
|
|||||||
SourceId sourceId2;
|
SourceId sourceId2;
|
||||||
SourceId sourceId3;
|
SourceId sourceId3;
|
||||||
SourceId sourceId4;
|
SourceId sourceId4;
|
||||||
|
QmlDesigner::SourcePathView importPath1{"/import/path1/to"};
|
||||||
|
QmlDesigner::SourcePathView importPath2{"/import/path2/to"};
|
||||||
|
QmlDesigner::SourcePathView importPath3{"/import/aaaa/to"};
|
||||||
|
SourceId importSourceId1;
|
||||||
|
SourceId importSourceId2;
|
||||||
|
SourceId importSourceId3;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ProjectStorageSlowTest, FetchTypeIdByName)
|
TEST_F(ProjectStorageSlowTest, FetchTypeIdByName)
|
||||||
@@ -1953,4 +1999,273 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddEnumerationDeclaration)
|
|||||||
Eq(types[0].enumerationDeclarations[2]))))));
|
Eq(types[0].enumerationDeclarations[2]))))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImports)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImportsAgain)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddMoreImports)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.push_back(Storage::Import{"QtQuick.Foo", Storage::VersionNumber{1}, importSourceId3});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
IsImport("QtQuick.Foo", Storage::VersionNumber{1}, importSourceId3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddSameImportNameButDifferentVersion)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{4}, importSourceId3});
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.pop_back();
|
||||||
|
imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId3});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
IsImport("Qml", Storage::VersionNumber{3}, importSourceId3),
|
||||||
|
IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsRemoveImport)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.pop_back();
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsUpdateImport)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports[1].sourceId = importSourceId3;
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
IsImport("QtQuick", Storage::VersionNumber{}, importSourceId3),
|
||||||
|
IsImport("/path/to", Storage::VersionNumber{}, SourceId{})));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImportDependecies)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
ElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("QtQuick",
|
||||||
|
Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddImportDependeciesWhichDoesNotExitsThrows)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
imports[1].importDependencies.push_back(Storage::Import{"QmlBase", Storage::VersionNumber{2}});
|
||||||
|
|
||||||
|
ASSERT_THROW(storage.synchronizeImports(imports), QmlDesigner::ImportDoesNotExists);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsRemovesDependeciesForRemovedImports)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
auto last = imports.back();
|
||||||
|
imports.pop_back();
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
last.importDependencies.pop_back();
|
||||||
|
imports.push_back(last);
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
ASSERT_THAT(storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
ElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddMoreImportDependecies)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.push_back(Storage::Import{"QmlBase", Storage::VersionNumber{2}, importSourceId1, {}});
|
||||||
|
imports[1].importDependencies.push_back(Storage::Import{"QmlBase", Storage::VersionNumber{2}});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QmlBase", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("QmlBase", Storage::VersionNumber{2})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsAddMoreImportDependeciesWithDifferentVersionNumber)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId1, {}});
|
||||||
|
imports[1].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{3}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("Qml", Storage::VersionNumber{3})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsDependencyGetsHighestVersionIfNoVersionIsSupplied)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId1, {}});
|
||||||
|
imports[1].importDependencies.push_back(Storage::Import{"Qml"});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{3}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("Qml", Storage::VersionNumber{3})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsDependencyGetsOnlyTheHighestDependency)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{1}, importSourceId1, {}});
|
||||||
|
imports[1].importDependencies.push_back(Storage::Import{"Qml"});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{1}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorageSlowTest, SynchronizeImportsDependencyRemoveDuplicateDependencies)
|
||||||
|
{
|
||||||
|
Storage::Imports imports{createImports()};
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
imports.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}, importSourceId1, {}});
|
||||||
|
imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}});
|
||||||
|
imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{2}});
|
||||||
|
imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{3}});
|
||||||
|
imports[2].importDependencies.push_back(Storage::Import{"Qml", Storage::VersionNumber{2}});
|
||||||
|
|
||||||
|
storage.synchronizeImports(imports);
|
||||||
|
|
||||||
|
ASSERT_THAT(
|
||||||
|
storage.fetchAllImports(),
|
||||||
|
UnorderedElementsAre(
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{2}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("Qml", Storage::VersionNumber{3}, importSourceId1),
|
||||||
|
Field(&Storage::Import::importDependencies, IsEmpty())),
|
||||||
|
AllOf(IsImport("QtQuick", Storage::VersionNumber{}, importSourceId2),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2})))),
|
||||||
|
AllOf(IsImport("/path/to", Storage::VersionNumber{}, SourceId{}),
|
||||||
|
Field(&Storage::Import::importDependencies,
|
||||||
|
UnorderedElementsAre(IsBasicImport("Qml", Storage::VersionNumber{2}),
|
||||||
|
IsBasicImport("Qml", Storage::VersionNumber{3}),
|
||||||
|
IsBasicImport("QtQuick", Storage::VersionNumber{}))))));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
Reference in New Issue
Block a user