forked from qt-creator/qt-creator
UnitTests: Tests for headless QML theme generator
Task-number: QDS-11956 Change-Id: I5b76b62153436aa2ee3811702beca06af611308a Reviewed-by: Marco Bubke <marco.bubke@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include <utils/smallstringio.h>
|
#include <utils/smallstringio.h>
|
||||||
|
|
||||||
|
#include <designsystem/dsconstants.h>
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template <typename T> ostream &operator<<(ostream &out, const QVector<T> &vector)
|
template <typename T> ostream &operator<<(ostream &out, const QVector<T> &vector)
|
||||||
{
|
{
|
||||||
@@ -435,6 +437,30 @@ const char *sourceTypeToText(SourceType sourceType)
|
|||||||
|
|
||||||
} // namespace
|
} // 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<int>(group) << ", " << GroupId(group) << "}";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTo(const GroupType &group, std::ostream *os)
|
||||||
|
{
|
||||||
|
*os << group;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus)
|
std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus)
|
||||||
{
|
{
|
||||||
return out << "(" << fileStatus.sourceId << ", " << fileStatus.size << ", "
|
return out << "(" << fileStatus.sourceId << ", " << fileStatus.size << ", "
|
||||||
|
@@ -133,11 +133,17 @@ class FileStatus;
|
|||||||
class Import;
|
class Import;
|
||||||
class NodeMetaInfo;
|
class NodeMetaInfo;
|
||||||
class PropertyMetaInfo;
|
class PropertyMetaInfo;
|
||||||
|
class ThemeProperty;
|
||||||
|
enum class GroupType;
|
||||||
struct CompoundPropertyMetaInfo;
|
struct CompoundPropertyMetaInfo;
|
||||||
enum class FlagIs : unsigned int;
|
enum class FlagIs : unsigned int;
|
||||||
template<typename NameType>
|
template<typename NameType>
|
||||||
class BasicAuxiliaryDataKey;
|
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 ModelNode &node);
|
||||||
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
|
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
|
||||||
std::ostream &operator<<(std::ostream &out, const AbstractProperty &property);
|
std::ostream &operator<<(std::ostream &out, const AbstractProperty &property);
|
||||||
|
@@ -46,6 +46,7 @@ endfunction(unittest_copy_data_folder)
|
|||||||
|
|
||||||
add_subdirectory(componentcore)
|
add_subdirectory(componentcore)
|
||||||
add_subdirectory(designercoreutils)
|
add_subdirectory(designercoreutils)
|
||||||
|
add_subdirectory(designsystem)
|
||||||
add_subdirectory(listmodeleditor)
|
add_subdirectory(listmodeleditor)
|
||||||
add_subdirectory(imagecache)
|
add_subdirectory(imagecache)
|
||||||
add_subdirectory(metainfo)
|
add_subdirectory(metainfo)
|
||||||
|
8
tests/unit/tests/unittests/designsystem/CMakeLists.txt
Normal file
8
tests/unit/tests/unittests/designsystem/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
extend_qtc_test(unittest
|
||||||
|
DEPENDS
|
||||||
|
QmlDesignerUtils DesignSystem
|
||||||
|
SOURCES
|
||||||
|
dsthemegroup-test.cpp
|
||||||
|
dsthememgr-test.cpp
|
||||||
|
dsthemeqml-test.cpp
|
||||||
|
)
|
237
tests/unit/tests/unittests/designsystem/dsthemegroup-test.cpp
Normal file
237
tests/unit/tests/unittests/designsystem/dsthemegroup-test.cpp
Normal file
@@ -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 <gtest-creator-printing.h>
|
||||||
|
|
||||||
|
#include <designsystem/dsconstants.h>
|
||||||
|
#include <designsystem/dsthemegroup.h>
|
||||||
|
|
||||||
|
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<ThemeProperty> 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<QmlDesigner::GroupType>
|
||||||
|
{
|
||||||
|
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
|
266
tests/unit/tests/unittests/designsystem/dsthememgr-test.cpp
Normal file
266
tests/unit/tests/unittests/designsystem/dsthememgr-test.cpp
Normal file
@@ -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 <bindingproperty.h>
|
||||||
|
#include <model.h>
|
||||||
|
#include <nodeproperty.h>
|
||||||
|
#include <projectstoragemock.h>
|
||||||
|
#include <sourcepathcachemock.h>
|
||||||
|
|
||||||
|
#include <designsystem/dsthememanager.h>
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
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<ThemeProperty> 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<QmlDesigner::GroupType>
|
||||||
|
{
|
||||||
|
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<QmlDesigner::ThemeId>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
255
tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp
Normal file
255
tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp
Normal file
@@ -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 <bindingproperty.h>
|
||||||
|
#include <model.h>
|
||||||
|
#include <nodeproperty.h>
|
||||||
|
#include <projectstoragemock.h>
|
||||||
|
#include <sourcepathcachemock.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
|
||||||
|
#include <designsystem/dsthemegroup.h>
|
||||||
|
#include <designsystem/dsthememanager.h>
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using QmlDesigner::DSThemeManager;
|
||||||
|
using QmlDesigner::GroupType;
|
||||||
|
using QmlDesigner::Import;
|
||||||
|
using QmlDesigner::ModelNode;
|
||||||
|
using QmlDesigner::ThemeProperty;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::formatter<QByteArray> : std::formatter<std::string>
|
||||||
|
{
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(const QByteArray &ba, FormatContext &ctx) const
|
||||||
|
{
|
||||||
|
return std::formatter<std::string>::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<QmlDesigner::GroupType>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
DesignSystemQmlTest()
|
||||||
|
: group(groupType)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const QmlDesigner::GroupType groupType = GetParam();
|
||||||
|
const QmlDesigner::PropertyName groupName = GroupId(groupType);
|
||||||
|
QmlDesigner::DSThemeGroup group;
|
||||||
|
NiceMock<SourcePathCacheMockWithPaths> pathCacheMock{"/path/model.qm"};
|
||||||
|
NiceMock<ProjectStorageMockWithQtQuick> 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
|
Reference in New Issue
Block a user