From e376992d0150dcc3a98fdddbc8d0239e97b87ec6 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Fri, 17 May 2024 14:31:44 +0200 Subject: [PATCH] UnitTests: Tests for headless QML theme generator Task-number: QDS-11956 Change-Id: I5b76b62153436aa2ee3811702beca06af611308a Reviewed-by: Marco Bubke Reviewed-by: Thomas Hartmann --- .../tests/printers/gtest-creator-printing.cpp | 26 ++ .../tests/printers/gtest-creator-printing.h | 6 + tests/unit/tests/unittests/CMakeLists.txt | 1 + .../unittests/designsystem/CMakeLists.txt | 8 + .../designsystem/dsthemegroup-test.cpp | 237 ++++++++++++++++ .../designsystem/dsthememgr-test.cpp | 266 ++++++++++++++++++ .../designsystem/dsthemeqml-test.cpp | 255 +++++++++++++++++ 7 files changed, 799 insertions(+) create mode 100644 tests/unit/tests/unittests/designsystem/CMakeLists.txt create mode 100644 tests/unit/tests/unittests/designsystem/dsthemegroup-test.cpp create mode 100644 tests/unit/tests/unittests/designsystem/dsthememgr-test.cpp create mode 100644 tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp diff --git a/tests/unit/tests/printers/gtest-creator-printing.cpp b/tests/unit/tests/printers/gtest-creator-printing.cpp index d7a63fe6900..1e2981ce171 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.cpp +++ b/tests/unit/tests/printers/gtest-creator-printing.cpp @@ -26,6 +26,8 @@ #include +#include + namespace std { template ostream &operator<<(ostream &out, const QVector &vector) { @@ -435,6 +437,30 @@ const char *sourceTypeToText(SourceType sourceType) } // namespace +std::ostream &operator<<(std::ostream &out, const ThemeProperty &prop) +{ + out << "{name: " << prop.name.toStdString() << ", value: " << prop.value + << ", isBinding: " << prop.isBinding << "}"; + + return out; +} + +void PrintTo(const ThemeProperty &prop, std::ostream *os) +{ + *os << prop; +} + +std::ostream &operator<<(std::ostream &out, const GroupType &group) +{ + out << "ThemeGroup{ " << static_cast(group) << ", " << GroupId(group) << "}"; + return out; +} + +void PrintTo(const GroupType &group, std::ostream *os) +{ + *os << group; +} + std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus) { return out << "(" << fileStatus.sourceId << ", " << fileStatus.size << ", " diff --git a/tests/unit/tests/printers/gtest-creator-printing.h b/tests/unit/tests/printers/gtest-creator-printing.h index 23c76832974..1438c889b8c 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.h +++ b/tests/unit/tests/printers/gtest-creator-printing.h @@ -133,11 +133,17 @@ class FileStatus; class Import; class NodeMetaInfo; class PropertyMetaInfo; +class ThemeProperty; +enum class GroupType; struct CompoundPropertyMetaInfo; enum class FlagIs : unsigned int; template class BasicAuxiliaryDataKey; +void PrintTo(const ThemeProperty &prop, std::ostream *os); +std::ostream &operator<<(std::ostream &out, const ThemeProperty &prop); +void PrintTo(const GroupType &group, std::ostream *os); +std::ostream &operator<<(std::ostream &out, const GroupType &group); std::ostream &operator<<(std::ostream &out, const ModelNode &node); std::ostream &operator<<(std::ostream &out, const VariantProperty &property); std::ostream &operator<<(std::ostream &out, const AbstractProperty &property); diff --git a/tests/unit/tests/unittests/CMakeLists.txt b/tests/unit/tests/unittests/CMakeLists.txt index 1aabede38f2..78cd94c2d9a 100644 --- a/tests/unit/tests/unittests/CMakeLists.txt +++ b/tests/unit/tests/unittests/CMakeLists.txt @@ -46,6 +46,7 @@ endfunction(unittest_copy_data_folder) add_subdirectory(componentcore) add_subdirectory(designercoreutils) +add_subdirectory(designsystem) add_subdirectory(listmodeleditor) add_subdirectory(imagecache) add_subdirectory(metainfo) diff --git a/tests/unit/tests/unittests/designsystem/CMakeLists.txt b/tests/unit/tests/unittests/designsystem/CMakeLists.txt new file mode 100644 index 00000000000..113381a5554 --- /dev/null +++ b/tests/unit/tests/unittests/designsystem/CMakeLists.txt @@ -0,0 +1,8 @@ +extend_qtc_test(unittest + DEPENDS + QmlDesignerUtils DesignSystem + SOURCES + dsthemegroup-test.cpp + dsthememgr-test.cpp + dsthemeqml-test.cpp +) diff --git a/tests/unit/tests/unittests/designsystem/dsthemegroup-test.cpp b/tests/unit/tests/unittests/designsystem/dsthemegroup-test.cpp new file mode 100644 index 00000000000..bf4c0f14788 --- /dev/null +++ b/tests/unit/tests/unittests/designsystem/dsthemegroup-test.cpp @@ -0,0 +1,237 @@ +// Copyright (C) 2024 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 + +#include +#include + +using QmlDesigner::DSThemeGroup; +using QmlDesigner::ThemeProperty; + +namespace { +constexpr const char testPropertyNameFoo[] = "propFoo"; +constexpr const char testPropertyNameBar[] = "propBar"; + +constexpr QmlDesigner::ThemeId themeId1 = 0; +constexpr QmlDesigner::ThemeId themeId2 = 1; + +MATCHER_P3(HasPropertyCount, themeId, themePropCount, totalPropsCount, "") +{ + const DSThemeGroup &group = arg; + return group.count() == totalPropsCount && group.count(themeId) == themePropCount; +} + +MATCHER_P2(HasThemeProperty, themeId, themeProp, "") +{ + const DSThemeGroup &group = arg; + const std::optional prop = group.propertyValue(themeId, themeProp.name); + + return prop && themeProp.name == prop->name && themeProp.value == prop->value + && themeProp.isBinding == prop->isBinding; +} + +class DesignGroupTest : public testing::TestWithParam +{ +protected: + DesignGroupTest() + : group(groupType) + { + } + + QmlDesigner::GroupType groupType = GetParam(); + QmlDesigner::DSThemeGroup group; +}; + +INSTANTIATE_TEST_SUITE_P(DesignSystem, + DesignGroupTest, + testing::Values(QmlDesigner::GroupType::Colors, + QmlDesigner::GroupType::Flags, + QmlDesigner::GroupType::Numbers, + QmlDesigner::GroupType::Strings)); + +TEST_P(DesignGroupTest, add_property) +{ + // arrange + ThemeProperty testProp{testPropertyNameFoo, "test", false}; + + // act + group.addProperty(themeId1, testProp); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 1u, 1u), HasThemeProperty(themeId1, testProp))); +} + +TEST_P(DesignGroupTest, add_multiple_properties) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + ThemeProperty testPropBar{testPropertyNameBar, "#bbddee", false}; + + // act + group.addProperty(themeId1, testPropFoo); + group.addProperty(themeId1, testPropBar); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 2u, 2u), + HasThemeProperty(themeId1, testPropFoo), + HasThemeProperty(themeId1, testPropBar))); +} + +TEST_P(DesignGroupTest, add_property_with_empty_property_name) +{ + // arrange + ThemeProperty testProp{"", "test", false}; + + // act + group.addProperty(themeId1, testProp); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 0u, 0u), Not(HasThemeProperty(themeId1, testProp)))); +} + +TEST_P(DesignGroupTest, add_binding_property) +{ + // arrange + ThemeProperty testProp{testPropertyNameFoo, "root.width", true}; + + // act + group.addProperty(themeId1, testProp); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 1u, 1u), HasThemeProperty(themeId1, testProp))); +} + +TEST_P(DesignGroupTest, add_property_with_duplicate_name) +{ + // arrange + ThemeProperty testPropA{testPropertyNameFoo, "#aaccff", false}; + ThemeProperty testPropB{testPropertyNameFoo, "#bbddee", false}; + group.addProperty(themeId1, testPropA); + + // act + group.addProperty(themeId1, testPropB); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 1u, 1u), + HasThemeProperty(themeId1, testPropA), + Not(HasThemeProperty(themeId1, testPropB)))); +} + +TEST_P(DesignGroupTest, remove_property) +{ + // arrange + ThemeProperty testProp{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testProp); + + // act + group.removeProperty(testPropertyNameFoo); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 0u, 0u), Not(HasThemeProperty(themeId1, testProp)))); +} + +TEST_P(DesignGroupTest, remove_nonexistent_property_have_no_side_effect) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testPropFoo); + + // act + group.removeProperty(testPropertyNameBar); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 1u, 1u), HasThemeProperty(themeId1, testPropFoo))); +} + +TEST_P(DesignGroupTest, remove_theme_with_multiple_properties) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testPropFoo); + ThemeProperty testPropBar{testPropertyNameBar, "#bbddee", false}; + group.addProperty(themeId1, testPropBar); + + // act + group.removeTheme(themeId1); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 0u, 0u), + Not(HasThemeProperty(themeId1, testPropFoo)), + Not(HasThemeProperty(themeId1, testPropBar)))); +} + +TEST_P(DesignGroupTest, remove_theme_from_group_having_multiple_themes) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testPropFoo); + ThemeProperty testPropBar{testPropertyNameBar, "#bbddee", false}; + group.addProperty(themeId2, testPropBar); + + // act + group.removeTheme(themeId1); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 0u, 1u), + Not(HasThemeProperty(themeId1, testPropFoo)), + HasThemeProperty(themeId2, testPropBar))); +} + +TEST_P(DesignGroupTest, remove_nonexistent_theme_have_no_side_effect) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testPropFoo); + + // act + group.removeTheme(themeId2); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 1u, 1u), HasThemeProperty(themeId1, testPropFoo))); +} + +TEST_P(DesignGroupTest, duplicate_theme) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testPropFoo); + ThemeProperty testPropBar{testPropertyNameBar, "#bbddee", false}; + group.addProperty(themeId1, testPropBar); + + // act + group.duplicateValues(themeId1, themeId2); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId2, 2u, 2u), + HasThemeProperty(themeId2, testPropFoo), + HasThemeProperty(themeId2, testPropBar))); +} + +TEST_P(DesignGroupTest, duplicate_nonexistent_have_no_side_effect) +{ + // arrange + ThemeProperty testPropFoo{testPropertyNameFoo, "#aaccff", false}; + group.addProperty(themeId1, testPropFoo); + + // act + group.duplicateValues(themeId2, themeId1); + + //assert + ASSERT_THAT(group, + AllOf(HasPropertyCount(themeId1, 1u, 1u), HasThemeProperty(themeId1, testPropFoo))); +} +} // namespace diff --git a/tests/unit/tests/unittests/designsystem/dsthememgr-test.cpp b/tests/unit/tests/unittests/designsystem/dsthememgr-test.cpp new file mode 100644 index 00000000000..02a2e56cabc --- /dev/null +++ b/tests/unit/tests/unittests/designsystem/dsthememgr-test.cpp @@ -0,0 +1,266 @@ +// Copyright (C) 2024 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 +#include +#include +#include +#include + +#include + +#include + +using QmlDesigner::DSThemeManager; +using QmlDesigner::GroupType; +using QmlDesigner::Import; +using QmlDesigner::ModelNode; +using QmlDesigner::ThemeProperty; + +namespace { +constexpr const char testPropNameFoo[] = "propFoo"; +constexpr const char testPropNameBar[] = "propBar"; + +constexpr const char darkThemeName[] = "dark"; +constexpr const char lightThemeName[] = "light"; + +MATCHER_P3(HasProperty, + themeId, + group, + themeProp, + std::format("Collection {} have a property {}", + (negation ? "Does't " : "Does "), + PrintToString(themeProp))) +{ + const DSThemeManager &mgr = arg; + const std::optional prop = mgr.property(themeId, group, themeProp.name); + + return prop && themeProp.name == prop->name && themeProp.value == prop->value + && themeProp.isBinding == prop->isBinding; +} + +class DesignSystemManagerTest : public testing::TestWithParam +{ +protected: + QmlDesigner::GroupType groupType = GetParam(); + DSThemeManager mgr; +}; + +INSTANTIATE_TEST_SUITE_P(DesignSystem, + DesignSystemManagerTest, + testing::Values(QmlDesigner::GroupType::Colors, + QmlDesigner::GroupType::Flags, + QmlDesigner::GroupType::Numbers, + QmlDesigner::GroupType::Strings)); + +TEST(DesignSystemManagerTest, add_theme) +{ + // arrange + DSThemeManager mgr; + + // act + const auto themeId = mgr.addTheme(darkThemeName); + + // assert + ASSERT_THAT(themeId, Optional(A())); +} + +TEST(DesignSystemManagerTest, add_theme_with_empty_name_fails) +{ + // arrange + DSThemeManager mgr; + + // act + const auto themeId = mgr.addTheme(""); + + // assert + ASSERT_THAT(themeId, Eq(std::nullopt)); +} + +TEST(DesignSystemManagerTest, add_theme_generates_valid_theme_id) +{ + // arrange + DSThemeManager mgr; + + // act + const auto themeId = mgr.addTheme(darkThemeName); + + // assert + ASSERT_THAT(mgr.themeId(darkThemeName), Optional(themeId)); +} + +TEST(DesignSystemManagerTest, remove_theme) +{ + // arrange + DSThemeManager mgr; + const auto themeId = mgr.addTheme(darkThemeName); + + // act + mgr.removeTheme(*themeId); + + // assert + ASSERT_THAT(mgr, Property(&DSThemeManager::themeCount, 0)); +} + +TEST(DesignSystemManagerTest, remove_theme_with_properties) +{ + // arrange + DSThemeManager mgr; + const auto themeId = mgr.addTheme(darkThemeName); + ThemeProperty testProp{testPropNameFoo, "#aaccbb", false}; + mgr.addProperty(GroupType::Colors, testProp); + + // act + mgr.removeTheme(*themeId); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 0), + Not(HasProperty(*themeId, GroupType::Colors, testProp)))); +} + +TEST_P(DesignSystemManagerTest, add_property_without_theme) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + + // act + mgr.addProperty(groupType, testProp); + + //assert + ASSERT_THAT(mgr, Property(&DSThemeManager::themeCount, 0)); +} + +TEST_P(DesignSystemManagerTest, add_property) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + const auto themeId = mgr.addTheme(darkThemeName); + + // act + mgr.addProperty(groupType, testProp); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + HasProperty(*themeId, groupType, testProp))); +} + +TEST_P(DesignSystemManagerTest, adding_invalid_property_fails) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, {}, false}; + const auto themeId = mgr.addTheme(darkThemeName); + + // act + const bool result = mgr.addProperty(groupType, testProp); + + // assert + ASSERT_FALSE(result); + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + Not(HasProperty(*themeId, groupType, testProp)))); +} + +TEST_P(DesignSystemManagerTest, adding_property_adds_property_to_all_themes) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + const auto themeIdDark = mgr.addTheme(darkThemeName); + const auto themeIdLight = mgr.addTheme(lightThemeName); + + // act + mgr.addProperty(groupType, testProp); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 2), + HasProperty(*themeIdDark, groupType, testProp), + HasProperty(*themeIdLight, groupType, testProp))); +} + +TEST_P(DesignSystemManagerTest, update_property_value) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + ThemeProperty testPropUpdated{testPropNameFoo, "foo", false}; + const auto themeId = mgr.addTheme(darkThemeName); + mgr.addProperty(groupType, testProp); + + // act + mgr.updateProperty(*themeId, groupType, testPropUpdated); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + HasProperty(*themeId, groupType, testPropUpdated))); +} + +TEST_P(DesignSystemManagerTest, update_property_name) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + ThemeProperty testPropUpdated{testPropNameBar, "test", false}; + const auto themeId = mgr.addTheme(darkThemeName); + mgr.addProperty(groupType, testProp); + + // act + mgr.updateProperty(*themeId, groupType, testProp, testPropUpdated.name); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + HasProperty(*themeId, groupType, testPropUpdated))); +} + +TEST_P(DesignSystemManagerTest, updating_invalid_property_fails) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + ThemeProperty testPropUpdated{testPropNameFoo, {}, false}; + const auto themeId = mgr.addTheme(darkThemeName); + mgr.addProperty(groupType, testProp); + + // act + mgr.updateProperty(*themeId, groupType, testProp, testPropUpdated.name); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + HasProperty(*themeId, groupType, testProp))); +} + +TEST_P(DesignSystemManagerTest, remove_property) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + const auto themeId = mgr.addTheme(darkThemeName); + mgr.addProperty(groupType, testProp); + + // act + mgr.removeProperty(groupType, testPropNameFoo); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + Not(HasProperty(*themeId, groupType, testProp)))); +} + +TEST_P(DesignSystemManagerTest, remove_absent_property_fails) +{ + // arrange + ThemeProperty testProp{testPropNameFoo, "test", false}; + const auto themeId = mgr.addTheme(darkThemeName); + mgr.addProperty(groupType, testProp); + + // act + mgr.removeProperty(groupType, testPropNameBar); + + // assert + ASSERT_THAT(mgr, + AllOf(Property(&DSThemeManager::themeCount, 1), + HasProperty(*themeId, groupType, testProp))); +} +} // namespace diff --git a/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp b/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp new file mode 100644 index 00000000000..602a1b356d8 --- /dev/null +++ b/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp @@ -0,0 +1,255 @@ +// Copyright (C) 2024 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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using QmlDesigner::DSThemeManager; +using QmlDesigner::GroupType; +using QmlDesigner::Import; +using QmlDesigner::ModelNode; +using QmlDesigner::ThemeProperty; + +template<> +struct std::formatter : std::formatter +{ + template + auto format(const QByteArray &ba, FormatContext &ctx) const + { + return std::formatter::format(ba.toStdString(), ctx); + } +}; + +namespace { + +static std::string formatedPropStr(const char tag[], const char name[], const QVariant &v) +{ + return std::format("{}Property({}, {})", tag, name, v.toString().toStdString()); +} + +static auto bindingPropStr = std::bind(&formatedPropStr, + "Binding", + std::placeholders::_1, + std::placeholders::_2); +static auto variantPropStr = std::bind(&formatedPropStr, + "Variant", + std::placeholders::_1, + std::placeholders::_2); + +constexpr const char testPropertyName1[] = "prop1"; +constexpr const char darkThemeName[] = "dark"; +constexpr QmlDesigner::ThemeId testThemeId = 1; + +MATCHER_P2(HasNodeProperty, + name, + typeName, + std::format("{} have node {} with type {})", (negation ? "Does't " : "Does "), name, typeName)) +{ + ModelNode n = arg; + return n.hasNodeProperty(name) && n.nodeProperty(name).modelNode().isValid() + && n.nodeProperty(name).modelNode().type() == typeName; +} + +MATCHER_P2(HasBindingProperty, + name, + value, + std::format("{} have {})", (negation ? "Does't " : "Does "), bindingPropStr(name, value))) +{ + ModelNode n = arg; + return n.hasBindingProperty(name) && n.bindingProperty(name).expression() == value; +} + +MATCHER_P2(HasVariantProperty, + name, + value, + std::format("{} have {})", (negation ? "Does't " : "Does "), variantPropStr(name, value))) +{ + ModelNode n = arg; + return n.hasVariantProperty(name) && n.variantProperty(name).value() == value; +} + +MATCHER_P2(HasGroupVariantProperty, + groupName, + themeProp, + std::format("{} have node {} with {})", + (negation ? "Does't " : "Does "), + groupName.constData(), + PrintToString(themeProp))) +{ + ModelNode n = arg; + + ModelNode groupNode = n.nodeProperty(groupName).modelNode(); + + return groupNode.isValid() && groupNode.hasVariantProperty(themeProp.name) + && groupNode.variantProperty(themeProp.name).value() == themeProp.value; +} + +MATCHER_P2(HasGroupBindingProperty, + groupName, + themeProp, + std::format("{} have node {} with {})", + (negation ? "Does't " : "Does "), + groupName.constData(), + PrintToString(themeProp))) +{ + ModelNode n = arg; + + ModelNode groupNode = n.nodeProperty(groupName).modelNode(); + + return groupNode.isValid() && groupNode.hasBindingProperty(themeProp.name) + && groupNode.bindingProperty(themeProp.name).expression() == themeProp.value.toString(); +} + +class DesignSystemQmlTest : public testing::TestWithParam +{ +protected: + DesignSystemQmlTest() + : group(groupType) + {} + + const QmlDesigner::GroupType groupType = GetParam(); + const QmlDesigner::PropertyName groupName = GroupId(groupType); + QmlDesigner::DSThemeGroup group; + NiceMock pathCacheMock{"/path/model.qm"}; + NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + "QtObject", + {Import::createLibraryImport("QM"), + Import::createLibraryImport("QtQuick")}, + QUrl::fromLocalFile(pathCacheMock.path.toQString())}; +}; + +INSTANTIATE_TEST_SUITE_P(DesignSystem, + DesignSystemQmlTest, + testing::Values(QmlDesigner::GroupType::Colors, + QmlDesigner::GroupType::Flags, + QmlDesigner::GroupType::Numbers, + QmlDesigner::GroupType::Strings)); + +TEST_P(DesignSystemQmlTest, group_aliase_properties_are_generated) +{ + // arrange + ThemeProperty testProp{testPropertyName1, "test", false}; + DSThemeManager mgr; + mgr.addTheme(darkThemeName); + mgr.addProperty(groupType, testProp); + ModelNode rootNode = model.rootModelNode(); + QString binding = QString("currentTheme.%1").arg(QString::fromLatin1(groupName)); + + // act + mgr.decorate(rootNode); + + // assert + ASSERT_THAT(rootNode, + AllOf(Property(&ModelNode::type, Eq("QtObject")), + HasBindingProperty(groupName, binding), + HasBindingProperty("currentTheme", darkThemeName), + HasNodeProperty(darkThemeName, "QtObject"))); +} + +TEST_P(DesignSystemQmlTest, empty_groups_generate_no_group_aliase_properties) +{ + // arrange + DSThemeManager mgr; + ModelNode rootNode = model.rootModelNode(); + QString binding = QString("currentTheme.%1").arg(QString::fromLatin1(groupName)); + + // act + mgr.decorate(rootNode); + + // assert + ASSERT_THAT(rootNode, + AllOf(Property(&ModelNode::type, Eq("QtObject")), + Not(HasBindingProperty(groupName, binding)), + Not(HasBindingProperty("currentTheme", darkThemeName)), + Not(HasNodeProperty(darkThemeName, "QtObject")))); +} + +TEST_P(DesignSystemQmlTest, decorate_appends_binding_property_to_group_node) +{ + // arrange + ThemeProperty testProp{testPropertyName1, "width", true}; + group.addProperty(testThemeId, testProp); + ModelNode rootNode = model.rootModelNode(); + + // act + group.decorate(testThemeId, rootNode); + + // assert + ASSERT_THAT(rootNode, + AllOf(HasNodeProperty(groupName, "QtObject"), + HasGroupBindingProperty(groupName, testProp))); +} + +TEST_P(DesignSystemQmlTest, mcu_flag_decorate_appends_binding_property_to_root_node) +{ + // arrange + ThemeProperty testProp{testPropertyName1, "width", true}; + group.addProperty(testThemeId, testProp); + ModelNode rootNode = model.rootModelNode(); + + // act + group.decorate(testThemeId, rootNode, false); + + // assert + ASSERT_THAT(rootNode, + AllOf(Not(HasNodeProperty(groupName, "QtObject")), + HasBindingProperty(testProp.name, testProp.value))); +} + +TEST_P(DesignSystemQmlTest, decorate_appends_variant_property_to_group_node) +{ + // arrange + ThemeProperty testProp{testPropertyName1, 5, false}; + group.addProperty(testThemeId, testProp); + ModelNode rootNode = model.rootModelNode(); + + // act + group.decorate(testThemeId, rootNode); + + // assert + ASSERT_THAT(rootNode, + AllOf(HasNodeProperty(groupName, "QtObject"), + HasGroupVariantProperty(groupName, testProp))); +} + +TEST_P(DesignSystemQmlTest, mcu_flag_decorate_appends_variant_property_to_root_node) +{ + // arrange + ThemeProperty testProp{testPropertyName1, 5, false}; + group.addProperty(testThemeId, testProp); + ModelNode rootNode = model.rootModelNode(); + + // act + group.decorate(testThemeId, rootNode, false); + + // assert + ASSERT_THAT(rootNode, + AllOf(Not(HasNodeProperty(groupName, "QtObject")), + HasVariantProperty(testProp.name, testProp.value))); +} + +TEST_P(DesignSystemQmlTest, empty_group_decorate_adds_no_property) +{ + // arrange + ModelNode rootNode = model.rootModelNode(); + + // act + group.decorate(testThemeId, rootNode); + + // assert + ASSERT_THAT(rootNode, Not(HasNodeProperty(groupName, "QtObject"))); +} +} // namespace