forked from qt-creator/qt-creator
QmlDesiger: ProjectStorage provides properties for typeId
It returns all properties of the type and the prototype chain in a sorted order. Task-nubmer: QDS-7276 Change-Id: I95c16abd16d9d0f1fdf68d3425780a888dc056b7 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -149,6 +149,18 @@ public:
|
||||
.template valueWithTransaction<TypeId>(&moduleId, exportedTypeName);
|
||||
}
|
||||
|
||||
PropertyDeclarationIds propertyIds(TypeId typeId) const
|
||||
{
|
||||
return selectPropertyDeclarationIdsForTypeStatement
|
||||
.template valuesWithTransaction<PropertyDeclarationId>(32, &typeId);
|
||||
}
|
||||
|
||||
Utils::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const
|
||||
{
|
||||
return selectPropertyNameStatement.template optionalValueWithTransaction<Utils::SmallString>(
|
||||
&propertyDeclarationId);
|
||||
}
|
||||
|
||||
PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,
|
||||
Utils::SmallStringView name)
|
||||
{
|
||||
@@ -2658,7 +2670,7 @@ public:
|
||||
"aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, "
|
||||
"propertyImportedTypeNameId",
|
||||
database};
|
||||
ReadStatement<1, 1> selectPropertyNameStatement{
|
||||
mutable ReadStatement<1, 1> selectPropertyNameStatement{
|
||||
"SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
|
||||
WriteStatement<2> updatePropertyDeclarationTypeStatement{
|
||||
"UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database};
|
||||
@@ -2845,6 +2857,16 @@ public:
|
||||
" moduleExportedImportId "
|
||||
"FROM imports",
|
||||
database};
|
||||
mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForTypeStatement{
|
||||
"WITH RECURSIVE "
|
||||
" typeChain(typeId) AS ("
|
||||
" VALUES(?1)"
|
||||
" UNION ALL "
|
||||
" SELECT prototypeId FROM types JOIN typeChain "
|
||||
" USING(typeId) WHERE prototypeId IS NOT NULL)"
|
||||
"SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations "
|
||||
" USING(typeId) ORDER BY propertyDeclarationId",
|
||||
database};
|
||||
};
|
||||
extern template class ProjectStorage<Sqlite::Database>;
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -176,6 +176,51 @@ MATCHER_P4(IsPropertyDeclaration,
|
||||
&& propertyDeclaration.traits == traits;
|
||||
}
|
||||
|
||||
class HasNameMatcher
|
||||
{
|
||||
public:
|
||||
using is_gtest_matcher = void;
|
||||
|
||||
HasNameMatcher(const QmlDesigner::ProjectStorage<Sqlite::Database> &storage,
|
||||
Utils::SmallStringView name)
|
||||
: storage{storage}
|
||||
, name{name}
|
||||
{}
|
||||
|
||||
bool MatchAndExplain(QmlDesigner::PropertyDeclarationId id, std::ostream *listener) const
|
||||
{
|
||||
auto propertyName = storage.propertyName(id);
|
||||
bool success = propertyName && *propertyName == name;
|
||||
|
||||
if (success)
|
||||
return true;
|
||||
|
||||
if (listener) {
|
||||
if (propertyName)
|
||||
*listener << "name is '" << *propertyName << "', not '" << name << "'";
|
||||
else
|
||||
*listener << "there is no '" << name << "'";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DescribeTo(std::ostream *os) const { *os << "is '" << name << "'"; }
|
||||
|
||||
void DescribeNegationTo(std::ostream *os) const { *os << "is not '" << name << "'"; }
|
||||
|
||||
private:
|
||||
const QmlDesigner::ProjectStorage<Sqlite::Database> &storage;
|
||||
Utils::SmallStringView name;
|
||||
};
|
||||
|
||||
#define HasName(name) Matcher<QmlDesigner::PropertyDeclarationId>(HasNameMatcher{storage, name})
|
||||
|
||||
MATCHER(IsSorted, std::string(negation ? "isn't sorted" : "is sorted"))
|
||||
{
|
||||
return std::is_sorted(begin(arg), end(arg));
|
||||
}
|
||||
|
||||
class ProjectStorage : public testing::Test
|
||||
{
|
||||
protected:
|
||||
@@ -577,6 +622,59 @@ protected:
|
||||
return package;
|
||||
}
|
||||
|
||||
auto createPackageWithProperties()
|
||||
{
|
||||
SynchronizationPackage package;
|
||||
|
||||
package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
|
||||
|
||||
package.types.push_back(Storage::Type{
|
||||
"QObject",
|
||||
Storage::ImportedType{},
|
||||
TypeAccessSemantics::Reference,
|
||||
sourceId1,
|
||||
{Storage::ExportedType{qmlModuleId, "Object", Storage::Version{}}},
|
||||
{Storage::PropertyDeclaration{"data",
|
||||
Storage::ImportedType{"Object"},
|
||||
Storage::PropertyDeclarationTraits::IsList},
|
||||
Storage::PropertyDeclaration{"children",
|
||||
Storage::ImportedType{"Object"},
|
||||
Storage::PropertyDeclarationTraits::IsList
|
||||
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
|
||||
package.types.push_back(Storage::Type{
|
||||
"QObject2",
|
||||
Storage::ImportedType{"Object"},
|
||||
TypeAccessSemantics::Reference,
|
||||
sourceId1,
|
||||
{Storage::ExportedType{qmlModuleId, "Object2", Storage::Version{}}},
|
||||
{Storage::PropertyDeclaration{"data2",
|
||||
Storage::ImportedType{"Object3"},
|
||||
Storage::PropertyDeclarationTraits::IsList},
|
||||
Storage::PropertyDeclaration{"children2",
|
||||
Storage::ImportedType{"Object3"},
|
||||
Storage::PropertyDeclarationTraits::IsList
|
||||
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
|
||||
package.types.push_back(Storage::Type{
|
||||
"QObject3",
|
||||
Storage::ImportedType{"Object2"},
|
||||
TypeAccessSemantics::Reference,
|
||||
sourceId1,
|
||||
{Storage::ExportedType{qmlModuleId, "Object3", Storage::Version{}}},
|
||||
{Storage::PropertyDeclaration{"data3",
|
||||
Storage::ImportedType{"Object2"},
|
||||
Storage::PropertyDeclarationTraits::IsList},
|
||||
Storage::PropertyDeclaration{"children3",
|
||||
Storage::ImportedType{"Object2"},
|
||||
Storage::PropertyDeclarationTraits::IsList
|
||||
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
|
||||
|
||||
package.updatedSourceIds.push_back(sourceId1);
|
||||
|
||||
shuffle(package.types);
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
auto createModuleExportedImportSynchronizationPackage()
|
||||
{
|
||||
SynchronizationPackage package;
|
||||
@@ -5047,4 +5145,58 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForWrongMajorVersion)
|
||||
ASSERT_FALSE(typeId);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, GetProperties)
|
||||
{
|
||||
auto package{createPackageWithProperties()};
|
||||
storage.synchronize(package);
|
||||
auto itemTypeId = fetchTypeId(sourceId1, "QObject3");
|
||||
|
||||
auto propertyIds = storage.propertyIds(itemTypeId);
|
||||
|
||||
ASSERT_THAT(propertyIds,
|
||||
UnorderedElementsAre(HasName("data"),
|
||||
HasName("children"),
|
||||
HasName("data2"),
|
||||
HasName("children2"),
|
||||
HasName("data3"),
|
||||
HasName("children3")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, GetPropertiesAreReturnedSorted)
|
||||
{
|
||||
auto package{createPackageWithProperties()};
|
||||
storage.synchronize(package);
|
||||
auto itemTypeId = fetchTypeId(sourceId1, "QObject3");
|
||||
|
||||
auto propertyIds = storage.propertyIds(itemTypeId);
|
||||
|
||||
ASSERT_THAT(propertyIds, IsSorted());
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, GetNoPropertiesPropertiesFromDerivedTypes)
|
||||
{
|
||||
auto package{createPackageWithProperties()};
|
||||
storage.synchronize(package);
|
||||
auto itemTypeId = fetchTypeId(sourceId1, "QObject2");
|
||||
|
||||
auto propertyIds = storage.propertyIds(itemTypeId);
|
||||
|
||||
ASSERT_THAT(propertyIds,
|
||||
UnorderedElementsAre(HasName("data"),
|
||||
HasName("children"),
|
||||
HasName("data2"),
|
||||
HasName("children2")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, GetNoPropertiesForWrongTypeId)
|
||||
{
|
||||
auto package{createPackageWithProperties()};
|
||||
storage.synchronize(package);
|
||||
auto itemTypeId = fetchTypeId(sourceId1, "WrongObject");
|
||||
|
||||
auto propertyIds = storage.propertyIds(itemTypeId);
|
||||
|
||||
ASSERT_THAT(propertyIds, IsEmpty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user