diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h index 5e905ca4db5..55ce166d904 100644 --- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h @@ -50,6 +50,8 @@ public: bool isValid() const; explicit operator bool() const { return isValid(); } + + TypeId id() const { return m_typeId; } bool isFileComponent() const; bool hasProperty(::Utils::SmallStringView propertyName) const; PropertyMetaInfos properties() const; diff --git a/src/plugins/qmldesigner/designercore/include/propertymetainfo.h b/src/plugins/qmldesigner/designercore/include/propertymetainfo.h index ecda132a0aa..99a704a4066 100644 --- a/src/plugins/qmldesigner/designercore/include/propertymetainfo.h +++ b/src/plugins/qmldesigner/designercore/include/propertymetainfo.h @@ -49,6 +49,9 @@ public: return bool(m_nodeMetaInfoPrivateData); #endif } + + PropertyDeclarationId id() const { return m_id; } + PropertyName name() const; NodeMetaInfo propertyType() const; bool isWritable() const; diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index 1888ca847be..fd25d9c450d 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -1421,7 +1421,7 @@ bool NodeMetaInfo::isValid() const bool NodeMetaInfo::isFileComponent() const { if constexpr (useProjectStorage()) - return bool(typeData().traits & Storage::TypeTraits::IsFileComponent); + return isValid() && bool(typeData().traits & Storage::TypeTraits::IsFileComponent); else return isValid() && m_privateData->isFileComponent(); } @@ -1429,7 +1429,7 @@ bool NodeMetaInfo::isFileComponent() const bool NodeMetaInfo::hasProperty(Utils::SmallStringView propertyName) const { if constexpr (useProjectStorage()) - return bool(m_projectStorage->propertyDeclarationId(m_typeId, propertyName)); + return isValid() && bool(m_projectStorage->propertyDeclarationId(m_typeId, propertyName)); else return isValid() && m_privateData->properties().contains(propertyName); } @@ -1440,11 +1440,12 @@ PropertyMetaInfos NodeMetaInfo::properties() const return {}; if constexpr (useProjectStorage()) { - return Utils::transform( - m_projectStorage->propertyDeclarationIds(m_typeId), [&](auto id) { - return PropertyMetaInfo{id, m_projectStorage}; - }); - + if (isValid()) { + return Utils::transform( + m_projectStorage->propertyDeclarationIds(m_typeId), [&](auto id) { + return PropertyMetaInfo{id, m_projectStorage}; + }); + } } else { const auto &properties = m_privateData->properties(); @@ -1456,15 +1457,19 @@ PropertyMetaInfos NodeMetaInfo::properties() const return propertyMetaInfos; } + + return {}; } PropertyMetaInfos NodeMetaInfo::localProperties() const { if constexpr (useProjectStorage()) { - return Utils::transform( - m_projectStorage->localPropertyDeclarationIds(m_typeId), [&](auto id) { - return PropertyMetaInfo{id, m_projectStorage}; - }); + if (isValid()) { + return Utils::transform( + m_projectStorage->localPropertyDeclarationIds(m_typeId), [&](auto id) { + return PropertyMetaInfo{id, m_projectStorage}; + }); + } } else { const auto &properties = m_privateData->localProperties(); @@ -1476,15 +1481,21 @@ PropertyMetaInfos NodeMetaInfo::localProperties() const return propertyMetaInfos; } + + return {}; } PropertyMetaInfo NodeMetaInfo::property(const PropertyName &propertyName) const { if constexpr (useProjectStorage()) { - return {m_projectStorage->propertyDeclarationId(m_typeId, propertyName), m_projectStorage}; + if (isValid()) { + return {m_projectStorage->propertyDeclarationId(m_typeId, propertyName), + m_projectStorage}; + } } else { - if (hasProperty(propertyName)) + if (hasProperty(propertyName)) { return PropertyMetaInfo{m_privateData, propertyName}; + } } return {}; @@ -1493,10 +1504,13 @@ PropertyMetaInfo NodeMetaInfo::property(const PropertyName &propertyName) const PropertyNameList NodeMetaInfo::signalNames() const { if constexpr (useProjectStorage()) { - return Utils::transform(m_projectStorage->signalDeclarationNames(m_typeId), - [&](const auto &name) { - return name.toQByteArray(); - }); + if (isValid()) { + return Utils::transform(m_projectStorage->signalDeclarationNames( + m_typeId), + [&](const auto &name) { + return name.toQByteArray(); + }); + } } else { if (isValid()) return m_privateData->signalNames(); @@ -1508,10 +1522,13 @@ PropertyNameList NodeMetaInfo::signalNames() const PropertyNameList NodeMetaInfo::slotNames() const { if constexpr (useProjectStorage()) { - return Utils::transform(m_projectStorage->functionDeclarationNames(m_typeId), - [&](const auto &name) { - return name.toQByteArray(); - }); + if (isValid()) { + return Utils::transform(m_projectStorage->functionDeclarationNames( + m_typeId), + [&](const auto &name) { + return name.toQByteArray(); + }); + } } else { if (isValid()) return m_privateData->slotNames(); @@ -1523,9 +1540,11 @@ PropertyNameList NodeMetaInfo::slotNames() const PropertyName NodeMetaInfo::defaultPropertyName() const { if constexpr (useProjectStorage()) { - if (auto name = m_projectStorage->propertyName(typeData().defaultPropertyId)) - return name->toQByteArray(); - return {}; + if (isValid()) { + if (auto name = m_projectStorage->propertyName(typeData().defaultPropertyId)) { + return name->toQByteArray(); + } + } } else { if (isValid()) return m_privateData->defaultPropertyName(); @@ -1537,10 +1556,14 @@ PropertyName NodeMetaInfo::defaultPropertyName() const PropertyMetaInfo NodeMetaInfo::defaultProperty() const { if constexpr (useProjectStorage()) { - return PropertyMetaInfo(typeData().defaultPropertyId, m_projectStorage); + if (isValid()) { + return PropertyMetaInfo(typeData().defaultPropertyId, m_projectStorage); + } } else { return property(defaultPropertyName()); } + + return {}; } bool NodeMetaInfo::hasDefaultProperty() const { diff --git a/tests/unit/tests/matchers/unittest-matchers.h b/tests/unit/tests/matchers/unittest-matchers.h index 8d1c8bbf5ac..f4ff225c747 100644 --- a/tests/unit/tests/matchers/unittest-matchers.h +++ b/tests/unit/tests/matchers/unittest-matchers.h @@ -91,6 +91,16 @@ public: return false; } + bool MatchAndExplain(const QByteArray &s, testing::MatchResultListener *listener) const + { + if (s.isEmpty()) { + return true; + } + + *listener << "whose size is " << s.size(); + return false; + } + void DescribeTo(std::ostream *os) const { *os << "is empty"; } void DescribeNegationTo(std::ostream *os) const { *os << "isn't empty"; } diff --git a/tests/unit/tests/mocks/projectstoragemock.cpp b/tests/unit/tests/mocks/projectstoragemock.cpp index 71d789d0d95..37384e48507 100644 --- a/tests/unit/tests/mocks/projectstoragemock.cpp +++ b/tests/unit/tests/mocks/projectstoragemock.cpp @@ -3,7 +3,16 @@ #include "projectstoragemock.h" -namespace QmlDesigner { +#include + +using QmlDesigner::ModuleId; +using QmlDesigner::PropertyDeclarationId; +using QmlDesigner::TypeId; +using QmlDesigner::TypeIds; +using QmlDesigner::Storage::PropertyDeclarationTraits; + +namespace Storage = QmlDesigner::Storage; + namespace { template @@ -12,62 +21,6 @@ void incrementBasicId(BasicId &id) id = BasicId::create(id.internalId() + 1); } -ModuleId createModule(ProjectStorageMock &mock, Utils::SmallStringView moduleName) -{ - static ModuleId moduleId; - incrementBasicId(moduleId); - - ON_CALL(mock, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId)); - - return moduleId; -} - -PropertyDeclarationId createProperty(ProjectStorageMock &mock, TypeId typeId, Utils::SmallString name) -{ - static PropertyDeclarationId propertyId; - incrementBasicId(propertyId); - - ON_CALL(mock, propertyDeclarationId(Eq(typeId), Eq(name))).WillByDefault(Return(propertyId)); - ON_CALL(mock, propertyName(Eq(propertyId))).WillByDefault(Return(name)); - - return propertyId; -} - -TypeId createType(ProjectStorageMock &mock, - ModuleId moduleId, - Utils::SmallStringView typeName, - Utils::SmallString defaultPropertyName, - Storage::TypeTraits typeTraits, - TypeIds baseTypeIds = {}) -{ - static TypeId typeId; - incrementBasicId(typeId); - - ON_CALL(mock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId)); - PropertyDeclarationId defaultPropertyDeclarationId; - if (defaultPropertyName.size()) - defaultPropertyDeclarationId = createProperty(mock, typeId, defaultPropertyName); - ON_CALL(mock, type(Eq(typeId))) - .WillByDefault(Return(Storage::Info::Type{defaultPropertyDeclarationId, typeTraits})); - - ON_CALL(mock, isBasedOn(Eq(typeId), Eq(typeId))).WillByDefault(Return(true)); - - for (TypeId baseTypeId : baseTypeIds) - ON_CALL(mock, isBasedOn(Eq(typeId), Eq(baseTypeId))).WillByDefault(Return(true)); - - return typeId; -} - -TypeId createObject(ProjectStorageMock &mock, - ModuleId moduleId, - Utils::SmallStringView typeName, - Utils::SmallString defaultPropertyName, - TypeIds baseTypeIds = {}) -{ - return createType( - mock, moduleId, typeName, defaultPropertyName, Storage::TypeTraits::Reference, baseTypeIds); -} - void setupIsBasedOn(ProjectStorageMock &mock) { auto call = [&](TypeId typeId, auto... ids) -> bool { @@ -82,49 +35,208 @@ void setupIsBasedOn(ProjectStorageMock &mock) } } // namespace -} // namespace QmlDesigner + +ModuleId ProjectStorageMock::createModule(Utils::SmallStringView moduleName) +{ + static ModuleId moduleId; + incrementBasicId(moduleId); + + ON_CALL(*this, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId)); + + return moduleId; +} + +PropertyDeclarationId ProjectStorageMock::createProperty(TypeId typeId, + Utils::SmallString name, + PropertyDeclarationTraits traits, + TypeId propertyTypeId) +{ + static PropertyDeclarationId propertyId; + incrementBasicId(propertyId); + + ON_CALL(*this, propertyDeclarationId(Eq(typeId), Eq(name))).WillByDefault(Return(propertyId)); + ON_CALL(*this, propertyName(Eq(propertyId))).WillByDefault(Return(name)); + + ON_CALL(*this, propertyDeclaration(Eq(propertyId))) + .WillByDefault(Return( + QmlDesigner::Storage::Info::PropertyDeclaration{typeId, name, traits, propertyTypeId})); + + auto ids = localPropertyDeclarationIds(typeId); + ids.push_back(propertyId); + ON_CALL(*this, propertyDeclarationIds(Eq(typeId))).WillByDefault(Return(ids)); + ON_CALL(*this, localPropertyDeclarationIds(Eq(typeId))).WillByDefault(Return(ids)); + + return propertyId; +} + +QmlDesigner::PropertyDeclarationId ProjectStorageMock::createProperty( + QmlDesigner::TypeId typeId, Utils::SmallString name, QmlDesigner::TypeId propertyTypeId) +{ + return createProperty(typeId, name, {}, propertyTypeId); +} + +void ProjectStorageMock::createSignal(QmlDesigner::TypeId typeId, Utils::SmallString name) +{ + auto signalNames = signalDeclarationNames(typeId); + signalNames.push_back(name); + ON_CALL(*this, signalDeclarationNames(Eq(typeId))).WillByDefault(Return(signalNames)); +} + +void ProjectStorageMock::createFunction(QmlDesigner::TypeId typeId, Utils::SmallString name) +{ + auto functionNames = functionDeclarationNames(typeId); + functionNames.push_back(name); + ON_CALL(*this, functionDeclarationNames(Eq(typeId))).WillByDefault(Return(functionNames)); +} + +TypeId ProjectStorageMock::createType(ModuleId moduleId, + Utils::SmallStringView typeName, + Utils::SmallStringView defaultPropertyName, + PropertyDeclarationTraits defaultPropertyTraits, + TypeId defaultPropertyTypeId, + Storage::TypeTraits typeTraits, + TypeIds baseTypeIds) +{ + static TypeId typeId; + incrementBasicId(typeId); + + ON_CALL(*this, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId)); + PropertyDeclarationId defaultPropertyDeclarationId; + if (defaultPropertyName.size()) { + if (!defaultPropertyTypeId) { + defaultPropertyTypeId = typeId; + } + + defaultPropertyDeclarationId = createProperty(typeId, + defaultPropertyName, + defaultPropertyTraits, + defaultPropertyTypeId); + } + + ON_CALL(*this, type(Eq(typeId))) + .WillByDefault(Return(Storage::Info::Type{defaultPropertyDeclarationId, typeTraits})); + + ON_CALL(*this, isBasedOn(Eq(typeId), Eq(typeId))).WillByDefault(Return(true)); + + for (TypeId baseTypeId : baseTypeIds) + ON_CALL(*this, isBasedOn(Eq(typeId), Eq(baseTypeId))).WillByDefault(Return(true)); + + return typeId; +} + +QmlDesigner::TypeId ProjectStorageMock::createType(QmlDesigner::ModuleId moduleId, + Utils::SmallStringView typeName, + QmlDesigner::Storage::TypeTraits typeTraits, + QmlDesigner::TypeIds baseTypeIds) +{ + return createType(moduleId, typeName, {}, {}, TypeId{}, typeTraits, baseTypeIds); +} + +TypeId ProjectStorageMock::createObject(ModuleId moduleId, + Utils::SmallStringView typeName, + Utils::SmallStringView defaultPropertyName, + PropertyDeclarationTraits defaultPropertyTraits, + QmlDesigner::TypeId defaultPropertyTypeId, + TypeIds baseTypeIds) +{ + return createType(moduleId, + typeName, + defaultPropertyName, + defaultPropertyTraits, + defaultPropertyTypeId, + Storage::TypeTraits::Reference, + baseTypeIds); +} + +TypeId ProjectStorageMock::createObject(ModuleId moduleId, + Utils::SmallStringView typeName, + TypeIds baseTypeIds) +{ + return createType(moduleId, typeName, Storage::TypeTraits::Reference, baseTypeIds); +} void ProjectStorageMock::setupQtQtuick() { - QmlDesigner::setupIsBasedOn(*this); + setupIsBasedOn(*this); - auto qmlModuleId = QmlDesigner::createModule(*this, "QML"); - auto qtQmlModelsModuleId = QmlDesigner::createModule(*this, "QtQml.Models"); - auto qtQuickModuleId = QmlDesigner::createModule(*this, "QtQuick"); - auto qtQuickNativeModuleId = QmlDesigner::createModule(*this, "QtQuick-cppnative"); + auto qmlModuleId = createModule("QML"); + auto qtQmlModelsModuleId = createModule("QtQml.Models"); + auto qtQuickModuleId = createModule("QtQuick"); + auto qtQuickNativeModuleId = createModule("QtQuick-cppnative"); - auto qtObjectId = QmlDesigner::createObject(*this, qmlModuleId, "QtObject", "children"); + auto intId = createType(qmlModuleId, "int", Storage::TypeTraits::Value); - QmlDesigner::createObject(*this, qtQmlModelsModuleId, "ListModel", "children", {qtObjectId}); - QmlDesigner::createObject(*this, qtQmlModelsModuleId, "ListElement", "children", {qtObjectId}); + auto qtObjectId = createObject(qmlModuleId, + "QtObject", + "children", + PropertyDeclarationTraits::IsList, + TypeId{}); - auto itemId = QmlDesigner::createObject(*this, qtQuickModuleId, "Item", "data", {qtObjectId}); - QmlDesigner::createObject(*this, qtQuickModuleId, "ListView", "data", {qtObjectId, itemId}); - QmlDesigner::createObject(*this, qtQuickModuleId, "StateGroup", "states", {qtObjectId}); - QmlDesigner::createObject(*this, qtQuickModuleId, "State", "changes", {qtObjectId}); - QmlDesigner::createObject(*this, qtQuickModuleId, "Transition", "animations", {qtObjectId}); - QmlDesigner::createObject(*this, qtQuickModuleId, "PropertyAnimation", "", {qtObjectId}); - auto stateOperationsId = QmlDesigner::createObject(*this, - qtQuickNativeModuleId, - " QQuickStateOperation", - "", - {qtObjectId}); - QmlDesigner::createObject(*this, - qtQuickModuleId, - "PropertyChanges", - "", - {qtObjectId, stateOperationsId}); + auto listElementId = createObject(qtQmlModelsModuleId, "ListElement", {qtObjectId}); + createObject(qtQmlModelsModuleId, + "ListModel", + "children", + PropertyDeclarationTraits::IsList, + listElementId, + {qtObjectId}); - auto qtQuickTimelineModuleId = QmlDesigner::createModule(*this, "QtQuick.Timeline"); - QmlDesigner::createObject(*this, qtQuickTimelineModuleId, "KeyframeGroup", "keyframes", {qtObjectId}); - QmlDesigner::createObject(*this, qtQuickTimelineModuleId, "Keyframe", "", {qtObjectId}); + auto itemId = createObject(qtQuickModuleId, + "Item", + "data", + PropertyDeclarationTraits::IsList, + qtObjectId, + {qtObjectId}); + createObject(qtQuickModuleId, + "ListView", + "data", + PropertyDeclarationTraits::IsList, + qtObjectId, + {qtObjectId, itemId}); + createObject(qtQuickModuleId, "StateGroup", {qtObjectId}); + createObject(qtQuickModuleId, + "State", + "changes", + PropertyDeclarationTraits::IsList, + qtObjectId, + {qtObjectId}); + auto animationId = createObject(qtQuickModuleId, "Animation", {qtObjectId}); + createObject(qtQuickModuleId, + "Transition", + "animations", + PropertyDeclarationTraits::IsList, + animationId, + {qtObjectId}); + createObject(qtQuickModuleId, "PropertyAnimation", {qtObjectId}); + auto stateOperationsId = createObject(qtQuickNativeModuleId, + " QQuickStateOperation", + {qtObjectId}); + createObject(qtQuickModuleId, "PropertyChanges", {qtObjectId, stateOperationsId}); - auto flowViewModuleId = QmlDesigner::createModule(*this, "FlowView"); - QmlDesigner::createObject(*this, flowViewModuleId, "FlowActionArea", "data", {qtObjectId, itemId}); - QmlDesigner::createObject(*this, flowViewModuleId, "FlowWildcard", "data", {qtObjectId}); - QmlDesigner::createObject(*this, flowViewModuleId, "FlowDecision", "", {qtObjectId}); - QmlDesigner::createObject(*this, flowViewModuleId, "FlowTransition", "", {qtObjectId}); - QmlDesigner::createObject(*this, flowViewModuleId, "FlowItem", "data", {qtObjectId, itemId}); + auto qtQuickTimelineModuleId = createModule("QtQuick.Timeline"); + createObject(qtQuickTimelineModuleId, "KeyframeGroup", {qtObjectId}); + createObject(qtQuickTimelineModuleId, "Keyframe", {qtObjectId}); + + auto flowViewModuleId = createModule("FlowView"); + createObject(flowViewModuleId, + "FlowActionArea", + "data", + PropertyDeclarationTraits::IsList, + qtObjectId, + {qtObjectId, itemId}); + createObject(flowViewModuleId, + "FlowWildcard", + "data", + PropertyDeclarationTraits::IsList, + qtObjectId, + {qtObjectId}); + createObject(flowViewModuleId, "FlowDecision", {qtObjectId}); + createObject(flowViewModuleId, "FlowTransition", {qtObjectId}); + createObject(flowViewModuleId, + "FlowItem", + "data", + PropertyDeclarationTraits::IsList, + qtObjectId, + {qtObjectId, itemId}); } void ProjectStorageMock::setupCommonTypeCache() diff --git a/tests/unit/tests/mocks/projectstoragemock.h b/tests/unit/tests/mocks/projectstoragemock.h index 383e56e4ec1..fc2544979ae 100644 --- a/tests/unit/tests/mocks/projectstoragemock.h +++ b/tests/unit/tests/mocks/projectstoragemock.h @@ -18,6 +18,47 @@ public: void setupQtQtuick(); void setupCommonTypeCache(); + QmlDesigner::ModuleId createModule(Utils::SmallStringView moduleName); + + QmlDesigner::TypeId createType( + QmlDesigner::ModuleId moduleId, + Utils::SmallStringView typeName, + Utils::SmallStringView defaultPropertyName, + QmlDesigner::Storage::PropertyDeclarationTraits defaultPropertyTraits, + QmlDesigner::TypeId defaultPropertyTypeId, + QmlDesigner::Storage::TypeTraits typeTraits, + QmlDesigner::TypeIds baseTypeIds = {}); + + QmlDesigner::TypeId createType(QmlDesigner::ModuleId moduleId, + Utils::SmallStringView typeName, + QmlDesigner::Storage::TypeTraits typeTraits, + QmlDesigner::TypeIds baseTypeIds = {}); + + QmlDesigner::TypeId createObject( + QmlDesigner::ModuleId moduleId, + Utils::SmallStringView typeName, + Utils::SmallStringView defaultPropertyName, + QmlDesigner::Storage::PropertyDeclarationTraits defaultPropertyTraits, + QmlDesigner::TypeId defaultPropertyTypeId, + QmlDesigner::TypeIds baseTypeIds = {}); + + QmlDesigner::TypeId createObject(QmlDesigner::ModuleId moduleId, + Utils::SmallStringView typeName, + QmlDesigner::TypeIds baseTypeIds = {}); + + QmlDesigner::PropertyDeclarationId createProperty( + QmlDesigner::TypeId typeId, + Utils::SmallString name, + QmlDesigner::Storage::PropertyDeclarationTraits traits, + QmlDesigner::TypeId propertyTypeId); + + QmlDesigner::PropertyDeclarationId createProperty(QmlDesigner::TypeId typeId, + Utils::SmallString name, + QmlDesigner::TypeId propertyTypeId); + + void createSignal(QmlDesigner::TypeId typeId, Utils::SmallString name); + void createFunction(QmlDesigner::TypeId typeId, Utils::SmallString name); + MOCK_METHOD(void, synchronize, (QmlDesigner::Storage::Synchronization::SynchronizationPackage package), diff --git a/tests/unit/tests/unittests/CMakeLists.txt b/tests/unit/tests/unittests/CMakeLists.txt index 0cd03124042..a50a0a2a761 100644 --- a/tests/unit/tests/unittests/CMakeLists.txt +++ b/tests/unit/tests/unittests/CMakeLists.txt @@ -61,6 +61,7 @@ endfunction(unittest_copy_data_folder) add_subdirectory(listmodeleditor) add_subdirectory(imagecache) +add_subdirectory(metainfo) add_subdirectory(model) add_subdirectory(sqlite) add_subdirectory(projectstorage) diff --git a/tests/unit/tests/unittests/metainfo/CMakeLists.txt b/tests/unit/tests/unittests/metainfo/CMakeLists.txt new file mode 100644 index 00000000000..7f2728f078b --- /dev/null +++ b/tests/unit/tests/unittests/metainfo/CMakeLists.txt @@ -0,0 +1,5 @@ +# qmldesigner/designercore/model +extend_qtc_test(unittest + SOURCES + nodemetainfo-test.cpp +) diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp new file mode 100644 index 00000000000..b2532938a3e --- /dev/null +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -0,0 +1,415 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "../utils/googletest.h" + +#include "../mocks/projectstoragemock.h" + +#include +#include +#include + +namespace { + +using QmlDesigner::ModelNode; +using QmlDesigner::ModelNodes; + +template +auto PropertyId(const Matcher &matcher) +{ + return Property(&QmlDesigner::PropertyMetaInfo::id, matcher); +} + +class NodeMetaInfo : public testing::Test +{ +protected: + NiceMock projectStorageMock; + QmlDesigner::Model model{projectStorageMock, "QtQuick.Item"}; + ModelNode rootNode = model.rootModelNode(); + ModelNode item = model.createModelNode("QtQuick.Item"); + ModelNode object = model.createModelNode("QML.QtObject"); + QmlDesigner::NodeMetaInfo itemMetaInfo = item.metaInfo(); + QmlDesigner::NodeMetaInfo objectMetaInfo = object.metaInfo(); + QmlDesigner::TypeId intTypeId = projectStorageMock.typeId(projectStorageMock.moduleId("QML"), + "int", + QmlDesigner::Storage::Version{}); +}; + +TEST_F(NodeMetaInfo, is_true_if_meta_info_exists) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + + auto isValid = bool(metaInfo); + + ASSERT_TRUE(isValid); +} + +TEST_F(NodeMetaInfo, is_valid_if_meta_info_exists) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + + auto isValid = metaInfo.isValid(); + + ASSERT_TRUE(isValid); +} + +TEST_F(NodeMetaInfo, is_false_if_meta_info_not_exists) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto isValid = bool(metaInfo); + + ASSERT_FALSE(isValid); +} + +TEST_F(NodeMetaInfo, default_is_false) +{ + auto isValid = bool(QmlDesigner::NodeMetaInfo{}); + + ASSERT_FALSE(isValid); +} + +TEST_F(NodeMetaInfo, is_invalid_if_meta_info_not_exists) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto isValid = metaInfo.isValid(); + + ASSERT_FALSE(isValid); +} + +TEST_F(NodeMetaInfo, default_is_invalid) +{ + auto isValid = QmlDesigner::NodeMetaInfo{}.isValid(); + + ASSERT_FALSE(isValid); +} + +TEST_F(NodeMetaInfo, item_is_based_on_object) +{ + bool isBasedOn = itemMetaInfo.isBasedOn(objectMetaInfo); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(NodeMetaInfo, item_is_based_on_item) +{ + bool isBasedOn = itemMetaInfo.isBasedOn(itemMetaInfo); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(NodeMetaInfo, object_is_no_based_on_item) +{ + bool isBasedOn = objectMetaInfo.isBasedOn(itemMetaInfo); + + ASSERT_FALSE(isBasedOn); +} + +TEST_F(NodeMetaInfo, object_is_not_file_component) +{ + bool isFileComponent = objectMetaInfo.isFileComponent(); + + ASSERT_FALSE(isFileComponent); +} + +TEST_F(NodeMetaInfo, default_is_not_file_component) +{ + bool isFileComponent = QmlDesigner::NodeMetaInfo{}.isFileComponent(); + + ASSERT_FALSE(isFileComponent); +} + +TEST_F(NodeMetaInfo, invalid_is_not_file_component) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + bool isFileComponent = metaInfo.isFileComponent(); + + ASSERT_FALSE(isFileComponent); +} + +TEST_F(NodeMetaInfo, component_is_file_component) +{ + using QmlDesigner::Storage::TypeTraits; + auto moduleId = projectStorageMock.createModule("/path/to/project"); + auto typeId = projectStorageMock.createType(moduleId, + "Foo", + TypeTraits::IsFileComponent | TypeTraits::Reference); + QmlDesigner::NodeMetaInfo metaInfo{typeId, &projectStorageMock}; + + bool isFileComponent = metaInfo.isFileComponent(); + + ASSERT_TRUE(isFileComponent); +} + +TEST_F(NodeMetaInfo, has_property) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + projectStorageMock.createProperty(metaInfo.id(), "x", intTypeId); + + bool hasProperty = metaInfo.hasProperty("x"); + + ASSERT_TRUE(hasProperty); +} + +TEST_F(NodeMetaInfo, has_not_property) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + + bool hasProperty = metaInfo.hasProperty("foo"); + + ASSERT_FALSE(hasProperty); +} + +TEST_F(NodeMetaInfo, default_has_not_property) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + bool hasProperty = metaInfo.hasProperty("x"); + + ASSERT_FALSE(hasProperty); +} + +TEST_F(NodeMetaInfo, invalid_has_not_property) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + bool hasProperty = metaInfo.hasProperty("x"); + + ASSERT_FALSE(hasProperty); +} + +TEST_F(NodeMetaInfo, get_property) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + auto propertyId = projectStorageMock.createProperty(metaInfo.id(), "x", intTypeId); + + auto property = metaInfo.property("x"); + + ASSERT_THAT(property, PropertyId(propertyId)); +} + +TEST_F(NodeMetaInfo, get_invalid_property_if_not_exists) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + + auto property = metaInfo.property("x"); + + ASSERT_THAT(property, PropertyId(IsFalse())); +} + +TEST_F(NodeMetaInfo, get_invalid_property_for_default) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto property = metaInfo.property("x"); + + ASSERT_THAT(property, PropertyId(IsFalse())); +} + +TEST_F(NodeMetaInfo, get_invalid_property_if_meta_info_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto property = metaInfo.property("x"); + + ASSERT_THAT(property, PropertyId(IsFalse())); +} + +TEST_F(NodeMetaInfo, get_properties) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + auto xPropertyId = projectStorageMock.createProperty(metaInfo.id(), "x", intTypeId); + auto yPropertyId = projectStorageMock.createProperty(metaInfo.id(), "y", intTypeId); + + auto properties = metaInfo.properties(); + + ASSERT_THAT(properties, IsSupersetOf({PropertyId(xPropertyId), PropertyId(yPropertyId)})); +} + +TEST_F(NodeMetaInfo, get_no_properties_for_default) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto properties = metaInfo.properties(); + + ASSERT_THAT(properties, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_no_properties_if_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto properties = metaInfo.properties(); + + ASSERT_THAT(properties, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_local_properties) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + auto xPropertyId = projectStorageMock.createProperty(metaInfo.id(), "x", intTypeId); + auto yPropertyId = projectStorageMock.createProperty(metaInfo.id(), "y", intTypeId); + + auto properties = metaInfo.localProperties(); + + ASSERT_THAT(properties, IsSupersetOf({PropertyId(xPropertyId), PropertyId(yPropertyId)})); +} + +TEST_F(NodeMetaInfo, get_no_local_properties_for_default_metainfo) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto properties = metaInfo.localProperties(); + + ASSERT_THAT(properties, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_no_local_properties_if_node_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto properties = metaInfo.localProperties(); + + ASSERT_THAT(properties, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_signal_names) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + projectStorageMock.createSignal(metaInfo.id(), "xChanged"); + projectStorageMock.createSignal(metaInfo.id(), "yChanged"); + + auto signalNames = metaInfo.signalNames(); + + ASSERT_THAT(signalNames, IsSupersetOf({"xChanged", "yChanged"})); +} + +TEST_F(NodeMetaInfo, get_no_signal_names_for_default_metainfo) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto signalNames = metaInfo.signalNames(); + + ASSERT_THAT(signalNames, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_no_signal_names_if_node_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto signalNames = metaInfo.signalNames(); + + ASSERT_THAT(signalNames, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_function_names) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + projectStorageMock.createFunction(metaInfo.id(), "setX"); + projectStorageMock.createFunction(metaInfo.id(), "setY"); + + auto functionNames = metaInfo.slotNames(); + + ASSERT_THAT(functionNames, IsSupersetOf({"setX", "setY"})); +} + +TEST_F(NodeMetaInfo, get_no_function_names_for_default_metainfo) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto functionNames = metaInfo.slotNames(); + + ASSERT_THAT(functionNames, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_no_function_names_if_node_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto functionNames = metaInfo.slotNames(); + + ASSERT_THAT(functionNames, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_default_property) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + auto defaultProperty = metaInfo.property("data"); + + auto property = metaInfo.defaultProperty(); + + ASSERT_THAT(property, defaultProperty); +} + +TEST_F(NodeMetaInfo, get_no_default_property_for_default_metainfo) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto property = metaInfo.defaultProperty(); + + ASSERT_THAT(property, IsFalse()); +} + +TEST_F(NodeMetaInfo, get_no_default_property_if_node_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto property = metaInfo.defaultProperty(); + + ASSERT_THAT(property, IsFalse()); +} + +TEST_F(NodeMetaInfo, get_default_property_name) +{ + auto node = model.createModelNode("QtQuick.Item"); + auto metaInfo = node.metaInfo(); + auto defaultProperty = metaInfo.property("data"); + + auto property = metaInfo.defaultPropertyName(); + + ASSERT_THAT(property, "data"); +} + +TEST_F(NodeMetaInfo, get_no_default_property_name_for_default_metainfo) +{ + auto metaInfo = QmlDesigner::NodeMetaInfo{}; + + auto property = metaInfo.defaultPropertyName(); + + ASSERT_THAT(property, IsEmpty()); +} + +TEST_F(NodeMetaInfo, get_no_default_property_name_if_node_is_invalid) +{ + auto node = model.createModelNode("QtQuick.Foo"); + auto metaInfo = node.metaInfo(); + + auto property = metaInfo.defaultPropertyName(); + + ASSERT_THAT(property, IsEmpty()); +} + +} // namespace diff --git a/tests/unit/tests/unittests/model/CMakeLists.txt b/tests/unit/tests/unittests/model/CMakeLists.txt index 8cd6b911ec7..187ed9f99a0 100644 --- a/tests/unit/tests/unittests/model/CMakeLists.txt +++ b/tests/unit/tests/unittests/model/CMakeLists.txt @@ -3,6 +3,7 @@ extend_qtc_test(unittest SOURCES import-test.cpp model-test.cpp + modelnode-test.cpp nodelistproperty-test.cpp modelresourcemanagement-test.cpp ) diff --git a/tests/unit/tests/unittests/model/modelnode-test.cpp b/tests/unit/tests/unittests/model/modelnode-test.cpp new file mode 100644 index 00000000000..0d9cf1b1842 --- /dev/null +++ b/tests/unit/tests/unittests/model/modelnode-test.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "../utils/googletest.h" + +#include "../mocks/projectstoragemock.h" + +#include +#include +#include + +namespace { + +class ModelNode : public testing::Test +{ +protected: + NiceMock projectStorageMock; + QmlDesigner::Model model{projectStorageMock, "QtQuick.Item"}; + QmlDesigner::ModelNode rootNode = model.rootModelNode(); +}; + +TEST_F(ModelNode, get_meta_info) +{ + auto metaInfo = rootNode.metaInfo(); +} + +} // namespace diff --git a/tests/unit/tests/utils/google-using-declarations.h b/tests/unit/tests/utils/google-using-declarations.h index 105b65714c7..19e8df2ef20 100644 --- a/tests/unit/tests/utils/google-using-declarations.h +++ b/tests/unit/tests/utils/google-using-declarations.h @@ -30,9 +30,11 @@ using testing::Gt; using testing::HasSubstr; using testing::InSequence; using testing::Invoke; +using testing::IsFalse; using testing::IsNull; using testing::IsSubsetOf; using testing::IsSupersetOf; +using testing::IsTrue; using testing::Le; using testing::Lt; using testing::Matcher;