You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
778 lines
38 KiB
C++
778 lines
38 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <AzFramework/Components/TransformComponent.h>
|
|
#include <AzFramework/Entity/EntityContext.h>
|
|
#include <AzFramework/Asset/SimpleAsset.h>
|
|
#include <AzTest/AzTest.h>
|
|
#include <AzToolsFramework/Application/ToolsApplication.h>
|
|
#include <AzCore/UnitTest/TestTypes.h>
|
|
#include <AzCore/StringFunc/StringFunc.h>
|
|
|
|
#include <AzToolsFramework/PropertyTreeEditor/PropertyTreeEditor.h>
|
|
|
|
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
|
#include <AzToolsFramework/UnitTest/ToolsTestApplication.h>
|
|
|
|
#include <QtTest/QtTest>
|
|
#include <QApplication>
|
|
|
|
namespace UnitTest
|
|
{
|
|
using namespace AzToolsFramework;
|
|
|
|
struct PropertyTreeEditorSubBlockTester
|
|
{
|
|
AZ_TYPE_INFO(PropertyTreeEditorTester, "{E9497A1E-9B41-4A33-8F05-92CE41A0ABD9}");
|
|
AZ::s16 m_myNegativeShort = -42;
|
|
};
|
|
|
|
struct MockAssetData
|
|
: public AZ::Data::AssetData
|
|
{
|
|
AZ_RTTI(MyTestAssetData, "{8B0A8DCA-7F29-4B8E-B5D7-08E0EAB2C900}", AZ::Data::AssetData);
|
|
|
|
MockAssetData(const AZ::Data::AssetId& assetId)
|
|
: AssetData(assetId)
|
|
{
|
|
// to skip the automatic removal from the asset system
|
|
m_useCount = 2;
|
|
}
|
|
};
|
|
|
|
class TestSimpleAsset
|
|
{
|
|
public:
|
|
AZ_TYPE_INFO(TestSimpleAsset, "{10A39072-9287-49FE-93C8-55F7715FC758}");
|
|
|
|
bool m_data = false;
|
|
|
|
static const char* GetFileFilter()
|
|
{
|
|
return "*.NaN";
|
|
}
|
|
|
|
static void Reflect(AZ::ReflectContext* reflection)
|
|
{
|
|
AZ::SerializeContext* serializeContext = AZ::RttiCast<AZ::SerializeContext*>(reflection);
|
|
if (serializeContext)
|
|
{
|
|
serializeContext->Class<TestSimpleAsset>()
|
|
->Version(0)
|
|
->Field("data", &TestSimpleAsset::m_data)
|
|
;
|
|
|
|
AzFramework::SimpleAssetReference<TestSimpleAsset>::Register(*serializeContext);
|
|
|
|
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
|
{
|
|
editContext->Class<TestSimpleAsset>("TestSimpleAsset", "Test data block for a simple asset mock data block")
|
|
->DataElement(0, &TestSimpleAsset::m_data, "My Data", "A test bool value.")
|
|
;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//! Test class
|
|
struct PropertyTreeEditorTester
|
|
{
|
|
AZ_TYPE_INFO(PropertyTreeEditorTester, "{D3E17BE6-0FEB-4A04-B8BE-105A4666E79F}");
|
|
|
|
int m_myInt = 42;
|
|
int m_myNewInt = 43;
|
|
bool m_myBool = true;
|
|
float m_myFloat = 42.0f;
|
|
AZStd::string m_myString = "StringValue";
|
|
AZStd::string m_myGroupedString = "GroupedStringValue";
|
|
PropertyTreeEditorSubBlockTester m_mySubBlock;
|
|
double m_myHiddenDouble = 42.0;
|
|
AZ::u16 m_myReadOnlyShort = 42;
|
|
AZ::Data::Asset<MockAssetData> m_myAssetData;
|
|
AzFramework::SimpleAssetReference<TestSimpleAsset> m_myTestSimpleAsset;
|
|
|
|
struct PropertyTreeEditorNestedTester
|
|
{
|
|
AZ_TYPE_INFO(PropertyTreeEditorTester, "{F5814544-424D-41C5-A5AB-632371615B6A}");
|
|
|
|
AZStd::string m_myNestedString = "NestedString";
|
|
};
|
|
|
|
AZStd::vector<PropertyTreeEditorNestedTester> m_myList;
|
|
AZStd::unordered_map<AZStd::string, PropertyTreeEditorNestedTester> m_myMap;
|
|
|
|
PropertyTreeEditorNestedTester m_nestedTester;
|
|
PropertyTreeEditorNestedTester m_nestedTesterHiddenChildren;
|
|
|
|
void Reflect(AZ::ReflectContext* context)
|
|
{
|
|
TestSimpleAsset::Reflect(context);
|
|
|
|
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<PropertyTreeEditorSubBlockTester>()
|
|
->Version(0)
|
|
->Field("myNegativeShort", &PropertyTreeEditorSubBlockTester::m_myNegativeShort);
|
|
|
|
serializeContext->Class<PropertyTreeEditorTester>()
|
|
->Version(1)
|
|
->Field("myInt", &PropertyTreeEditorTester::m_myInt)
|
|
->Field("myBool", &PropertyTreeEditorTester::m_myBool)
|
|
->Field("myFloat", &PropertyTreeEditorTester::m_myFloat)
|
|
->Field("myString", &PropertyTreeEditorTester::m_myString)
|
|
->Field("NestedTester", &PropertyTreeEditorTester::m_nestedTester)
|
|
->Field("myNewInt", &PropertyTreeEditorTester::m_myNewInt)
|
|
->Field("myGroupedString", &PropertyTreeEditorTester::m_myGroupedString)
|
|
->Field("myList", &PropertyTreeEditorTester::m_myList)
|
|
->Field("myMap", &PropertyTreeEditorTester::m_myMap)
|
|
->Field("mySubBlock", &PropertyTreeEditorTester::m_mySubBlock)
|
|
->Field("myHiddenDouble", &PropertyTreeEditorTester::m_myHiddenDouble)
|
|
->Field("myReadOnlyShort", &PropertyTreeEditorTester::m_myReadOnlyShort)
|
|
->Field("nestedTesterHiddenChildren", &PropertyTreeEditorTester::m_nestedTesterHiddenChildren)
|
|
->Field("myAssetData", &PropertyTreeEditorTester::m_myAssetData)
|
|
->Field("myTestSimpleAsset", &PropertyTreeEditorTester::m_myTestSimpleAsset)
|
|
;
|
|
|
|
serializeContext->Class<PropertyTreeEditorNestedTester>()
|
|
->Version(1)
|
|
->Field("myNestedString", &PropertyTreeEditorNestedTester::m_myNestedString)
|
|
;
|
|
|
|
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
|
{
|
|
editContext->Class<PropertyTreeEditorSubBlockTester>(
|
|
"PropertyTreeEditorSubBlock Tester", "Tester sub block for the PropertyTreeEditor test")
|
|
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorSubBlockTester::m_myNegativeShort, "My Negative Short", "A test short int.")
|
|
;
|
|
|
|
editContext->Class<PropertyTreeEditorTester>(
|
|
"PropertyTreeEditor Tester", "Tester for the PropertyTreeEditor")
|
|
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myInt, "My Int", "A test int.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myBool, "My Bool", "A test bool.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myFloat, "My Float", "A test float.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myString, "My String", "A test string.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_nestedTester, "Nested", "A nested class.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myNewInt, "My New Int", "A test int.", "My Old Int")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myList, "My New List", "A test vector<>.", "My Old List")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myMap, "My Map", "A test unordered_map<>.", "My Old Map")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myAssetData, "My Asset Data", "An test asset data.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myTestSimpleAsset, "My Test Simple Asset", "A test simple asset ref.")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myHiddenDouble, "My Hidden Double", "A test hidden node.", "My Old Double")
|
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_nestedTesterHiddenChildren, "Nested Hidden Children", "A test node with hidden children.")
|
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::HideChildren)
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myReadOnlyShort, "My Read Only", "A test read only node.")
|
|
->Attribute(AZ::Edit::Attributes::ReadOnly, true)
|
|
->DataElement(0, &PropertyTreeEditorTester::m_mySubBlock, "My Sub Block", "sub block test")
|
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
|
->ClassElement(AZ::Edit::ClassElements::Group, "Grouped")
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorTester::m_myGroupedString, "My Grouped String", "A test grouped string.")
|
|
;
|
|
|
|
editContext->Class<PropertyTreeEditorNestedTester>(
|
|
"PropertyTreeEditor Nested Tester", "SubClass Tester for the PropertyTreeEditor")
|
|
|
|
->DataElement(AZ::Edit::UIHandlers::Default, &PropertyTreeEditorNestedTester::m_myNestedString, "My Nested String", "A test string.")
|
|
;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class PropertyTreeEditorTests
|
|
: public ::testing::Test
|
|
{
|
|
public:
|
|
void SetUp() override
|
|
{
|
|
m_app.Start(AzFramework::Application::Descriptor());
|
|
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
|
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
|
// in the unit tests.
|
|
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
|
}
|
|
|
|
void TearDown() override
|
|
{
|
|
m_app.Stop();
|
|
}
|
|
|
|
ToolsTestApplication m_app{ "PropertyTreeEditorTests" };
|
|
AZ::SerializeContext* m_serializeContext = nullptr;
|
|
};
|
|
|
|
TEST_F(PropertyTreeEditorTests, ReadPropertyTreeValues)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
|
|
// Test existing properties of different types
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome boolOutcome = propertyTree.GetProperty("My Bool");
|
|
EXPECT_TRUE(boolOutcome.IsSuccess());
|
|
EXPECT_TRUE(AZStd::any_cast<bool>(boolOutcome.GetValue()));
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcome = propertyTree.GetProperty("My Int");
|
|
EXPECT_TRUE(intOutcome.IsSuccess());
|
|
EXPECT_EQ(AZStd::any_cast<int>(intOutcome.GetValue()), propertyTreeEditorTester.m_myInt);
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome floatOutcome = propertyTree.GetProperty("My Float");
|
|
EXPECT_TRUE(floatOutcome.IsSuccess());
|
|
EXPECT_FLOAT_EQ(AZStd::any_cast<float>(floatOutcome.GetValue()), propertyTreeEditorTester.m_myFloat);
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcome = propertyTree.GetProperty("My String");
|
|
EXPECT_TRUE(stringOutcome.IsSuccess());
|
|
EXPECT_STREQ(AZStd::any_cast<AZStd::string>(stringOutcome.GetValue()).data(), propertyTreeEditorTester.m_myString.data());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome nestedOutcome = propertyTree.GetProperty("Nested|My Nested String");
|
|
EXPECT_TRUE(nestedOutcome.IsSuccess());
|
|
EXPECT_STREQ(AZStd::any_cast<AZStd::string>(nestedOutcome.GetValue()).data(), propertyTreeEditorTester.m_nestedTester.m_myNestedString.data());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome groupedOutcome = propertyTree.GetProperty("Grouped|My Grouped String");
|
|
EXPECT_TRUE(groupedOutcome.IsSuccess());
|
|
EXPECT_STREQ(AZStd::any_cast<AZStd::string>(groupedOutcome.GetValue()).data(), propertyTreeEditorTester.m_myGroupedString.data());
|
|
}
|
|
|
|
|
|
// Test non-existing properties
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcome = propertyTree.GetProperty("Wrong Property");
|
|
EXPECT_FALSE(intOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome nestedOutcome = propertyTree.GetProperty("Nested|Wrong Nested Property");
|
|
EXPECT_FALSE(nestedOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
// Addressing the grouped property by name directly without the group should fail
|
|
PropertyTreeEditor::PropertyAccessOutcome groupedOutcome = propertyTree.GetProperty("My Grouped String");
|
|
EXPECT_FALSE(groupedOutcome.IsSuccess());
|
|
}
|
|
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, WritePropertyTreeValues)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
|
|
// Test existing properties of different types
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome boolOutcomeSet = propertyTree.SetProperty("My Bool", AZStd::any(false));
|
|
EXPECT_TRUE(boolOutcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome boolOutcomeGet = propertyTree.GetProperty("My Bool");
|
|
EXPECT_TRUE(boolOutcomeGet.IsSuccess());
|
|
EXPECT_FALSE(AZStd::any_cast<bool>(boolOutcomeGet.GetValue()));
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcomeSet = propertyTree.SetProperty("My Int", AZStd::any(48));
|
|
EXPECT_TRUE(intOutcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcomeGet = propertyTree.GetProperty("My Int");
|
|
EXPECT_TRUE(intOutcomeGet.IsSuccess());
|
|
EXPECT_EQ(AZStd::any_cast<int>(intOutcomeGet.GetValue()), AZStd::any_cast<int>(intOutcomeSet.GetValue()));
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome floatOutcomeSet = propertyTree.SetProperty("My Float", AZStd::any(48.0f));
|
|
EXPECT_TRUE(floatOutcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome floatOutcomeGet = propertyTree.GetProperty("My Float");
|
|
EXPECT_TRUE(floatOutcomeGet.IsSuccess());
|
|
EXPECT_FLOAT_EQ(AZStd::any_cast<float>(floatOutcomeGet.GetValue()), AZStd::any_cast<float>(floatOutcomeSet.GetValue()));
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcomeSet = propertyTree.SetProperty("My String", AZStd::make_any<AZStd::string>("New Value"));
|
|
EXPECT_TRUE(stringOutcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcomeGet = propertyTree.GetProperty("My String");
|
|
EXPECT_TRUE(stringOutcomeGet.IsSuccess());
|
|
EXPECT_STREQ(AZStd::any_cast<AZStd::string>(stringOutcomeSet.GetValue()).data(), AZStd::any_cast<AZStd::string>(stringOutcomeGet.GetValue()).data());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcomeSet = propertyTree.SetProperty("Nested|My Nested String", AZStd::make_any<AZStd::string>("New Nested Value"));
|
|
EXPECT_TRUE(stringOutcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcomeGet = propertyTree.GetProperty("Nested|My Nested String");
|
|
EXPECT_TRUE(stringOutcomeGet.IsSuccess());
|
|
EXPECT_STREQ(AZStd::any_cast<AZStd::string>(stringOutcomeSet.GetValue()).data(), AZStd::any_cast<AZStd::string>(stringOutcomeGet.GetValue()).data());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcomeSet = propertyTree.SetProperty("Grouped|My Grouped String", AZStd::make_any<AZStd::string>("New Grouped Value"));
|
|
EXPECT_TRUE(stringOutcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome stringOutcomeGet = propertyTree.GetProperty("Grouped|My Grouped String");
|
|
EXPECT_TRUE(stringOutcomeGet.IsSuccess());
|
|
EXPECT_STREQ(AZStd::any_cast<AZStd::string>(stringOutcomeSet.GetValue()).data(), AZStd::any_cast<AZStd::string>(stringOutcomeGet.GetValue()).data());
|
|
}
|
|
|
|
|
|
// Test non-existing properties
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcome = propertyTree.SetProperty("Wrong Property", AZStd::any(12));
|
|
EXPECT_FALSE(intOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome nestedOutcome = propertyTree.SetProperty("Nested|Wrong Nested Property", AZStd::make_any<AZStd::string>("Some Value"));
|
|
EXPECT_FALSE(nestedOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome groupedOutcome = propertyTree.SetProperty("Grouped|Wrong Grouped Property", AZStd::make_any<AZStd::string>("Some Value"));
|
|
EXPECT_FALSE(groupedOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
// Addressing the grouped property by name directly without the group should fail
|
|
PropertyTreeEditor::PropertyAccessOutcome groupedOutcome = propertyTree.SetProperty("My Grouped String", AZStd::make_any<AZStd::string>("Some Value"));
|
|
EXPECT_FALSE(groupedOutcome.IsSuccess());
|
|
}
|
|
|
|
|
|
// Test existing properties with wrong type
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcome = propertyTree.SetProperty("My Int", AZStd::any(12.0f));
|
|
EXPECT_FALSE(intOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome nestedOutcome = propertyTree.SetProperty("Nested|My Nested String", AZStd::any(42.0f));
|
|
EXPECT_FALSE(nestedOutcome.IsSuccess());
|
|
}
|
|
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome groupedOutcome = propertyTree.SetProperty("Grouped|My Grouped String", AZStd::any(42.0f));
|
|
EXPECT_FALSE(groupedOutcome.IsSuccess());
|
|
}
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, PropertyTreeVectorContainerSupport)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
// IsContainer
|
|
{
|
|
EXPECT_FALSE(propertyTree.IsContainer("My New Int"));
|
|
EXPECT_TRUE(propertyTree.IsContainer("My New List"));
|
|
}
|
|
|
|
// AddContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZ::s32>(0);
|
|
AZStd::any value = AZStd::make_any<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>();
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeAdd0 = propertyTree.AddContainerItem("My New Int", key, value);
|
|
EXPECT_FALSE(outcomeAdd0.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeAdd1 = propertyTree.AddContainerItem("My New List", key, value);
|
|
EXPECT_TRUE(outcomeAdd1.IsSuccess());
|
|
}
|
|
|
|
// GetContainerCount
|
|
{
|
|
EXPECT_FALSE(propertyTree.GetContainerCount("My New Int").IsSuccess());
|
|
EXPECT_EQ(1, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My New List").GetValue()));
|
|
}
|
|
|
|
// GetContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZ::s32>(0);
|
|
AZStd::any keyString = AZStd::make_any<AZStd::string_view>("0");
|
|
|
|
EXPECT_FALSE(propertyTree.GetContainerItem("My New Int", key).IsSuccess());
|
|
EXPECT_FALSE(propertyTree.GetContainerItem("My New List", keyString).IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcome = propertyTree.GetContainerItem("My New List", key);
|
|
EXPECT_TRUE(outcome.IsSuccess());
|
|
if (outcome.IsSuccess())
|
|
{
|
|
auto&& testerValue = AZStd::any_cast<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>(&outcome.GetValue());
|
|
EXPECT_STREQ("NestedString", testerValue->m_myNestedString.c_str());
|
|
}
|
|
}
|
|
|
|
// UpdateContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZ::s32>(0);
|
|
AZStd::any keyString = AZStd::make_any<AZStd::string_view>("0");
|
|
PropertyTreeEditorTester::PropertyTreeEditorNestedTester testUpdate;
|
|
testUpdate.m_myNestedString = "a new value";
|
|
AZStd::any value = AZStd::make_any<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>(testUpdate);
|
|
|
|
EXPECT_FALSE(propertyTree.UpdateContainerItem("My New Int", key, value).IsSuccess());
|
|
EXPECT_FALSE(propertyTree.UpdateContainerItem("My New List", keyString, value).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.UpdateContainerItem("My New List", key, value).IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcome = propertyTree.GetContainerItem("My New List", key);
|
|
EXPECT_TRUE(outcome.IsSuccess());
|
|
if (outcome.IsSuccess())
|
|
{
|
|
auto&& testerValue = AZStd::any_cast<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>(&outcome.GetValue());
|
|
EXPECT_STREQ(testUpdate.m_myNestedString.c_str(), testerValue->m_myNestedString.c_str());
|
|
}
|
|
}
|
|
|
|
// RemoveContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZ::s32>(0);
|
|
AZStd::any keyString = AZStd::make_any<AZStd::string_view>("0");
|
|
|
|
EXPECT_FALSE(propertyTree.RemoveContainerItem("My New Int", key).IsSuccess());
|
|
EXPECT_FALSE(propertyTree.RemoveContainerItem("My New List", keyString).IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeAdd1 = propertyTree.RemoveContainerItem("My New List", key);
|
|
EXPECT_TRUE(outcomeAdd1.IsSuccess());
|
|
EXPECT_EQ(0, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My New List").GetValue()));
|
|
}
|
|
|
|
// ResetContainer
|
|
{
|
|
AZStd::any value = AZStd::make_any<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>();
|
|
|
|
propertyTree.AddContainerItem("My New List", AZStd::make_any<AZ::s32>(0), value);
|
|
propertyTree.AddContainerItem("My New List", AZStd::make_any<AZ::s32>(1), value);
|
|
propertyTree.AddContainerItem("My New List", AZStd::make_any<AZ::s32>(2), value);
|
|
|
|
EXPECT_EQ(3, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My New List").GetValue()));
|
|
propertyTree.ResetContainer("My New List");
|
|
EXPECT_EQ(0, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My New List").GetValue()));
|
|
}
|
|
|
|
// AppendContainerItem
|
|
{
|
|
AZStd::any value = AZStd::make_any<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>();
|
|
|
|
EXPECT_TRUE(propertyTree.AppendContainerItem("My New List", value).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.AppendContainerItem("My New List", value).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.AppendContainerItem("My New List", value).IsSuccess());
|
|
|
|
EXPECT_EQ(3, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My New List").GetValue()));
|
|
propertyTree.ResetContainer("My New List");
|
|
}
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, PropertyTreeUnorderedMapContainerSupport)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
using TestData = PropertyTreeEditorTester::PropertyTreeEditorNestedTester;
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
propertyTreeEditorTester.m_myMap.emplace(AZStd::make_pair("one", TestData()));
|
|
const char* testDataString = "a test string";
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
// AddContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZStd::string>("two");
|
|
TestData testItem;
|
|
testItem.m_myNestedString = testDataString;
|
|
AZStd::any value = AZStd::make_any<TestData>(testItem);
|
|
EXPECT_TRUE(propertyTree.AddContainerItem("My Map", key, value).IsSuccess());
|
|
}
|
|
|
|
// GetContainerCount
|
|
{
|
|
EXPECT_EQ(2, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My Map").GetValue()));
|
|
}
|
|
|
|
// GetContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZStd::string>("two");
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcome = propertyTree.GetContainerItem("My Map", key);
|
|
EXPECT_TRUE(outcome.IsSuccess());
|
|
if (outcome.IsSuccess())
|
|
{
|
|
auto&& testerValue = AZStd::any_cast<TestData>(&outcome.GetValue());
|
|
EXPECT_STREQ(testDataString, testerValue->m_myNestedString.c_str());
|
|
}
|
|
}
|
|
|
|
// UpdateContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZStd::string>("two");
|
|
TestData testUpdate;
|
|
testUpdate.m_myNestedString = "a new value";
|
|
AZStd::any value = AZStd::make_any<TestData>(testUpdate);
|
|
|
|
EXPECT_TRUE(propertyTree.UpdateContainerItem("My Map", key, value).IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcome = propertyTree.GetContainerItem("My Map", key);
|
|
if (outcome.IsSuccess())
|
|
{
|
|
auto&& testerValue = AZStd::any_cast<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>(&outcome.GetValue());
|
|
EXPECT_STREQ(testUpdate.m_myNestedString.c_str(), testerValue->m_myNestedString.c_str());
|
|
}
|
|
}
|
|
|
|
// RemoveContainerItem
|
|
{
|
|
AZStd::any key = AZStd::make_any<AZStd::string>("two");
|
|
|
|
EXPECT_TRUE(propertyTree.RemoveContainerItem("My Map", key).IsSuccess());
|
|
EXPECT_EQ(1, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My Map").GetValue()));
|
|
}
|
|
|
|
// ResetContainer
|
|
{
|
|
EXPECT_EQ(1, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My Map").GetValue()));
|
|
propertyTree.ResetContainer("My Map");
|
|
EXPECT_EQ(0, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My Map").GetValue()));
|
|
}
|
|
|
|
// AppendContainerItem
|
|
{
|
|
AZStd::any value = AZStd::make_any<PropertyTreeEditorTester::PropertyTreeEditorNestedTester>();
|
|
EXPECT_FALSE(propertyTree.AppendContainerItem("My Map", value).IsSuccess());
|
|
EXPECT_EQ(0, AZStd::any_cast<AZ::u64>(propertyTree.GetContainerCount("My Map").GetValue()));
|
|
}
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, PropertyTreeInspection)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
// BuildPathsList
|
|
{
|
|
auto&& pathList = propertyTree.BuildPathsList();
|
|
EXPECT_TRUE(!pathList.empty());
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Map"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My New List"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "Nested|My Nested String"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "Grouped|My Grouped String"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Hidden Double"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Sub Block|My Negative Short"; }));
|
|
}
|
|
|
|
// BuildPathsListWithTypes
|
|
{
|
|
static auto stringContains = [](const AZStd::string& data, const char* subString) -> bool
|
|
{
|
|
return data.find(subString) != AZStd::string::npos;
|
|
};
|
|
auto&& pathList = propertyTree.BuildPathsListWithTypes();
|
|
EXPECT_TRUE(!pathList.empty());
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return stringContains(path,"NotVisible"); }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return stringContains(path,"Visible"); }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return stringContains(path,"ShowChildrenOnly"); }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return stringContains(path,"HideChildren"); }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return stringContains(path,"ReadOnly"); }));
|
|
}
|
|
|
|
// GetPropertyType
|
|
{
|
|
EXPECT_STREQ("AZStd::unordered_map", propertyTree.GetPropertyType("My Map").c_str());
|
|
EXPECT_STREQ("AZStd::vector", propertyTree.GetPropertyType("My New List").c_str());
|
|
EXPECT_STREQ("AZStd::string", propertyTree.GetPropertyType("Nested|My Nested String").c_str());
|
|
EXPECT_STREQ("double", propertyTree.GetPropertyType("My Hidden Double").c_str());
|
|
EXPECT_STREQ("PropertyTreeEditorTester", propertyTree.GetPropertyType("Nested").c_str());
|
|
}
|
|
|
|
// BuildPathsList after enforcement removes the "show children only" nodes from the paths
|
|
{
|
|
propertyTree.SetVisibleEnforcement(true);
|
|
|
|
auto&& pathList = propertyTree.BuildPathsList();
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Map"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My New List"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "Nested|My Nested String"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "Grouped|My Grouped String"; }));
|
|
EXPECT_FALSE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Hidden Double"; }));
|
|
EXPECT_FALSE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Sub Block|My Negative Short"; }));
|
|
EXPECT_TRUE(AZStd::any_of(pathList.begin(), pathList.end(), [](auto&& path) { return path == "My Negative Short"; }));
|
|
}
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, PropertyTreeAttributeInspection)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
// HasAttribute
|
|
{
|
|
EXPECT_TRUE(propertyTree.HasAttribute("My Read Only", "ReadOnly"));
|
|
EXPECT_TRUE(propertyTree.HasAttribute("My Hidden Double", "Visibility"));
|
|
EXPECT_TRUE(propertyTree.HasAttribute("My Sub Block", "AutoExpand"));
|
|
}
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, HandlesVisibleEnforcement)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
// can access a hidden value with 'visible enforcement' set to false
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeGet = propertyTree.GetProperty("My Hidden Double");
|
|
EXPECT_TRUE(outcomeGet.IsSuccess());
|
|
EXPECT_EQ(42.0, AZStd::any_cast<double>(outcomeGet.GetValue()));
|
|
}
|
|
|
|
// can mutate a hidden value with 'visible enforcement' set to false
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeSet = propertyTree.SetProperty("My Hidden Double", AZStd::any(12.0));
|
|
EXPECT_TRUE(outcomeSet.IsSuccess());
|
|
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeGet = propertyTree.GetProperty("My Hidden Double");
|
|
EXPECT_TRUE(outcomeGet.IsSuccess());
|
|
EXPECT_EQ(12.0, AZStd::any_cast<double>(outcomeGet.GetValue()));
|
|
}
|
|
|
|
propertyTree.SetVisibleEnforcement(true);
|
|
|
|
// can NOT access hidden value with 'visible enforcement' set to true
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeGet = propertyTree.GetProperty("My Hidden Double");
|
|
EXPECT_FALSE(outcomeGet.IsSuccess());
|
|
}
|
|
|
|
// can NOT mutate a hidden value with 'visible enforcement' set to false
|
|
{
|
|
PropertyTreeEditor::PropertyAccessOutcome outcomeSet = propertyTree.SetProperty("My Hidden Double", AZStd::any(42.0));
|
|
EXPECT_FALSE(outcomeSet.IsSuccess());
|
|
}
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, PropertyTreeDeprecatedNamesSupport)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
|
|
PropertyTreeEditor propertyTree = PropertyTreeEditor(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
|
|
// Test that new and deprecated name both refer to the same property
|
|
{
|
|
int newIntValue = 0;
|
|
|
|
// get current value of My New Int
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcomeGet = propertyTree.GetProperty("My New Int");
|
|
EXPECT_TRUE(intOutcomeGet.IsSuccess());
|
|
|
|
newIntValue = AZStd::any_cast<int>(intOutcomeGet.GetValue());
|
|
|
|
// Set new value to My Old Int
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcomeSet = propertyTree.SetProperty("My Old Int", AZStd::any(12));
|
|
EXPECT_TRUE(intOutcomeSet.IsSuccess());
|
|
|
|
// Read value of My New Int again
|
|
PropertyTreeEditor::PropertyAccessOutcome intOutcomeGetAgain = propertyTree.GetProperty("My New Int");
|
|
EXPECT_TRUE(intOutcomeGetAgain.IsSuccess());
|
|
|
|
// Verify that My Old Int and My New Int refer to the same property
|
|
EXPECT_TRUE(AZStd::any_cast<int>(intOutcomeGetAgain.GetValue()) != newIntValue);
|
|
}
|
|
|
|
}
|
|
|
|
TEST_F(PropertyTreeEditorTests, ClearWithEmptyAny)
|
|
{
|
|
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
|
|
|
AZ::Data::AssetId mockAssetId = AZ::Data::AssetId::CreateString("{66CC8A20-DC4D-4856-95FE-5C75A47B6A21}:0");
|
|
MockAssetData mockAssetData(mockAssetId);
|
|
AZ::Data::Asset<MockAssetData> mockAsset(&mockAssetData, AZ::Data::AssetLoadBehavior::Default);
|
|
|
|
AzFramework::SimpleAssetReference<TestSimpleAsset> mockSimpleAsset;
|
|
mockSimpleAsset.SetAssetPath("path/to/42");
|
|
|
|
PropertyTreeEditorTester propertyTreeEditorTester;
|
|
propertyTreeEditorTester.Reflect(m_serializeContext);
|
|
propertyTreeEditorTester.m_myInt = 42;
|
|
propertyTreeEditorTester.m_mySubBlock.m_myNegativeShort = -42;
|
|
propertyTreeEditorTester.m_myList.push_back({});
|
|
propertyTreeEditorTester.m_myAssetData = AZStd::move(mockAsset);
|
|
propertyTreeEditorTester.m_myTestSimpleAsset = mockSimpleAsset;
|
|
|
|
PropertyTreeEditor propertyTree(&propertyTreeEditorTester, AZ::AzTypeInfo<PropertyTreeEditorTester>::Uuid());
|
|
propertyTree.SetVisibleEnforcement(true);
|
|
|
|
// use an empty any<> to set properties back to a default value
|
|
{
|
|
AZStd::any anEmpty;
|
|
EXPECT_TRUE(propertyTree.SetProperty("My Int", anEmpty).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.SetProperty("My Negative Short", anEmpty).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.SetProperty("My New List", anEmpty).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.SetProperty("My Asset Data", anEmpty).IsSuccess());
|
|
EXPECT_TRUE(propertyTree.SetProperty("My Test Simple Asset", anEmpty).IsSuccess());
|
|
}
|
|
|
|
// check that the properties went back to default values
|
|
{
|
|
EXPECT_EQ(0, propertyTreeEditorTester.m_myInt);
|
|
EXPECT_EQ(0, propertyTreeEditorTester.m_mySubBlock.m_myNegativeShort);
|
|
EXPECT_TRUE(propertyTreeEditorTester.m_myList.empty());
|
|
EXPECT_FALSE(propertyTreeEditorTester.m_myAssetData.GetId().IsValid());
|
|
EXPECT_TRUE(propertyTreeEditorTester.m_myTestSimpleAsset.GetAssetPath().empty());
|
|
}
|
|
}
|
|
|
|
} // namespace UnitTest
|