Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,671 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/ReflectionManager.h>
#include <AzCore/Math/MathReflection.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/MockIGraphObject.h>
// the DLL entry point for SceneCore to reflect its behavior context
extern "C" AZ_DLL_EXPORT void ReflectBehavior(AZ::BehaviorContext* context);
// the DLL entry point for SceneCore to reflect its serialize context
extern "C" AZ_DLL_EXPORT void ReflectTypes(AZ::SerializeContext* context);
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class MockManifestRule : public DataTypes::IManifestObject
{
public:
AZ_RTTI(MockManifestRule, "{D6F96B48-4E6F-4EE8-A5A3-959B76F90DA8}", IManifestObject);
AZ_CLASS_ALLOCATOR(MockManifestRule, AZ::SystemAllocator, 0);
MockManifestRule() = default;
MockManifestRule(double value)
: m_value(value)
{
}
double GetValue() const
{
return m_value;
}
void SetValue(double value)
{
m_value = value;
}
static void Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<MockManifestRule, IManifestObject>()
->Version(1)
->Field("value", &MockManifestRule::m_value);
}
}
private:
double m_value = 0.0;
};
struct MockBuilder final
{
AZ_TYPE_INFO(MockBuilder, "{ECF0FB2C-E5C0-4B89-993C-8511A7EF6894}");
AZStd::unique_ptr<AZ::SceneAPI::Containers::Scene> m_scene;
MockBuilder()
{
m_scene = AZStd::make_unique<AZ::SceneAPI::Containers::Scene>("unit_scene");
}
~MockBuilder()
{
m_scene.reset();
}
void BuildSceneGraph()
{
m_scene->SetManifestFilename("manifest_filename");
m_scene->SetSource("unit_source_filename", azrtti_typeid<AZ::SceneAPI::Containers::Scene>());
auto& graph = m_scene->GetGraph();
/*----------------------------\
| Root |
| / \ |
| | | |
| A B |
| | /|\ |
| C I J K |
| / | \ \ |
| D E F L |
| / \ |
| G H |
\----------------------------*/
//Build up the graph
const auto indexA = graph.AddChild(graph.GetRoot(), "A", AZStd::make_shared<DataTypes::MockIGraphObject>(1));
const auto indexC = graph.AddChild(indexA, "C", AZStd::make_shared<DataTypes::MockIGraphObject>(3));
const auto indexE = graph.AddChild(indexC, "E", AZStd::make_shared<DataTypes::MockIGraphObject>(4));
graph.AddChild(indexC, "D", AZStd::make_shared<DataTypes::MockIGraphObject>(5));
graph.AddChild(indexC, "F", AZStd::make_shared<DataTypes::MockIGraphObject>(6));
graph.AddChild(indexE, "G", AZStd::make_shared<DataTypes::MockIGraphObject>(7));
graph.AddChild(indexE, "H", AZStd::make_shared<DataTypes::MockIGraphObject>(8));
const auto indexB = graph.AddChild(graph.GetRoot(), "B", AZStd::make_shared<DataTypes::MockIGraphObject>(2));
const auto indexK = graph.AddChild(indexB, "K", AZStd::make_shared<DataTypes::MockIGraphObject>(2));
graph.AddChild(indexB, "I", AZStd::make_shared<DataTypes::MockIGraphObject>(9));
graph.AddChild(indexB, "J", AZStd::make_shared<DataTypes::MockIGraphObject>(10));
graph.AddChild(indexK, "L", AZStd::make_shared<DataTypes::MockIGraphObject>(12));
m_scene->GetManifest().AddEntry(AZStd::make_shared<MockManifestRule>(0.1));
m_scene->GetManifest().AddEntry(AZStd::make_shared<MockManifestRule>(2.3));
m_scene->GetManifest().AddEntry(AZStd::make_shared<MockManifestRule>(4.5));
}
static void Reflect(ReflectContext* context)
{
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<MockBuilder>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("BuildSceneGraph", [](MockBuilder& self)
{
return self.BuildSceneGraph();
})
->Method("GetScene", [](MockBuilder& self)
{
return self.m_scene.get();
});
}
}
};
class SceneGraphBehaviorTest
: public ::testing::Test
{
public:
void SetUp() override
{
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
ReflectBehavior(m_behaviorContext.get());
}
void TearDown() override
{
m_behaviorContext.reset();
}
AZ::BehaviorClass* GetBehaviorClass(const AZ::TypeId& behaviorClassType)
{
auto entry = m_behaviorContext->m_typeToClassMap.find(behaviorClassType);
return (entry != m_behaviorContext->m_typeToClassMap.end()) ? entry->second : nullptr;
}
AZ::BehaviorProperty* GetBehaviorProperty(AZ::BehaviorClass& behaviorClass, AZStd::string_view propertyName)
{
auto entry = behaviorClass.m_properties.find(propertyName);
return (entry != behaviorClass.m_properties.end()) ? entry->second : nullptr;
}
bool HasBehaviorClass(const AZ::TypeId& behaviorClassType)
{
return GetBehaviorClass(behaviorClassType) != nullptr;
}
bool HasProperty(AZ::BehaviorClass& behaviorClass, AZStd::string_view propertyName, const AZ::TypeId& propertyClassType)
{
AZ::BehaviorProperty* behaviorProperty = GetBehaviorProperty(behaviorClass, propertyName);
if (behaviorProperty)
{
return behaviorProperty->m_getter->GetResult()->m_typeId == propertyClassType;
}
return false;
}
using ArgList = AZStd::vector<AZ::TypeId>;
bool HasMethodWithInput(AZ::BehaviorClass& behaviorClass, AZStd::string_view methodName, const ArgList& input)
{
auto entry = behaviorClass.m_methods.find(methodName);
if (entry == behaviorClass.m_methods.end())
{
return false;
}
AZ::BehaviorMethod* method = entry->second;
const size_t methodArgsCount = method->IsMember() ? method->GetNumArguments() - 1 : method->GetNumArguments();
if (input.size() != methodArgsCount)
{
return false;
}
for (size_t argIndex = 0; argIndex < input.size(); ++argIndex)
{
const size_t thisPointerOffset = method->IsMember() ? 1 : 0;
const auto argType = method->GetArgument(argIndex + thisPointerOffset)->m_typeId;
const auto inputType = input[argIndex];
if (inputType != argType)
{
return false;
}
}
return true;
}
bool HasMethodWithOutput(AZ::BehaviorClass& behaviorClass, AZStd::string_view methodName, const AZ::TypeId& output, const ArgList& input)
{
auto entry = behaviorClass.m_methods.find(methodName);
if (entry == behaviorClass.m_methods.end())
{
return false;
}
AZ::BehaviorMethod* method = entry->second;
if (method->HasResult())
{
if (method->GetResult()->m_typeId != output)
{
return false;
}
}
else
{
return false;
}
return HasMethodWithInput(behaviorClass, methodName, input);
}
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
};
TEST_F(SceneGraphBehaviorTest, SceneClass_BehaviorContext_Exists)
{
EXPECT_TRUE(HasBehaviorClass(azrtti_typeid<AZ::SceneAPI::Containers::Scene>()));
}
TEST_F(SceneGraphBehaviorTest, SceneClass_BehaviorContext_HasExpectedProperties)
{
AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid<AZ::SceneAPI::Containers::Scene>());
ASSERT_NE(nullptr, behaviorClass);
EXPECT_TRUE(HasProperty(*behaviorClass, "name", azrtti_typeid<AZStd::string>()));
EXPECT_TRUE(HasProperty(*behaviorClass, "manifestFilename", azrtti_typeid<AZStd::string>()));
EXPECT_TRUE(HasProperty(*behaviorClass, "sourceFilename", azrtti_typeid<AZStd::string>()));
EXPECT_TRUE(HasProperty(*behaviorClass, "sourceGuid", azrtti_typeid<AZ::Uuid>()));
EXPECT_TRUE(HasProperty(*behaviorClass, "graph", azrtti_typeid<AZ::SceneAPI::Containers::SceneGraph>()));
EXPECT_TRUE(HasProperty(*behaviorClass, "manifest", azrtti_typeid<AZ::SceneAPI::Containers::SceneManifest>()));
}
TEST_F(SceneGraphBehaviorTest, SceneGraphClass_BehaviorContext_Exists)
{
EXPECT_TRUE(HasBehaviorClass(azrtti_typeid<AZ::SceneAPI::Containers::SceneGraph>()));
EXPECT_TRUE(HasBehaviorClass(azrtti_typeid<AZ::SceneAPI::Containers::SceneGraph::NodeIndex>()));
EXPECT_TRUE(HasBehaviorClass(azrtti_typeid<AZ::SceneAPI::Containers::SceneGraph::Name>()));
}
TEST_F(SceneGraphBehaviorTest, SceneGraphClass_BehaviorContext_HasExpectedProperties)
{
using namespace AZ::SceneAPI::Containers;
AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid<SceneGraph>());
ASSERT_NE(nullptr, behaviorClass);
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetNodeName", azrtti_typeid<SceneGraph::Name>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetRoot", azrtti_typeid<SceneGraph::NodeIndex>(), {}));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeContent", azrtti_typeid<bool>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeSibling", azrtti_typeid<bool>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeChild", azrtti_typeid<bool>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "HasNodeParent", azrtti_typeid<bool>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "IsNodeEndPoint", azrtti_typeid<bool>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetNodeCount", azrtti_typeid<size_t>(), {}));
EXPECT_TRUE(HasMethodWithOutput(
*behaviorClass,
"GetNodeParent",
azrtti_typeid<SceneGraph::NodeIndex>(),
{ azrtti_typeid<SceneGraph>(), azrtti_typeid<SceneGraph::NodeIndex>() }
));
EXPECT_TRUE(HasMethodWithOutput(
*behaviorClass,
"GetNodeSibling",
azrtti_typeid<SceneGraph::NodeIndex>(),
{ azrtti_typeid<SceneGraph>(), azrtti_typeid<SceneGraph::NodeIndex>() }
));
EXPECT_TRUE(HasMethodWithOutput(
*behaviorClass,
"GetNodeChild",
azrtti_typeid<SceneGraph::NodeIndex>(),
{ azrtti_typeid<SceneGraph>(), azrtti_typeid<SceneGraph::NodeIndex>() }
));
EXPECT_TRUE(HasMethodWithOutput(
*behaviorClass,
"FindWithPath",
azrtti_typeid<SceneGraph::NodeIndex>(),
{ azrtti_typeid<SceneGraph>(), azrtti_typeid<AZStd::string>() }
));
EXPECT_TRUE(HasMethodWithOutput(
*behaviorClass,
"FindWithRootAndPath",
azrtti_typeid<SceneGraph::NodeIndex>(),
{ azrtti_typeid<SceneGraph>(), azrtti_typeid<SceneGraph::NodeIndex>(), azrtti_typeid<AZStd::string>() }
));
}
TEST_F(SceneGraphBehaviorTest, SceneGraphNodeIndexClass_BehaviorContext_HasExpectedProperties)
{
using namespace AZ::SceneAPI::Containers;
AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid<SceneGraph::NodeIndex>());
ASSERT_NE(nullptr, behaviorClass);
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "AsNumber", azrtti_typeid<uint32_t>(), {}));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "Distance", azrtti_typeid<AZ::s32>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "IsValid", azrtti_typeid<bool>(), {}));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "Equal", azrtti_typeid<bool>(), { azrtti_typeid<SceneGraph::NodeIndex>() }));
}
TEST_F(SceneGraphBehaviorTest, SceneGraphNameClass_BehaviorContext_HasExpectedProperties)
{
using namespace AZ::SceneAPI::Containers;
AZ::BehaviorClass* behaviorClass = GetBehaviorClass(azrtti_typeid<SceneGraph::Name>());
ASSERT_NE(nullptr, behaviorClass);
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetPath", azrtti_typeid<const char*>(), {}));
EXPECT_TRUE(HasMethodWithOutput(*behaviorClass, "GetName", azrtti_typeid<const char*>(), {}));
}
class MockSceneComponentApplication
: public AZ::ComponentApplicationBus::Handler
{
public:
MockSceneComponentApplication()
{
AZ::ComponentApplicationBus::Handler::BusConnect();
}
~MockSceneComponentApplication()
{
AZ::ComponentApplicationBus::Handler::BusDisconnect();
}
MOCK_METHOD1(FindEntity, AZ::Entity* (const AZ::EntityId&));
MOCK_METHOD1(AddEntity, bool(AZ::Entity*));
MOCK_METHOD0(Destroy, void());
MOCK_METHOD1(RegisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*));
MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&));
MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&));
MOCK_METHOD1(EnumerateEntities, void(const ComponentApplicationRequests::EntityCallback&));
MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
MOCK_CONST_METHOD0(GetAppRoot, const char* ());
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
};
//
// SceneGraphBehaviorScriptTest
//
class SceneGraphBehaviorScriptTest
: public UnitTest::AllocatorsFixture
{
public:
AZStd::unique_ptr<MockSceneComponentApplication> m_componentApplication;
AZStd::unique_ptr<AZ::ScriptContext> m_scriptContext;
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
static void TestExpectTrue(bool value)
{
EXPECT_TRUE(value);
}
static void TestExpectEquals(AZ::s64 lhs, AZ::s64 rhs)
{
EXPECT_EQ(lhs, rhs);
}
static void ReflectTestTypes(AZ::ReflectContext* context)
{
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<DataTypes::MockIGraphObject>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph.test")
->Method("GetId", [](const DataTypes::MockIGraphObject& self)
{
return self.m_id;
})
->Method("SetId", [](DataTypes::MockIGraphObject& self, int value)
{
self.m_id = value;
})
->Method("AddAndSet", [](DataTypes::MockIGraphObject& self, int lhs, int rhs)
{
self.m_id = lhs + rhs;
});
}
}
void SetUp() override
{
UnitTest::AllocatorsFixture::SetUp();
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
m_behaviorContext->Method("TestExpectTrue", &TestExpectTrue);
m_behaviorContext->Method("TestExpectEquals", &TestExpectEquals);
AZ::MathReflect(m_behaviorContext.get());
ReflectBehavior(m_behaviorContext.get());
ReflectTestTypes(m_behaviorContext.get());
MockBuilder::Reflect(m_behaviorContext.get());
m_scriptContext = AZStd::make_unique<AZ::ScriptContext>();
m_scriptContext->BindTo(m_behaviorContext.get());
m_componentApplication = AZStd::make_unique<::testing::NiceMock<MockSceneComponentApplication>>();
ON_CALL(*m_componentApplication, GetBehaviorContext())
.WillByDefault(::testing::Invoke([this]()
{
return this->m_behaviorContext.get();
}));
ON_CALL(*m_componentApplication, GetSerializeContext())
.WillByDefault(::testing::Invoke([this]()
{
return this->m_serializeContext.get();
}));
}
void TearDown() override
{
m_scriptContext.reset();
m_serializeContext.reset();
m_behaviorContext.reset();
UnitTest::AllocatorsFixture::TearDown();
}
void ExpectExecute(AZStd::string_view script)
{
EXPECT_TRUE(m_scriptContext->Execute(script.data()));
}
};
TEST_F(SceneGraphBehaviorScriptTest, Scene_ScriptContext_Access)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("builder:BuildSceneGraph()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("TestExpectTrue(scene ~= nil)");
ExpectExecute("TestExpectTrue(scene.name == 'unit_scene')");
ExpectExecute("TestExpectTrue(scene.manifestFilename == 'manifest_filename')");
ExpectExecute("TestExpectTrue(scene.sourceFilename == 'unit_source_filename')");
ExpectExecute("TestExpectTrue(tostring(scene.sourceGuid) == '{1F2E6142-B0D8-42C6-A6E5-CD726DAA9EF0}')");
ExpectExecute("TestExpectTrue(scene:GetOriginalSceneOrientation() == Scene.SceneOrientation_YUp)");
}
TEST_F(SceneGraphBehaviorScriptTest, SceneGraph_ScriptContext_AccessMockNodes)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("builder:BuildSceneGraph()");
ExpectExecute("scene = builder:GetScene()");
// instance methods
ExpectExecute("TestExpectTrue(scene.graph ~= nil)");
ExpectExecute("TestExpectTrue(scene.graph:GetRoot():IsValid())");
ExpectExecute("TestExpectEquals(scene.graph:GetNodeCount(), 13)");
ExpectExecute("nodeRoot = scene.graph:GetRoot()");
ExpectExecute("nodeA = scene.graph:GetNodeChild(nodeRoot); TestExpectTrue(nodeA:IsValid())");
ExpectExecute("TestExpectTrue(scene.graph:HasNodeContent(nodeA))");
ExpectExecute("nodeC = scene.graph:GetNodeChild(nodeA); TestExpectTrue(nodeC:IsValid())");
ExpectExecute("nodeNameC = scene.graph:GetNodeName(nodeC); TestExpectTrue(nodeNameC ~= nil)");
ExpectExecute("nodeE = scene.graph:GetNodeChild(nodeC); TestExpectTrue(nodeE:IsValid())");
ExpectExecute("TestExpectTrue(scene.graph:HasNodeSibling(nodeE))");
ExpectExecute("TestExpectTrue(scene.graph:HasNodeChild(nodeE))");
ExpectExecute("TestExpectTrue(scene.graph:HasNodeParent(nodeE))");
ExpectExecute("nodeG = scene.graph:GetNodeChild(nodeE); TestExpectTrue(nodeG:IsValid())");
ExpectExecute("TestExpectTrue(scene.graph:GetNodeParent(nodeG) == nodeE)");
ExpectExecute("nodeH = scene.graph:GetNodeSibling(nodeG); TestExpectTrue(nodeH:IsValid())");
ExpectExecute("TestExpectTrue(scene.graph:GetNodeName(nodeH):GetPath() == 'A.C.E.H')");
ExpectExecute("nodeB = scene.graph:GetNodeSibling(nodeA); TestExpectTrue(nodeB:IsValid())");
ExpectExecute("nodeK = scene.graph:GetNodeChild(nodeB); TestExpectTrue(nodeK:IsValid())");
ExpectExecute("TestExpectTrue(scene.graph:FindWithPath('B.K') == nodeK)");
ExpectExecute("nodeL = scene.graph:GetNodeChild(nodeK); TestExpectTrue(nodeL:IsValid())");
ExpectExecute("TestExpectTrue(scene.graph:FindWithRootAndPath(nodeK, 'L') == nodeL)");
// static methods
ExpectExecute("TestExpectTrue(scene.graph.IsValidName('A'))");
ExpectExecute("TestExpectTrue(scene.graph.GetNodeSeperationCharacter() == string.byte('.'))");
}
TEST_F(SceneGraphBehaviorScriptTest, SceneGraphNodeIndex_ScriptContext_AccessMockNodes)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("builder:BuildSceneGraph()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("nodeA = scene.graph:GetNodeChild(scene.graph:GetRoot())");
ExpectExecute("TestExpectTrue(nodeA:IsValid())");
ExpectExecute("TestExpectEquals(nodeA:AsNumber(), 1)");
ExpectExecute("TestExpectEquals(scene.graph:GetRoot():Distance(nodeA), 1)");
ExpectExecute("TestExpectEquals(nodeA:Distance(scene.graph:GetRoot()), -1)");
ExpectExecute("TestExpectTrue(nodeA == scene.graph:FindWithPath('A'))");
}
TEST_F(SceneGraphBehaviorScriptTest, SceneGraphName_ScriptContext_AccessMockNodes)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("builder:BuildSceneGraph()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
ExpectExecute("nodeNameG = scene.graph:GetNodeName(nodeG)");
ExpectExecute("TestExpectTrue(nodeNameG:GetPath() == 'A.C.E.G')");
ExpectExecute("TestExpectTrue(nodeNameG:GetName() == 'G')");
}
TEST_F(SceneGraphBehaviorScriptTest, SceneGraphIGraphNode_ScriptContext_AccessMockNodes)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("builder:BuildSceneGraph()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("nodeG = scene.graph:FindWithPath('A.C.E.G')");
ExpectExecute("proxy = scene.graph:GetNodeContent(nodeG)");
ExpectExecute("TestExpectTrue(proxy:CastWithTypeName('MockIGraphObject'))");
ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
ExpectExecute("TestExpectEquals(value, 7)");
ExpectExecute("setIdArgs = vector_any(); setIdArgs:push_back(8);");
ExpectExecute("proxy:Invoke('SetId', setIdArgs)");
ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
ExpectExecute("TestExpectEquals(value, 8)");
ExpectExecute("addArgs = vector_any(); addArgs:push_back(8); addArgs:push_back(9)");
ExpectExecute("proxy:Invoke('AddAndSet', addArgs)");
ExpectExecute("value = proxy:Invoke('GetId', vector_any())");
ExpectExecute("TestExpectEquals(value, 17)");
}
//
// SceneManifestBehaviorScriptTest is meant to test the script abilities of the SceneManifest
//
class SceneManifestBehaviorScriptTest
: public UnitTest::AllocatorsFixture
{
public:
AZStd::unique_ptr<MockSceneComponentApplication> m_componentApplication;
AZStd::unique_ptr<AZ::ScriptContext> m_scriptContext;
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
AZStd::unique_ptr<AZ::JsonRegistrationContext> m_jsonRegistrationContext;
AZStd::string_view m_jsonMockData = R"JSON('{"values":[{"$type":"MockManifestRule","value":0.1},{"$type":"MockManifestRule","value":2.3},{"$type":"MockManifestRule","value":4.5}]}')JSON";
static void TestAssertTrue(bool value)
{
EXPECT_TRUE(value);
}
void SetUp() override
{
UnitTest::AllocatorsFixture::SetUp();
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
MockBuilder::Reflect(m_serializeContext.get());
MockManifestRule::Reflect(m_serializeContext.get());
ReflectTypes(m_serializeContext.get());
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
m_behaviorContext->Method("TestAssertTrue", &TestAssertTrue);
AZ::MathReflect(m_behaviorContext.get());
MockBuilder::Reflect(m_behaviorContext.get());
MockManifestRule::Reflect(m_behaviorContext.get());
ReflectBehavior(m_behaviorContext.get());
m_jsonRegistrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
m_scriptContext = AZStd::make_unique<AZ::ScriptContext>();
m_scriptContext->BindTo(m_behaviorContext.get());
m_componentApplication = AZStd::make_unique<::testing::NiceMock<MockSceneComponentApplication>>();
ON_CALL(*m_componentApplication, GetBehaviorContext()).WillByDefault(::testing::Invoke([this]()
{
return this->m_behaviorContext.get();
}));
ON_CALL(*m_componentApplication, GetSerializeContext()).WillByDefault(::testing::Invoke([this]()
{
return this->m_serializeContext.get();
}));
ON_CALL(*m_componentApplication, GetJsonRegistrationContext()).WillByDefault(::testing::Invoke([this]()
{
return this->m_jsonRegistrationContext.get();
}));
}
void TearDown() override
{
m_jsonRegistrationContext->EnableRemoveReflection();
AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
m_jsonRegistrationContext->DisableRemoveReflection();
m_jsonRegistrationContext.reset();
m_serializeContext.reset();
m_scriptContext.reset();
m_behaviorContext.reset();
m_componentApplication.reset();
UnitTest::AllocatorsFixture::TearDown();
}
void ExpectExecute(AZStd::string_view script)
{
EXPECT_TRUE(m_scriptContext->Execute(script.data()));
}
};
TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_GetDefaultJSON)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("manifest = scene.manifest:ExportToJson()");
ExpectExecute(R"JSON(TestAssertTrue(manifest == '{}'))JSON");
}
TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_GetComplexJSON)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("builder:BuildSceneGraph()");
ExpectExecute("manifest = scene.manifest:ExportToJson()");
auto read = AZStd::fixed_string<1024>::format("TestAssertTrue(manifest == %s)", m_jsonMockData.data());
ExpectExecute(read);
}
TEST_F(SceneManifestBehaviorScriptTest, SceneManifest_ScriptContext_SetComplexJSON)
{
ExpectExecute("builder = MockBuilder()");
ExpectExecute("scene = builder:GetScene()");
ExpectExecute("manifest = scene.manifest:ExportToJson()");
ExpectExecute(R"JSON(TestAssertTrue(manifest == '{}'))JSON");
auto load = AZStd::fixed_string<1024>::format("TestAssertTrue(scene.manifest:ImportFromJson(%s))", m_jsonMockData.data());
ExpectExecute(load);
ExpectExecute("manifest = scene.manifest:ExportToJson()");
auto read = AZStd::fixed_string<1024>::format("TestAssertTrue(manifest == %s)", m_jsonMockData.data());
ExpectExecute(read);
}
}
}
}
@@ -0,0 +1,901 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/MockIGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
//
// Name
//
TEST(SceneGraphNameTest, ConstructorAndGetPath_MovedNameIsPath_PathIsEqualToGivenName)
{
const char* name = "test";
SceneGraph::Name test(AZStd::string(name), 0);
EXPECT_STREQ(name, test.GetPath());
}
TEST(SceneGraphNameTest, GetName_ValidOffset_ReturnsB)
{
const char* name = "A.B";
SceneGraph::Name test(AZStd::string(name), 2);
EXPECT_STREQ("B", test.GetName());
}
TEST(SceneGraphNameTest, ConstructorAndGetName_InvalidOffset_ReturnsEmptyStringAndDoesNotAssert)
{
const char* name = "A.B";
SceneGraph::Name test(AZStd::string(name), 42);
EXPECT_STREQ("", test.GetName());
}
TEST(SceneGraphNameTest, Constructor_BlankPath_GetPathAndGetNameReturnValidEmptyStrings)
{
SceneGraph::Name test(AZStd::string(""), 0);
EXPECT_STREQ("", test.GetPath());
EXPECT_STREQ("", test.GetName());
}
TEST(SceneGraphNameTest, Equality_IdenticalNames_NamesAreEqual)
{
const char* name = "A.B";
SceneGraph::Name test1(AZStd::string(name), 2);
SceneGraph::Name test2(AZStd::string(name), 2);
EXPECT_TRUE(test1 == test2);
EXPECT_FALSE(test1 != test2);
}
TEST(SceneGraphNameTest, Equality_DifferentOffsets_NamesAreNotEqual)
{
const char* name = "A.B.C";
SceneGraph::Name test1(AZStd::string(name), 2);
SceneGraph::Name test2(AZStd::string(name), 4);
EXPECT_FALSE(test1 == test2);
EXPECT_TRUE(test1 != test2);
}
TEST(SceneGraphNameTest, Equality_DifferentPaths_NamesAreNotEqual)
{
const char* name1 = "A.B";
const char* name2 = "C.D";
SceneGraph::Name test1(AZStd::string(name1), 2);
SceneGraph::Name test2(AZStd::string(name2), 2);
EXPECT_FALSE(test1 == test2);
EXPECT_TRUE(test1 != test2);
}
TEST(SceneGraphNameTest, Equality_CompletelyDifferent_NamesAreNotEqual)
{
const char* name1 = "A.B";
const char* name2 = "C.D.E";
SceneGraph::Name test1(AZStd::string(name1), 2);
SceneGraph::Name test2(AZStd::string(name2), 4);
EXPECT_FALSE(test1 == test2);
EXPECT_TRUE(test1 != test2);
}
//
// SceneGraph
//
class SceneGraphTest
: public ::testing::Test
, public AZ::Debug::TraceMessageBus::Handler
{
public:
void SetUp() override
{
BusConnect();
}
void TearDown() override
{
BusDisconnect();
}
bool OnPreAssert(const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/)
{
m_assertTriggered = true;
return true;
}
bool m_assertTriggered = false;
};
TEST_F(SceneGraphTest, Constructor_Default_HasRoot)
{
SceneGraph testSceneGraph;
EXPECT_TRUE(testSceneGraph.GetRoot().IsValid());
}
TEST_F(SceneGraphTest, Find_NonExistantNode_IsNotValid)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.Find("NonExistantNodeName");
EXPECT_FALSE(testNodeIndex.IsValid());
}
// GetNodeCount
TEST_F(SceneGraphTest, GetNodeCount_CountForEmptyGraph_Returns1)
{
SceneGraph testSceneGraph;
size_t count = testSceneGraph.GetNodeCount();
EXPECT_EQ(1, count);
}
//AddSibling
TEST_F(SceneGraphTest, AddSibling_NodeValid_NodeIndexValid)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
EXPECT_TRUE(testNodeIndex.IsValid());
}
TEST_F(SceneGraphTest, AddSibling_NodeHasSiblingAlready_NodeIndexValidAndNotFirstNode)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex firstNode = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex secondNode = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject1", AZStd::move(testDataObject));
EXPECT_TRUE(secondNode.IsValid());
EXPECT_NE(firstNode, secondNode);
}
TEST_F(SceneGraphTest, AddSibling_NodeInvalid_NodeIndexIsNotValid)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex invalidNodeIndex = testSceneGraph.Find("NonExistantNodeName");
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(invalidNodeIndex, "testObject", AZStd::move(testDataObject));
EXPECT_FALSE(testNodeIndex.IsValid());
}
TEST_F(SceneGraphTest, AddSibling_RootNoData_NodeIndexValid)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject");
EXPECT_TRUE(testNodeIndex.IsValid());
}
//AddChild (implementation depends on AddSibling)
TEST_F(SceneGraphTest, AddChild_ParentValid_NodeIndexValid)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
EXPECT_TRUE(testNodeIndex.IsValid());
}
TEST_F(SceneGraphTest, AddChild_ParentValidNoData_NodeIndexValid)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject");
EXPECT_TRUE(testNodeIndex.IsValid());
}
TEST_F(SceneGraphTest, AddChild_ParentHasChildAlready_NodeIndexValidNotEqualFirst)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex firstIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex secondIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject1", AZStd::move(testDataObject));
EXPECT_TRUE(secondIndex.IsValid());
EXPECT_NE(firstIndex, secondIndex);
}
TEST_F(SceneGraphTest, AddChild_InvalidNameUsed_AssertTriggered)
{
SceneGraph testSceneGraph;
testSceneGraph.AddChild(testSceneGraph.GetRoot(), "Invalid.Name");
EXPECT_TRUE(m_assertTriggered);
}
TEST_F(SceneGraphTest, AddChild_DuplicateNameUsed_AssertTriggered)
{
SceneGraph testSceneGraph;
testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject");
testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject");
EXPECT_TRUE(m_assertTriggered);
}
TEST_F(SceneGraphTest, AddChild_ParentIsEndPoint_AssertTriggered)
{
SceneGraph testSceneGraph;
testSceneGraph.MakeEndPoint(testSceneGraph.GetRoot());
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
EXPECT_TRUE(m_assertTriggered);
}
TEST_F(SceneGraphTest, AddChild_ParentInvalid_NodeIndexIsNotValid)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex invalidNodeIndex = testSceneGraph.Find("NonExistantNodeName");
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(invalidNodeIndex, "testObject", AZStd::move(testDataObject));
EXPECT_FALSE(testNodeIndex.IsValid());
}
//HasNodeContent
TEST_F(SceneGraphTest, HasNodeContent_AddChildCalledwithData_NodeHasData)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
EXPECT_TRUE(testSceneGraph.HasNodeContent(testNodeIndex));
}
TEST_F(SceneGraphTest, HasNodeContent_AddChildCalledwithNoData_NodeHasNoData)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject");
EXPECT_FALSE(testSceneGraph.HasNodeContent(testNodeIndex));
}
TEST_F(SceneGraphTest, HasNodeContent_AddSiblingCalledwithData_NodeHasData)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
EXPECT_TRUE(testSceneGraph.HasNodeContent(testNodeIndex));
}
TEST_F(SceneGraphTest, HasNodeContent_AddSiblingCalledwithNoData_NodeHasNoData)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject");
EXPECT_FALSE(testSceneGraph.HasNodeContent(testNodeIndex));
}
// IsNodeEndPoint
TEST_F(SceneGraphTest, IsNodeEndPoint_NewNodesAreNotEndPoints_NodeIsNotAnEndPoint)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject");
EXPECT_FALSE(testSceneGraph.IsNodeEndPoint(testNodeIndex));
}
//GetNodeContent
TEST_F(SceneGraphTest, GetNodeContent_IntDataChildAddedToRoot_CanGetNodeData)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>(1);
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject", AZStd::move(testDataObject));
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(testNodeIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(1, storedValue->m_id);
}
TEST_F(SceneGraphTest, GetNodeContent_NoData_NodeDataIsNullPtr)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testObject");
AZStd::shared_ptr<DataTypes::IGraphObject> storedValue = testSceneGraph.GetNodeContent(testNodeIndex);
EXPECT_EQ(nullptr, storedValue);
}
//Find
TEST_F(SceneGraphTest, Find_OnRootwithChild_NodeIndexIsCorrect)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "TestObject", AZStd::move(testDataObject));
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("TestObject");
EXPECT_TRUE(foundIndex.IsValid());
EXPECT_EQ(foundIndex, testNodeIndex);
}
TEST_F(SceneGraphTest, Find_OnRootwithChildwithChild_NodeIndexIsCorrect)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex firstChildNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "FirstChild", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(firstChildNodeIndex, "FirstChildofFirstChild", AZStd::move(testDataObject));
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("FirstChild.FirstChildofFirstChild");
EXPECT_TRUE(foundIndex.IsValid());
EXPECT_EQ(foundIndex, testNodeIndex);
}
TEST_F(SceneGraphTest, Find_OnRootwithSecondChild_NodeIndexIsCorrect)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex firstChildNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "FirstChild", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "SecondChild", AZStd::move(testDataObject));
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("SecondChild");
EXPECT_TRUE(foundIndex.IsValid());
EXPECT_EQ(foundIndex, testNodeIndex);
}
TEST_F(SceneGraphTest, Find_OnNodewithSecondChildLookingForSecondChild_NodeIndexIsCorrect)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testRootNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testRoot", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex firstChildNodeIndex = testSceneGraph.AddChild(testRootNodeIndex, "FirstChild", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testRootNodeIndex, "SecondChild", AZStd::move(testDataObject));
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find(testRootNodeIndex, "SecondChild");
EXPECT_TRUE(foundIndex.IsValid());
EXPECT_EQ(foundIndex, testNodeIndex);
}
TEST_F(SceneGraphTest, Find_ParentDoesNotHaveThisChild_NodeIndexIsNotValid)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testRootNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testRoot", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testRootNodeSiblingIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testRootSibling", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex firstChildNodeIndex = testSceneGraph.AddChild(testRootNodeIndex, "FirstChild", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>();
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testRootNodeIndex, "SecondChild", AZStd::move(testDataObject));
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find(testRootNodeSiblingIndex, "SecondChild");
EXPECT_FALSE(foundIndex.IsValid());
}
//SetContent
TEST_F(SceneGraphTest, SetContent_EmptyNodeByReference_NewValueConfirmed)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testNode");
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>(1);
bool result = testSceneGraph.SetContent(testNodeIndex, testDataObject);
EXPECT_TRUE(result);
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(testNodeIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(1, storedValue->m_id);
}
TEST_F(SceneGraphTest, SetContent_EmptyNodeByMove_NewValueConfirmed)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testNode");
bool result = testSceneGraph.SetContent(testNodeIndex, AZStd::make_shared<DataTypes::MockIGraphObject>(1));
EXPECT_TRUE(result);
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(testNodeIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(1, storedValue->m_id);
}
TEST_F(SceneGraphTest, SetContent_ExistingNodeByReference_NewFloatConfirmed)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>(1);
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testNode", AZStd::move(testDataObject));
testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>(2);
bool result = testSceneGraph.SetContent(testNodeIndex, testDataObject);
EXPECT_TRUE(result);
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(testNodeIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(2, storedValue->m_id);
}
TEST_F(SceneGraphTest, SetContent_ExistingNodeByMove_NewFloatConfirmed)
{
SceneGraph testSceneGraph;
AZStd::shared_ptr<DataTypes::MockIGraphObject> testDataObject = AZStd::make_shared<DataTypes::MockIGraphObject>(1);
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "testNode", AZStd::move(testDataObject));
bool result = testSceneGraph.SetContent(testNodeIndex, AZStd::make_shared<DataTypes::MockIGraphObject>(2));
EXPECT_TRUE(result);
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(testNodeIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(2, storedValue->m_id);
}
// MakeEndPoint
TEST_F(SceneGraphTest, MakeEndPoint_MarkNodeAsEndPoint_NodeIsAnEndPoint)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject");
testSceneGraph.MakeEndPoint(testNodeIndex);
EXPECT_TRUE(testSceneGraph.IsNodeEndPoint(testNodeIndex));
}
TEST_F(SceneGraphTest, MakeEndPoint_AddChildToEndPointNode_FailsToAddChild)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject");
testSceneGraph.MakeEndPoint(testNodeIndex);
testSceneGraph.AddChild(testNodeIndex, "testObject2");
EXPECT_TRUE(m_assertTriggered);
}
TEST_F(SceneGraphTest, MakeEndPoint_AddSiblingToEndPointNode_SiblingAdded)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddSibling(testSceneGraph.GetRoot(), "testObject");
testSceneGraph.MakeEndPoint(testNodeIndex);
SceneGraph::NodeIndex result = testSceneGraph.AddSibling(testNodeIndex, "testObject2");
EXPECT_TRUE(result.IsValid());
}
//GetNodeName/Data These are testing use cases that haven't been covered
TEST_F(SceneGraphTest, GetNodeName_NodeExists_ReturnsCorrectName)
{
SceneGraph testSceneGraph;
AZStd::string expectedNodeName("TestNode");
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), expectedNodeName.c_str());
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find(expectedNodeName);
ASSERT_TRUE(foundIndex.IsValid());
const SceneGraph::Name& nodeName = testSceneGraph.GetNodeName(foundIndex);
EXPECT_STREQ(expectedNodeName.c_str(), nodeName.GetPath());
EXPECT_STREQ(expectedNodeName.c_str(), nodeName.GetName());
}
TEST_F(SceneGraphTest, GetNodeName_InvalidNode_Invalid)
{
SceneGraph testSceneGraph;
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.Find("NonExistantNodeName");
const SceneGraph::Name& nodeName = testSceneGraph.GetNodeName(testNodeIndex);
EXPECT_STREQ("<Invalid>", nodeName.GetPath());
EXPECT_STREQ("<Invalid>", nodeName.GetName());
}
// Clear
TEST_F(SceneGraphTest, Clear_ClearningEmptyGraph_NoChangeToTheNodeCount)
{
SceneGraph testSceneGraph;
testSceneGraph.Clear();
EXPECT_EQ(1, testSceneGraph.GetNodeCount());
}
// IsValidName
TEST_F(SceneGraphTest, IsValidName_NullPtrPassed_ReturnsFalse)
{
EXPECT_FALSE(SceneGraph::IsValidName(nullptr));
}
TEST_F(SceneGraphTest, IsValidName_EmptyStringGiven_ReturnsFalse)
{
AZStd::string emptyString;
EXPECT_FALSE(SceneGraph::IsValidName(emptyString));
EXPECT_FALSE(SceneGraph::IsValidName(emptyString.c_str()));
}
TEST_F(SceneGraphTest, IsValidName_ValidStringGiven_ReturnsTrue)
{
AZStd::string validString = "valid";
EXPECT_TRUE(SceneGraph::IsValidName(validString));
EXPECT_TRUE(SceneGraph::IsValidName(validString.c_str()));
}
TEST_F(SceneGraphTest, IsValidName_StringContainsInvalidCharacter_ReturnsFalse)
{
AZStd::string invalidString = "inva.lid";
EXPECT_FALSE(SceneGraph::IsValidName(invalidString));
EXPECT_FALSE(SceneGraph::IsValidName(invalidString.c_str()));
}
// tests run on a prearranged, more complex configuration
class SceneGraphTests
: public ::testing::Test
{
public:
SceneGraphTests()
{
}
protected:
void SetUp()
{
/*---------------------------------------\
| Root |
| | | |
| A B |
| | /|\ |
| C I J K |
| / | \ \ |
| D E F L |
| / \ |
| G H |
\---------------------------------------*/
//Build up the graph
SceneGraph::NodeIndex testNodeIndex = testSceneGraph.AddChild(testSceneGraph.GetRoot(), "A", AZStd::make_shared<DataTypes::MockIGraphObject>(1));
SceneGraph::NodeIndex indexA = testNodeIndex;
SceneGraph::NodeIndex indexB = testSceneGraph.AddSibling(indexA, "B", AZStd::make_shared<DataTypes::MockIGraphObject>(2));
testNodeIndex = testSceneGraph.AddChild(testNodeIndex, "C", AZStd::make_shared<DataTypes::MockIGraphObject>(3));
testNodeIndex = testSceneGraph.AddChild(testNodeIndex, "D", AZStd::make_shared<DataTypes::MockIGraphObject>(4));
SceneGraph::NodeIndex EIndex = testSceneGraph.AddSibling(testNodeIndex, "E", AZStd::make_shared<DataTypes::MockIGraphObject>(5));
testNodeIndex = testSceneGraph.AddSibling(testNodeIndex, "F", AZStd::make_shared<DataTypes::MockIGraphObject>(6));
testNodeIndex = testSceneGraph.AddChild(EIndex, "G", AZStd::make_shared<DataTypes::MockIGraphObject>(7));
testNodeIndex = testSceneGraph.AddSibling(testNodeIndex, "H", AZStd::make_shared<DataTypes::MockIGraphObject>(8));
testNodeIndex = testSceneGraph.AddChild(indexB, "I", AZStd::make_shared<DataTypes::MockIGraphObject>(9));
testNodeIndex = testSceneGraph.AddChild(indexB, "J", AZStd::make_shared<DataTypes::MockIGraphObject>(10));
testNodeIndex = testSceneGraph.AddChild(indexB, "K", AZStd::make_shared<DataTypes::MockIGraphObject>(11));
testNodeIndex = testSceneGraph.AddChild(testNodeIndex, "L", AZStd::make_shared<DataTypes::MockIGraphObject>(12));
}
void TearDown()
{
}
SceneGraph testSceneGraph;
enum Constants : int
{
nodeValueA = 1,
nodeValueB = 2,
nodeValueC = 3,
nodeValueD = 4,
nodeValueE = 5,
nodeValueF = 6,
nodeValueG = 7,
nodeValueH = 8,
nodeValueI = 9,
nodeValueJ = 10,
nodeValueK = 11,
nodeValueL = 12,
totalNodeCount = 12 + 1 // +1 for the root node.
};
};
//Find's
TEST_F(SceneGraphTests, FindCharPointer_E_IsValid)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E");
EXPECT_TRUE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, FindString_E_IsValid)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find(AZStd::string("A.C.E"));
EXPECT_TRUE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, FindRootCharPointer_G_IsValid)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E");
foundIndex = testSceneGraph.Find(foundIndex, "G");
EXPECT_TRUE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, FindRootString_G_IsValid)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find(AZStd::string("A.C.E"));
foundIndex = testSceneGraph.Find(foundIndex, AZStd::string("G"));
EXPECT_TRUE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, FindRootCharPointer_Z_NotValid)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E");
foundIndex = testSceneGraph.Find(foundIndex, "Z");
EXPECT_FALSE(foundIndex.IsValid());
}
//Node Find/GetNodeData integrity
TEST_F(SceneGraphTests, GetNodeData_A_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueA, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_B_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("B");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueB, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_C_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueC, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_D_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.D");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueD, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_E_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueE, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_F_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.F");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueF, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_G_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E.G");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueG, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_H_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E.H");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueH, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_I_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("B.I");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueI, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_J_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("B.J");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueJ, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_K_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("B.K");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueK, storedValue->m_id);
}
TEST_F(SceneGraphTests, GetNodeData_L_ValidValue)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("B.K.L");
EXPECT_TRUE(foundIndex.IsValid());
AZStd::shared_ptr<DataTypes::MockIGraphObject> storedValue = azrtti_cast<DataTypes::MockIGraphObject*>(testSceneGraph.GetNodeContent(foundIndex));
ASSERT_NE(nullptr, storedValue);
EXPECT_EQ(nodeValueL, storedValue->m_id);
}
//Has Relations
TEST_F(SceneGraphTests, HasNodeSibling_GHasSibling_True)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E.G");
EXPECT_TRUE(testSceneGraph.HasNodeSibling(foundIndex));
}
TEST_F(SceneGraphTests, HasNodeSibling_HHasNoSibling_False)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E.H");
EXPECT_FALSE(testSceneGraph.HasNodeSibling(foundIndex));
}
TEST_F(SceneGraphTests, HasNodeSibling_LHasNoSibling_False)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("B.K.L");
EXPECT_FALSE(testSceneGraph.HasNodeSibling(foundIndex));
}
TEST_F(SceneGraphTests, HasNodeChild_EHasChild_True)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E");
EXPECT_TRUE(testSceneGraph.HasNodeChild(foundIndex));
}
TEST_F(SceneGraphTests, HasNodeChild_GHasNoChild_False)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E.G");
EXPECT_FALSE(testSceneGraph.HasNodeChild(foundIndex));
}
TEST_F(SceneGraphTests, HasNodeParent_GHasParent_True)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.Find("A.C.E.G");
EXPECT_TRUE(testSceneGraph.HasNodeParent(foundIndex));
}
TEST_F(SceneGraphTests, HasNodeParent_RootHasNoParent_False)
{
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetRoot();
EXPECT_FALSE(testSceneGraph.HasNodeParent(foundIndex));
}
//GetNodeRelations
TEST_F(SceneGraphTests, GetNodeParent_G_ReturnsE)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("A.C.E.G");
SceneGraph::NodeIndex targetIndex = testSceneGraph.Find("A.C.E");
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeParent(sourceIndex);
EXPECT_EQ(targetIndex, foundIndex);
}
TEST_F(SceneGraphTests, GetNodeParent_RootNoParent_NotValid)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.GetRoot();
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeParent(sourceIndex);
EXPECT_FALSE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, GetNodeSibling_GHasSibling_ReturnsH)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("A.C.E.G");
SceneGraph::NodeIndex targetIndex = testSceneGraph.Find("A.C.E.H");
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeSibling(sourceIndex);
EXPECT_EQ(targetIndex, foundIndex);
}
TEST_F(SceneGraphTests, GetNodeSibling_HEndOfList_NotValid)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("A.C.E.H");
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeSibling(sourceIndex);
EXPECT_FALSE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, GetNodeSibling_LNoSiblings_NotValid)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("B.K.L");
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeSibling(sourceIndex);
EXPECT_FALSE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, GetNodeChild_EHasChild_ReturnsG)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("A.C.E");
SceneGraph::NodeIndex targetIndex = testSceneGraph.Find("A.C.E.G");
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeChild(sourceIndex);
EXPECT_TRUE(foundIndex.IsValid());
EXPECT_EQ(targetIndex, foundIndex);
}
TEST_F(SceneGraphTests, GetNodeChild_GNoChildren_NotValid)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("A.C.E.G");
SceneGraph::NodeIndex foundIndex = testSceneGraph.GetNodeChild(sourceIndex);
EXPECT_FALSE(foundIndex.IsValid());
}
TEST_F(SceneGraphTests, GetNodeChild_ConvertToHierarchConvertToNodeIndex_ProducedIterator)
{
SceneGraph::NodeIndex sourceIndex = testSceneGraph.Find("A");
SceneGraph::HierarchyStorageConstData::iterator storageIterator = testSceneGraph.ConvertToHierarchyIterator(sourceIndex);
SceneGraph::NodeIndex nodeIndex = testSceneGraph.ConvertToNodeIndex(storageIterator);
SceneGraph::NodeIndex testIndex = sourceIndex;
EXPECT_EQ(nodeIndex, testIndex);
}
// GetNodeCount - continued
TEST_F(SceneGraphTests, GetNodeCount_GetCountOfFilledTree_ReturnsNumberOfNodes)
{
EXPECT_EQ(totalNodeCount, testSceneGraph.GetNodeCount());
}
// Clear - continued
TEST_F(SceneGraphTests, Clear_ClearFilledTree_ClearedWithDefaultAdded)
{
testSceneGraph.Clear();
EXPECT_EQ(1, testSceneGraph.GetNodeCount());
EXPECT_TRUE(testSceneGraph.GetRoot().IsValid());
EXPECT_STREQ("", testSceneGraph.GetNodeName(testSceneGraph.GetRoot()).GetPath());
EXPECT_EQ(nullptr, testSceneGraph.GetNodeContent(testSceneGraph.GetRoot()));
}
/*
The following APIs are not covered in this test implementation
inline NodeIndex ConvertToNodeIndex(HierarchyStorageConstData::iterator iterator) const;
inline NodeIndex ConvertToNodeIndex(NameStorageConstData::iterator iterator) const;
inline NodeIndex ConvertToNodeIndex(ContentStorageData::iterator iterator) const;
inline NodeIndex ConvertToNodeIndex(ContentStorageConstData::iterator iterator) const;
inline HierarchyStorageConstData GetHierarchyStorage() const;
inline NameStorageConstData GetNameStorage() const;
inline ContentStorageData GetContentStorage();
inline ContentStorageConstData GetContentStorage() const;
*/
}
}
}
@@ -0,0 +1,393 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
#include <AzCore/Serialization/Utils.h>
#include <AzFramework/FileFunc/FileFunc.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <SceneAPI/SceneCore/DataTypes/IManifestObject.h>
#include <string>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
const int BUFFER_SIZE = 64 * 1024;
static decltype(SceneManifest::s_invalidIndex) INVALID_INDEX(SceneManifest::s_invalidIndex); // gtest cannot compare static consts
class MockManifestInt : public DataTypes::IManifestObject
{
public:
AZ_RTTI(MockManifestInt, "{D6F96B49-4E6F-4EE8-A5A3-959B76F90DA8}", IManifestObject);
AZ_CLASS_ALLOCATOR(MockManifestInt, AZ::SystemAllocator, 0);
MockManifestInt()
: m_value(0)
{
}
MockManifestInt(int64_t value)
: m_value(value)
{
}
int64_t GetValue() const
{
return m_value;
}
void SetValue(int64_t value)
{
m_value = value;
}
static void Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->
Class<MockManifestInt, IManifestObject>()->
Version(1)->
Field("value", &MockManifestInt::m_value);
}
}
protected:
int64_t m_value;
};
class MockSceneManifest
: public SceneManifest
{
public:
AZ_RTTI(MockSceneManifest, "{E6B3247F-1B48-49F8-B514-18FAC77C0F94}", SceneManifest);
AZ_CLASS_ALLOCATOR(MockSceneManifest, AZ::SystemAllocator, 0);
AZ::Outcome<void, AZStd::string> LoadFromString(const AZStd::string& fileContents, SerializeContext* context, JsonRegistrationContext* registrationContext, bool loadXml = false)
{
return SceneManifest::LoadFromString(fileContents, context, registrationContext, loadXml);
}
AZ::Outcome<rapidjson::Document, AZStd::string> SaveToJsonDocument(SerializeContext* context, JsonRegistrationContext* registrationContext)
{
return SceneManifest::SaveToJsonDocument(context, registrationContext);
}
static void Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->
Class<MockSceneManifest, SceneManifest>()->
Version(1);
}
}
};
class SceneManifestTest
: public ::testing::Test
, public AZ::Debug::TraceMessageBus::Handler
{
public:
SceneManifestTest()
{
m_firstDataObject = AZStd::make_shared<MockManifestInt>(1);
m_secondDataObject = AZStd::make_shared<MockManifestInt>(2);
m_testDataObject = AZStd::make_shared<MockManifestInt>(3);
m_testManifest.AddEntry(m_firstDataObject);
m_testManifest.AddEntry(m_secondDataObject);
m_testManifest.AddEntry(m_testDataObject);
}
void SetUp() override
{
m_serializeContext = AZStd::make_unique<SerializeContext>();
m_jsonRegistrationContext = AZStd::make_unique<JsonRegistrationContext>();
m_jsonSystemComponent = AZStd::make_unique<JsonSystemComponent>();
m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get());
DataTypes::IManifestObject::Reflect(m_serializeContext.get());
MockManifestInt::Reflect(m_serializeContext.get());
SceneManifest::Reflect(m_serializeContext.get());
MockSceneManifest::Reflect(m_serializeContext.get());
BusConnect();
}
void TearDown() override
{
BusDisconnect();
m_jsonRegistrationContext->EnableRemoveReflection();
m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get());
m_jsonRegistrationContext->DisableRemoveReflection();
m_serializeContext->EnableRemoveReflection();
DataTypes::IManifestObject::Reflect(m_serializeContext.get());
MockManifestInt::Reflect(m_serializeContext.get());
SceneManifest::Reflect(m_serializeContext.get());
MockSceneManifest::Reflect(m_serializeContext.get());
m_serializeContext->DisableRemoveReflection();
m_serializeContext.reset();
m_jsonRegistrationContext.reset();
m_jsonSystemComponent.reset();
}
bool OnPreAssert(const char* /*message*/, int /*line*/, const char* /*func*/, const char* /*message*/) override
{
m_assertTriggered = true;
return true;
}
bool m_assertTriggered = false;
AZStd::shared_ptr<MockManifestInt> m_firstDataObject;
AZStd::shared_ptr<MockManifestInt> m_secondDataObject;
AZStd::shared_ptr<MockManifestInt> m_testDataObject;
MockSceneManifest m_testManifest;
AZStd::unique_ptr<SerializeContext> m_serializeContext;
AZStd::unique_ptr<JsonRegistrationContext> m_jsonRegistrationContext;
AZStd::unique_ptr<JsonSystemComponent> m_jsonSystemComponent;
};
TEST(SceneManifest, IsEmpty_Empty_True)
{
SceneManifest testManifest;
EXPECT_TRUE(testManifest.IsEmpty());
}
TEST(SceneManifest, AddEntry_AddNewValue_ResultTrue)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject = AZStd::make_shared<MockManifestInt>(100);
bool result = testManifest.AddEntry(testDataObject);
EXPECT_TRUE(result);
}
TEST(SceneManifest, AddEntry_MoveNewValue_ResultTrueAndPointerClear)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject = AZStd::make_shared<MockManifestInt>(100);
bool result = testManifest.AddEntry(AZStd::move(testDataObject));
EXPECT_TRUE(result);
EXPECT_EQ(nullptr, testDataObject.get());
}
//dependent on AddEntry
TEST(SceneManifest, IsEmpty_NotEmpty_False)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject = AZStd::make_shared<MockManifestInt>(100);
bool result = testManifest.AddEntry(AZStd::move(testDataObject));
EXPECT_FALSE(testManifest.IsEmpty());
}
//dependent on AddEntry and IsEmpty
TEST(SceneManifest, Clear_NotEmpty_EmptyTrue)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject = AZStd::make_shared<MockManifestInt>(100);
bool result = testManifest.AddEntry(AZStd::move(testDataObject));
EXPECT_FALSE(testManifest.IsEmpty());
testManifest.Clear();
EXPECT_TRUE(testManifest.IsEmpty());
}
//RemoveEntry
TEST(SceneManifest, RemoveEntry_NameInList_ResultTrueAndNotStillInList)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject = AZStd::make_shared<MockManifestInt>(1);
testManifest.AddEntry(testDataObject);
bool result = testManifest.RemoveEntry(testDataObject);
EXPECT_TRUE(result);
}
TEST_F(SceneManifestTest, RemoveEntry_NameNotInList_ResultFalse)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject = AZStd::make_shared<MockManifestInt>(1);
testManifest.RemoveEntry(testDataObject);
EXPECT_TRUE(m_assertTriggered);
}
// GetEntryCount
TEST(SceneManifest, GetEntryCount_EmptyManifest_CountIsZero)
{
SceneManifest testManifest;
EXPECT_TRUE(testManifest.IsEmpty());
EXPECT_EQ(0, testManifest.GetEntryCount());
}
TEST_F(SceneManifestTest, GetEntryCount_FilledManifest_CountIsThree)
{
EXPECT_EQ(3, m_testManifest.GetEntryCount());
}
// GetValue
TEST_F(SceneManifestTest, GetValue_ValidIndex_ReturnsInt2)
{
AZStd::shared_ptr<MockManifestInt> result = azrtti_cast<MockManifestInt*>(m_testManifest.GetValue(1));
ASSERT_TRUE(result);
EXPECT_EQ(2, result->GetValue());
}
TEST_F(SceneManifestTest, GetValue_InvalidIndex_ReturnsNullPtr)
{
EXPECT_EQ(nullptr, m_testManifest.GetValue(42));
}
// FindIndex
TEST_F(SceneManifestTest, FindIndex_ValidValue_ResultIsOne)
{
EXPECT_EQ(1, m_testManifest.FindIndex(m_secondDataObject.get()));
}
TEST_F(SceneManifestTest, FindIndex_InvalidValueFromSharedPtr_ResultIsInvalidIndex)
{
AZStd::shared_ptr<DataTypes::IManifestObject> invalid = AZStd::make_shared<MockManifestInt>(42);
EXPECT_EQ(INVALID_INDEX, m_testManifest.FindIndex(invalid.get()));
}
TEST_F(SceneManifestTest, FindIndex_InvalidValueFromNullptr_ResultIsInvalidIndex)
{
DataTypes::IManifestObject* invalid = nullptr;
EXPECT_EQ(INVALID_INDEX, m_testManifest.FindIndex(invalid));
}
// RemoveEntry - continued
TEST(SceneManifest, RemoveEntry_IndexAdjusted_IndexReduced)
{
SceneManifest testManifest;
AZStd::shared_ptr<MockManifestInt> testDataObject1 = AZStd::make_shared<MockManifestInt>(1);
AZStd::shared_ptr<MockManifestInt> testDataObject2 = AZStd::make_shared<MockManifestInt>(2);
AZStd::shared_ptr<MockManifestInt> testDataObject3 = AZStd::make_shared<MockManifestInt>(3);
testManifest.AddEntry(testDataObject1);
testManifest.AddEntry(testDataObject2);
testManifest.AddEntry(testDataObject3);
bool result = testManifest.RemoveEntry(testDataObject2);
ASSERT_TRUE(result);
EXPECT_EQ(1, azrtti_cast<MockManifestInt*>(testManifest.GetValue(0))->GetValue());
EXPECT_EQ(3, azrtti_cast<MockManifestInt*>(testManifest.GetValue(1))->GetValue());
EXPECT_EQ(0, testManifest.FindIndex(testDataObject1));
EXPECT_EQ(INVALID_INDEX, testManifest.FindIndex(testDataObject2));
EXPECT_EQ(1, testManifest.FindIndex(testDataObject3));
}
// SaveToJsonObject
TEST_F(SceneManifestTest, SaveToJsonDocument_SaveFilledManifestToString_ReturnsTrue)
{
auto result = m_testManifest.SaveToJsonDocument(m_serializeContext.get(), m_jsonRegistrationContext.get());
EXPECT_TRUE(result.IsSuccess());
}
TEST_F(SceneManifestTest, SaveToJsonDocument_SaveEmptyManifestToString_ReturnsTrue)
{
MockSceneManifest empty;
auto result = empty.SaveToJsonDocument(m_serializeContext.get(), m_jsonRegistrationContext.get());
EXPECT_TRUE(result.IsSuccess());
}
// LoadFromString
TEST_F(SceneManifestTest, LoadFromString_LoadEmptyManifestFromString_ReturnsTrue)
{
MockSceneManifest empty;
auto writeToJsonResult = empty.SaveToJsonDocument(m_serializeContext.get(), m_jsonRegistrationContext.get());
ASSERT_TRUE(writeToJsonResult.IsSuccess());
AZStd::string jsonText;
auto writeToStringResult = AzFramework::FileFunc::WriteJsonToString(writeToJsonResult.GetValue(), jsonText);
ASSERT_TRUE(writeToStringResult.IsSuccess());
MockSceneManifest loaded;
auto loadFromStringResult = loaded.LoadFromString(jsonText, m_serializeContext.get(), m_jsonRegistrationContext.get());
EXPECT_TRUE(loadFromStringResult.IsSuccess());
EXPECT_TRUE(loaded.IsEmpty());
}
TEST_F(SceneManifestTest, LoadFromString_LoadFilledManifestFromString_ReturnsTrue)
{
auto writeToJsonResult = m_testManifest.SaveToJsonDocument(m_serializeContext.get(), m_jsonRegistrationContext.get());
ASSERT_TRUE(writeToJsonResult.IsSuccess());
AZStd::string jsonText;
auto writeToStringResult = AzFramework::FileFunc::WriteJsonToString(writeToJsonResult.GetValue(), jsonText);
ASSERT_TRUE(writeToStringResult.IsSuccess());
MockSceneManifest loaded;
auto loadFromStringResult = loaded.LoadFromString(jsonText, m_serializeContext.get(), m_jsonRegistrationContext.get());
EXPECT_TRUE(loadFromStringResult.IsSuccess());
EXPECT_FALSE(loaded.IsEmpty());
ASSERT_EQ(loaded.GetEntryCount(), m_testManifest.GetEntryCount());
}
TEST_F(SceneManifestTest, LoadFromString_LoadFromXml_ObjectIdenticalToJsonLoadedObject)
{
// Write out the test Scene Manifest to XML string
char buffer[BUFFER_SIZE];
IO::MemoryStream xmlStream(IO::MemoryStream(buffer, sizeof(buffer), 0));
ASSERT_TRUE(AZ::Utils::SaveObjectToStream<SceneManifest>(xmlStream, ObjectStream::ST_XML, &m_testManifest, m_serializeContext.get()));
xmlStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
AZStd::string xmlString(buffer);
// Deserialize XML
MockSceneManifest xmlSceneManifest;
AZ::Outcome<void, AZStd::string> result = xmlSceneManifest.LoadFromString(xmlString, m_serializeContext.get(), m_jsonRegistrationContext.get(), true);
ASSERT_TRUE(result.IsSuccess());
ASSERT_FALSE(xmlSceneManifest.IsEmpty());
// Write out the test Scene Manifest to JSON string
auto writeToJsonResult = m_testManifest.SaveToJsonDocument(m_serializeContext.get(), m_jsonRegistrationContext.get());
ASSERT_TRUE(writeToJsonResult.IsSuccess());
AZStd::string jsonText;
auto writeToStringResult = AzFramework::FileFunc::WriteJsonToString(writeToJsonResult.GetValue(), jsonText);
ASSERT_TRUE(writeToStringResult.IsSuccess());
// Deserialize JSON
MockSceneManifest jsonSceneManifest;
result = jsonSceneManifest.LoadFromString(jsonText, m_serializeContext.get(), m_jsonRegistrationContext.get());
ASSERT_TRUE(result.IsSuccess());
ASSERT_FALSE(jsonSceneManifest.IsEmpty());
// Ensure both deserialized Scene Manifests are identical
ASSERT_EQ(xmlSceneManifest.GetEntryCount(), jsonSceneManifest.GetEntryCount());
}
}
}
}
@@ -0,0 +1,103 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
// Allocators are setup by the test's environment initialization since they need to be passed to another dll
using SceneTest = ::testing::Test;
TEST_F(SceneTest, Constructor_StringRef_HasCorrectName)
{
AZStd::string sampleSceneName = "testName";
Scene testScene(sampleSceneName);
EXPECT_TRUE(sampleSceneName == testScene.GetName());
}
TEST_F(SceneTest, Constructor_StringRefRef_HasCorrectName)
{
const char* sampleNameChrStar = "testName";
AZStd::string sampleSceneName = sampleNameChrStar;
Scene testScene(AZStd::move(sampleSceneName));
EXPECT_TRUE(strcmp(sampleNameChrStar, testScene.GetName().c_str()) == 0);
}
TEST_F(SceneTest, Constructor_EmptyStrRef_HasCorrectName)
{
AZStd::string sampleSceneName = "";
Scene testScene(sampleSceneName);
EXPECT_TRUE(sampleSceneName == testScene.GetName().c_str());
}
class SceneFilenameTests
: public ::testing::Test
{
public:
SceneFilenameTests()
: m_testId(Uuid::CreateString("{C9B909EE-0751-4BD7-B68B-B2C48D535396}"))
, m_testScene("testScene")
{
}
protected:
AZ::Uuid m_testId;
Scene m_testScene;
};
TEST_F(SceneFilenameTests, SetSource_StringRef_SourceFileRegistered)
{
AZStd::string testFilename = "testFilename.fbx";
m_testScene.SetSource(testFilename, m_testId);
const AZStd::string compareFilename = m_testScene.GetSourceFilename();
EXPECT_STREQ(testFilename.c_str(), compareFilename.c_str());
EXPECT_EQ(m_testId, m_testScene.GetSourceGuid());
}
TEST_F(SceneFilenameTests, SetSource_StringRefRef_SourceFileRegistered)
{
const char* testChrFilename = "testFilename.fbx";
AZStd::string testFilename = testChrFilename;
m_testScene.SetSource(AZStd::move(testFilename), m_testId);
const AZStd::string compareFilename = m_testScene.GetSourceFilename();
EXPECT_STREQ(testChrFilename, compareFilename.c_str());
EXPECT_EQ(m_testId, m_testScene.GetSourceGuid());
}
TEST_F(SceneFilenameTests, SetManifestFilename_StringRef_ManifestFileRegistered)
{
AZStd::string testFilename = "testFilename.assetinfo";
m_testScene.SetManifestFilename(testFilename);
const AZStd::string compareFilename = m_testScene.GetManifestFilename();
EXPECT_STREQ(testFilename.c_str(), compareFilename.c_str());
}
TEST_F(SceneFilenameTests, SetManifestFilename_StringRefRef_ManifestFileRegistered)
{
const char* testChrFilename = "testFilename.assetinfo";
AZStd::string testFilename = testChrFilename;
m_testScene.SetManifestFilename(AZStd::move(testFilename));
const AZStd::string compareFilename = m_testScene.GetManifestFilename();
EXPECT_STREQ(testChrFilename, compareFilename.c_str());
}
}
}
}
@@ -0,0 +1,178 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/MockIGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class FiltersTests
: public ::testing::Test
{
protected:
void SetUp() override
{
m_entries.emplace_back(AZStd::make_shared<DataTypes::MockIGraphObject>(1));
m_entries.emplace_back(AZStd::make_shared<DataTypes::MockIGraphObjectAlt>(2));
m_entries.emplace_back(AZStd::make_shared<DataTypes::MockIGraphObject>(3));
m_constEntries.emplace_back(AZStd::make_shared<const DataTypes::MockIGraphObject>(1));
m_constEntries.emplace_back(AZStd::make_shared<const DataTypes::MockIGraphObjectAlt>(2));
m_constEntries.emplace_back(AZStd::make_shared<const DataTypes::MockIGraphObject>(3));
}
AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>> m_entries;
AZStd::vector<AZStd::shared_ptr<const DataTypes::IGraphObject>> m_constEntries;
};
TEST_F(FiltersTests, MakeDerivedFilterView_FilterTypes_ListsEntryOneAndThree)
{
auto view = Containers::MakeDerivedFilterView<DataTypes::MockIGraphObject>(m_entries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeDerivedFilterView_FilterConstTypes_ListsEntryOneAndThree)
{
auto view = Containers::MakeDerivedFilterView<DataTypes::MockIGraphObject>(m_constEntries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeDerivedFilterView_ConstFilterTypes_ListsEntryOneAndThree)
{
const AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& constEntries = m_entries;
auto view = Containers::MakeDerivedFilterView<DataTypes::MockIGraphObject>(constEntries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeDerivedFilterView_ConstFilterConstTypes_ListsEntryOneAndThree)
{
const AZStd::vector<AZStd::shared_ptr<const DataTypes::IGraphObject>>& constEntries = m_constEntries;
auto view = Containers::MakeDerivedFilterView<DataTypes::MockIGraphObject>(constEntries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeDerivedFilterView_ReferenceRetrievedFromIteratorAllowsChangingValueInOriginal_ValueChangedFromOneToTen)
{
auto view = Containers::MakeDerivedFilterView<DataTypes::MockIGraphObject>(m_entries);
view.begin()->m_id = 10;
EXPECT_EQ(10, azrtti_cast<DataTypes::MockIGraphObject*>(m_entries[0])->m_id);
}
TEST_F(FiltersTests, MakeExactFilterView_FilterTypes_ListsEntryOneAndThree)
{
auto view = Containers::MakeExactFilterView<DataTypes::MockIGraphObject>(m_entries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeExactFilterView_FilterConstTypes_ListsEntryOneAndThree)
{
auto view = Containers::MakeExactFilterView<DataTypes::MockIGraphObject>(m_constEntries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeExactFilterView_ConstFilterTypes_ListsEntryOneAndThree)
{
const AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& constEntries = m_entries;
auto view = Containers::MakeExactFilterView<DataTypes::MockIGraphObject>(constEntries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeExactFilterView_ConstFilterConstTypes_ListsEntryOneAndThree)
{
const AZStd::vector<AZStd::shared_ptr<const DataTypes::IGraphObject>>& constEntries = m_constEntries;
auto view = Containers::MakeExactFilterView<DataTypes::MockIGraphObject>(constEntries);
auto it = view.begin();
EXPECT_EQ(1, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(3, it->m_id);
EXPECT_EQ(DataTypes::MockIGraphObject::TYPEINFO_Uuid(), it->RTTI_GetType());
++it;
EXPECT_EQ(view.end(), it);
}
TEST_F(FiltersTests, MakeExactFilterView_ReferenceRetrievedFromIteratorAllowsChangingValueInOriginal_ValueChangedFromOneToTen)
{
auto view = Containers::MakeExactFilterView<DataTypes::MockIGraphObject>(m_entries);
view.begin()->m_id = 10;
EXPECT_EQ(10, azrtti_cast<DataTypes::MockIGraphObject*>(m_entries[0])->m_id);
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,281 @@
/*
* 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.
*
*/
/*
* This suite of tests focus on the unique features the ConvertIterator
* adds as an iterator. The basic functionality and iterator conformity is tested
* in the Iterator Conformity Tests (see IteratorConformityTests.cpp).
*/
#include <AzTest/AzTest.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/containers/vector.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
#include <SceneAPI/SceneCore/Tests/Containers/Views/IteratorTestsBase.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
using ::testing::Const;
class MockClass
{
public:
virtual ~MockClass() = default;
MOCK_METHOD0(TestFunction, void());
MOCK_CONST_METHOD0(TestFunction, void());
};
// Google mock has problems with putting mock classes in
// containers so for those cases use a simpler mock.
class TestClass
{
public:
enum Caller
{
NotCalled,
NonConstFunction,
ConstFunction
};
void TestFunction()
{
m_calling = NonConstFunction;
}
void TestFunction() const
{
m_calling = ConstFunction;
}
mutable Caller m_calling = { NotCalled };
};
inline float ConvertIntToFloat(int& value)
{
return static_cast<float>(value);
}
inline int ConvertFloatToInt(float& value)
{
return static_cast<int>(value);
}
template<typename CollectionType>
class ConvertIteratorTests
: public IteratorTypedTestsBase<CollectionType>
{
public:
ConvertIteratorTests() = default;
~ConvertIteratorTests() override = default;
};
TYPED_TEST_CASE_P(ConvertIteratorTests);
// MakeConvertIterator
TYPED_TEST_P(ConvertIteratorTests, MakeConvertIterator_FunctionComparedWithExplicitlyDeclaredIterator_IteratorsAreEqual)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
auto lhsIterator = MakeConvertIterator(this->GetBaseIterator(0), ConvertIntToFloat);
auto rhsIterator = ConvertIterator<BaseIterator, float>(this->GetBaseIterator(0), ConvertIntToFloat);
EXPECT_EQ(lhsIterator, rhsIterator);
}
// MakeConvertView
TYPED_TEST_P(ConvertIteratorTests, MakeConvertView_IteratorVersionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
auto view = MakeConvertView(this->m_testCollection.begin(), this->m_testCollection.end(), ConvertIntToFloat);
auto begin = ConvertIterator<BaseIterator, float>(this->m_testCollection.begin(), ConvertIntToFloat);
auto end = ConvertIterator<BaseIterator, float>(this->m_testCollection.end(), ConvertIntToFloat);
EXPECT_EQ(view.begin(), begin);
EXPECT_EQ(view.end(), end);
}
TYPED_TEST_P(ConvertIteratorTests, MakeConvertView_ViewVersionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
auto sourceView = MakeView(this->m_testCollection.begin(), this->m_testCollection.end());
auto view = MakeConvertView(sourceView, ConvertIntToFloat);
auto begin = ConvertIterator<BaseIterator, float>(this->m_testCollection.begin(), ConvertIntToFloat);
auto end = ConvertIterator<BaseIterator, float>(this->m_testCollection.end(), ConvertIntToFloat);
EXPECT_EQ(view.begin(), begin);
EXPECT_EQ(view.end(), end);
}
REGISTER_TYPED_TEST_CASE_P(ConvertIteratorTests,
MakeConvertIterator_FunctionComparedWithExplicitlyDeclaredIterator_IteratorsAreEqual,
MakeConvertView_IteratorVersionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd,
MakeConvertView_ViewVersionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd
);
INSTANTIATE_TYPED_TEST_CASE_P(CommonTests, ConvertIteratorTests, BasicCollectionTypes);
// Casting
TEST(ConvertIterator, Casting_CanBetweenValueTypes_GetCastedValueAsInt)
{
AZStd::vector<float> floatValues = { 3.1415f };
auto iterator = MakeConvertIterator(floatValues.begin(), ConvertFloatToInt);
auto value = *iterator;
EXPECT_EQ(3, value);
}
const MockClass* ConvertMockToConstMock(MockClass* value)
{
return const_cast<const MockClass*>(value);
}
TEST(ConvertIterator, Casting_CanApplyConstToPointerThroughStaticFunction_ConstFunctionCalled)
{
MockClass mock;
EXPECT_CALL(Const(mock), TestFunction()).Times(1);
EXPECT_CALL(mock, TestFunction()).Times(0);
AZStd::vector<MockClass*> mocks = { &mock };
auto iterator = MakeConvertIterator(mocks.begin(), ConvertMockToConstMock);
(*iterator)->TestFunction();
}
TEST(ConvertIterator, Casting_CanApplyConstToPointerThroughLamba_ConstFunctionCalled)
{
MockClass mock;
EXPECT_CALL(Const(mock), TestFunction()).Times(1);
EXPECT_CALL(mock, TestFunction()).Times(0);
AZStd::vector<MockClass*> mocks = { &mock };
auto iterator = MakeConvertIterator(mocks.begin(),
[](MockClass* value) -> const MockClass*
{
return const_cast<const MockClass*>(value);
});
(*iterator)->TestFunction();
}
TEST(ConvertIterator, Casting_CanApplyConstToValueThroughDereference_ConstFunctionCalled)
{
TestClass test;
AZStd::vector<TestClass> tests = { test };
auto iterator = MakeConvertIterator(tests.begin(),
[](TestClass& value) -> const TestClass&
{
return value;
});
(*iterator).TestFunction();
EXPECT_EQ(TestClass::ConstFunction, tests[0].m_calling);
}
TEST(ConvertIterator, Casting_CanApplyConstToValueThroughArrowOperator_ConstFunctionCalled)
{
TestClass test;
AZStd::vector<TestClass> tests = { test };
auto iterator = MakeConvertIterator(tests.begin(),
[](TestClass& value) -> const TestClass&
{
return value;
});
iterator->TestFunction();
EXPECT_EQ(TestClass::ConstFunction, tests[0].m_calling);
}
TEST(ConvertIterator, Casting_CanApplyConstToValueThroughIndex_ConstFunctionCalled)
{
TestClass test;
AZStd::vector<TestClass> tests = { test };
auto iterator = MakeConvertIterator(tests.begin(),
[](TestClass& value) -> const TestClass&
{
return value;
});
iterator[0].TestFunction();
EXPECT_EQ(TestClass::ConstFunction, tests[0].m_calling);
}
TEST(ConvertIterator, Casting_CanApplyConstToUniquePtrValue_ConstFunctionCalled)
{
AZStd::unique_ptr<MockClass> mock(new MockClass());
EXPECT_CALL(Const(*mock), TestFunction()).Times(1);
EXPECT_CALL(*mock, TestFunction()).Times(0);
AZStd::vector<AZStd::unique_ptr<MockClass> > tests;
tests.push_back(AZStd::move(mock));
auto iterator = MakeConvertIterator(tests.begin(),
[](AZStd::unique_ptr<MockClass>& value)
-> const MockClass*
{
return value.get();
});
(*iterator)->TestFunction();
}
TEST(ConvertIterator, Casting_CanApplyConstToSharedPtr_ConstFunctionCalled)
{
AZStd::shared_ptr<MockClass> mock = AZStd::make_shared<MockClass>();
EXPECT_CALL(Const(*mock), TestFunction()).Times(1);
EXPECT_CALL(*mock, TestFunction()).Times(0);
AZStd::vector<AZStd::shared_ptr<MockClass> > tests;
tests.push_back(AZStd::move(mock));
auto iterator = MakeConvertIterator(tests.begin(),
[](AZStd::shared_ptr<MockClass>& value)
{
return AZStd::shared_ptr<const MockClass>(value);
});
(*iterator)->TestFunction();
}
// Algorithms
TEST(ConvertIterator, Algorithms_Find3_FindsFirstInstanceOf3)
{
AZStd::vector<float> values = { 8.3f, 3.1f, 4.6f, 3.3f, 9.9f, 6.1f };
auto convertView = MakeConvertView(values.begin(), values.end(), ConvertFloatToInt);
auto result = AZStd::find(convertView.begin(), convertView.end(), 3);
ASSERT_NE(convertView.end(), result);
EXPECT_EQ(3, *result);
EXPECT_EQ(1, AZStd::distance(convertView.begin(), result));
}
TEST(ConvertIterator, Algorithms_Count_ThreeInstanceOfFourAreFound)
{
AZStd::vector<float> values = { 8.3f, 4.1f, 4.6f, 4.3f, 9.9f, 6.1f };
auto convertView = MakeConvertView(values.begin(), values.end(), ConvertFloatToInt);
size_t result = AZStd::count_if(convertView.begin(), convertView.end(),
[](int value)
{
return value == 4;
});
EXPECT_EQ(3, result);
}
} // namespace Views
} // namespace Containers
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,617 @@
/*
* 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.
*
*/
#define _SCL_SECURE_NO_WARNINGS
#include <AzTest/AzTest.h>
#include <AzCore/std/createdestroy.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/iterator.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_set.h>
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Tests/Containers/Views/IteratorTestsBase.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
template<typename CollectionType>
class FilterIteratorBasicTests
: public IteratorTypedTestsBase<CollectionType>
{
public:
FilterIteratorBasicTests()
{
MakeComparePredicate(0);
}
~FilterIteratorBasicTests() override = default;
using BaseIteratorReference = typename IteratorTypedTestsBase<CollectionType>::BaseIteratorReference;
template<typename T>
void MakeComparePredicate(T compareValue)
{
m_testPredicate = [compareValue](const BaseIteratorReference value) -> bool
{
return value >= compareValue;
};
}
template<typename T>
void MakeNotEqualPredicate(T compareValue)
{
m_testPredicate = [compareValue](const BaseIteratorReference value) -> bool
{
return value != compareValue;
};
}
AZStd::function<bool(const BaseIteratorReference)> m_testPredicate;
};
TYPED_TEST_CASE_P(FilterIteratorBasicTests);
TYPED_TEST_P(FilterIteratorBasicTests,
Constructor_InputIsEmptyValidBaseIterator_NoCrash)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
FilterIterator<BaseIterator>
testIterator(this->m_testCollection.begin(), this->m_testCollection.end(),
this->m_testPredicate);
}
TYPED_TEST_P(FilterIteratorBasicTests,
Constructor_MovesForwardBasedOnPredicate_ExpectSkipFirstEntryAndReturnSecond)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
lhsIterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
EXPECT_EQ(1, *lhsIterator);
}
// Increment operator
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorPreIncrement_MoveOneUnfilteredElementUp_ReturnsTheSecondValue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
iterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
++iterator;
EXPECT_EQ(1, *iterator);
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorPreIncrement_MoveOneSkippingOne_ReturnsTheThirdValue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
iterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
++iterator;
EXPECT_EQ(2, *iterator);
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorPostIncrement_MoveOneUnfilteredElementUp_ReturnsTheSecondValue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
iterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
iterator++;
EXPECT_EQ(1, *iterator);
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorPostIncrement_MoveOneSkippingOne_ReturnsTheThirdValue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
iterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
iterator++;
EXPECT_EQ(2, *iterator);
}
// Equals equals operator
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorEqualsEquals_DifferentlyInitializedObjectsPredicatePassesAll_ReturnsFalse)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
FilterIterator<BaseIterator>
lhsIterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
FilterIterator<BaseIterator>
rhsIterator(this->GetBaseIterator(1), this->m_testCollection.end(),
this->m_testPredicate);
EXPECT_NE(lhsIterator, rhsIterator);
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorEqualsEquals_DifferentlyInitializedObjectsPredicatePassesPart_ReturnsTrue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
lhsIterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
FilterIterator<BaseIterator>
rhsIterator(this->GetBaseIterator(1), this->m_testCollection.end(),
this->m_testPredicate);
EXPECT_EQ(lhsIterator, rhsIterator);
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorEqualsEquals_SkippingAllEntriesMatchesWithEndIterator_FullySkippedIteratorIsSameAsEnd)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(3);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
FilterIterator<BaseIterator>
iterator(this->m_testCollection.begin(), this->m_testCollection.end(),
this->m_testPredicate);
FilterIterator<BaseIterator>
endIterator(this->m_testCollection.end(), this->m_testCollection.end(),
this->m_testPredicate);
EXPECT_EQ(iterator, endIterator);
}
// Not equals operator
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorNotEquals_DifferentObjects_ReturnsTrue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
FilterIterator<BaseIterator>
lhsIterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
FilterIterator<BaseIterator>
rhsIterator(this->GetBaseIterator(1), this->m_testCollection.end(),
this->m_testPredicate);
EXPECT_TRUE(lhsIterator != rhsIterator);
}
// Star operator
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorStar_GetValueByDereferencingIterator_ExpectFirstValueInArray)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
AddElement(this->m_testCollection, 0);
FilterIterator<BaseIterator>
lhsIterator(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
EXPECT_EQ(0, *lhsIterator);
}
// Decrement operator
template<typename Container, typename = typename AZStd::iterator_traits<typename Container::iterator>::iterator_category>
struct OperatorPreDecrement
{
int operator()([[maybe_unused]] FilterIteratorBasicTests<Container>& test, [[maybe_unused]] int iteratorOffset, int expectedResult)
{
return expectedResult;
}
};
template<typename Container>
struct OperatorPreDecrement<Container, AZStd::bidirectional_iterator_tag>
{
int operator()(FilterIteratorBasicTests<Container>& test, int iteratorOffset, [[maybe_unused]] int expectedResult)
{
FilterIterator<typename Container::iterator>
iterator(test.GetBaseIterator(iteratorOffset), test.m_testCollection.begin(), test.m_testCollection.end(),
test.m_testPredicate);
--iterator;
return *iterator;
};
};
template<typename Container>
struct OperatorPreDecrement<Container, AZStd::random_access_iterator_tag>
: public OperatorPreDecrement<Container, AZStd::bidirectional_iterator_tag>
{
};
template<typename Container>
struct OperatorPreDecrement<Container, AZStd::contiguous_iterator_tag>
: public OperatorPreDecrement<Container, AZStd::bidirectional_iterator_tag>
{
};
template<typename Container, typename = typename AZStd::iterator_traits<typename Container::iterator>::iterator_category>
struct OperatorPostDecrement
{
int operator()([[maybe_unused]] FilterIteratorBasicTests<Container>& test, [[maybe_unused]] int iteratorOffset, int expectedResult)
{
return expectedResult;
}
};
template<typename Container>
struct OperatorPostDecrement<Container, AZStd::bidirectional_iterator_tag>
{
int operator()(FilterIteratorBasicTests<Container>& test, int iteratorOffset, [[maybe_unused]] int expectedResult)
{
FilterIterator<typename Container::iterator>
iterator(test.GetBaseIterator(iteratorOffset), test.m_testCollection.begin(), test.m_testCollection.end(),
test.m_testPredicate);
iterator--;
return *iterator;
};
};
template<typename Container>
struct OperatorPostDecrement<Container, AZStd::random_access_iterator_tag>
: public OperatorPostDecrement<Container, AZStd::bidirectional_iterator_tag>
{
};
template<typename Container>
struct OperatorPostDecrement<Container, AZStd::contiguous_iterator_tag>
: public OperatorPostDecrement<Container, AZStd::bidirectional_iterator_tag>
{
};
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorDecrement_MoveOneUnfilteredElementDown_ReturnsTheFirstValue)
{
using CollectionType = typename IteratorTypedTestsBase<TypeParam>::CollectionType;
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
ReorderToMatchIterationWithAddition(this->m_testCollection);
EXPECT_EQ(0, OperatorPreDecrement<CollectionType>()(*this, 1, 0));
EXPECT_EQ(0, OperatorPostDecrement<CollectionType>()(*this, 1, 0));
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorDecrement_MoveOneFilteredElementDown_ReturnsTheFirstValue)
{
using CollectionType = typename IteratorTypedTestsBase<TypeParam>::CollectionType;
this->MakeNotEqualPredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
EXPECT_EQ(0, OperatorPreDecrement<CollectionType>()(*this, 2, 0));
EXPECT_EQ(0, OperatorPostDecrement<CollectionType>()(*this, 2, 0));
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorDecrement_MoveDownToLastFilteredElement_ExpectToStayOnCurrentElement)
{
using CollectionType = typename IteratorTypedTestsBase<TypeParam>::CollectionType;
this->MakeNotEqualPredicate(0);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
ReorderToMatchIterationWithAddition(this->m_testCollection);
EXPECT_EQ(1, OperatorPreDecrement<CollectionType>()(*this, 1, 1));
EXPECT_EQ(1, OperatorPostDecrement<CollectionType>()(*this, 1, 1));
}
TYPED_TEST_P(FilterIteratorBasicTests,
OperatorDecrement_MoveOneUnfilteredElementDownFromEnd_ReturnsTheSecondValue)
{
using CollectionType = typename IteratorTypedTestsBase<TypeParam>::CollectionType;
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
ReorderToMatchIterationWithAddition(this->m_testCollection);
EXPECT_EQ(1, OperatorPreDecrement<CollectionType>()(*this, 2, 1));
EXPECT_EQ(1, OperatorPostDecrement<CollectionType>()(*this, 2, 1));
}
// Filtered Elements
TYPED_TEST_P(FilterIteratorBasicTests,
MakeFilterView_InputIsIterator_CorrectFilteredElements)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(2);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
AddElement(this->m_testCollection, 3);
AZStd::unordered_set<int> expectedElements = {2, 3};
View<FilterIterator<BaseIterator> > view = MakeFilterView(this->m_testCollection.begin(), this->m_testCollection.end(),
this->m_testPredicate);
for (auto it : view)
{
if (expectedElements.find(it) != expectedElements.end())
{
expectedElements.erase(it);
}
}
EXPECT_TRUE(expectedElements.empty());
}
TYPED_TEST_P(FilterIteratorBasicTests,
MakeFilterView_InputIteratorNotStartsAtBegin_CorrectFilteredElements)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(2);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
AddElement(this->m_testCollection, 3);
ReorderToMatchIterationWithAddition(this->m_testCollection);
AZStd::unordered_set<int> expectedElements = { 2, 3 };
View<FilterIterator<BaseIterator> > view = MakeFilterView(this->GetBaseIterator(1), this->m_testCollection.end(),
this->m_testPredicate);
for (auto it : view)
{
if (expectedElements.find(it) != expectedElements.end())
{
expectedElements.erase(it);
}
}
EXPECT_TRUE(expectedElements.empty());
}
// Algorithms
TYPED_TEST_P(FilterIteratorBasicTests,
Algorithms_CopyFilteredContainer_ContainerIsCopiedWithoutFilteredValue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeNotEqualPredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
View<FilterIterator<BaseIterator> > view = MakeFilterView(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
AZStd::vector<int> target;
AZStd::copy(view.begin(), view.end(), AZStd::back_inserter(target));
ASSERT_EQ(2, target.size());
EXPECT_EQ(0, target[0]);
EXPECT_EQ(2, target[1]);
}
TYPED_TEST_P(FilterIteratorBasicTests,
Algorithms_FillFilteredContainer_AllValuesAreSetTo42ExceptFilteredValue)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeNotEqualPredicate(1);
AddElement(this->m_testCollection, 0);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
ReorderToMatchIterationWithAddition(this->m_testCollection);
View<FilterIterator<BaseIterator> > view = MakeFilterView(this->GetBaseIterator(0), this->m_testCollection.end(),
this->m_testPredicate);
AZStd::generate_n(view.begin(), 2, [](){ return 42; });
EXPECT_EQ(42, *this->GetBaseIterator(0));
EXPECT_EQ(1, *this->GetBaseIterator(1));
EXPECT_EQ(42, *this->GetBaseIterator(2));
}
TYPED_TEST_P(FilterIteratorBasicTests,
Algorithms_PartialSortCopyFilteredContainer_AllValuesLargerOrEqualThan10AreCopiedAndSorted)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(10);
AddElement(this->m_testCollection, 18);
AddElement(this->m_testCollection, 42);
AddElement(this->m_testCollection, 36);
AddElement(this->m_testCollection, 9);
AddElement(this->m_testCollection, 88);
AddElement(this->m_testCollection, 3);
AZStd::vector<int> results;
View<FilterIterator<BaseIterator> > view = MakeFilterView(this->m_testCollection.begin(), this->m_testCollection.end(), this->m_testPredicate);
AZStd::copy(view.begin(), view.end(), AZStd::back_inserter(results));
for (auto val : results)
{
EXPECT_GE(val, 10);
}
}
REGISTER_TYPED_TEST_CASE_P(FilterIteratorBasicTests,
Constructor_InputIsEmptyValidBaseIterator_NoCrash,
OperatorStar_GetValueByDereferencingIterator_ExpectFirstValueInArray,
Constructor_MovesForwardBasedOnPredicate_ExpectSkipFirstEntryAndReturnSecond,
OperatorPreIncrement_MoveOneUnfilteredElementUp_ReturnsTheSecondValue,
OperatorPreIncrement_MoveOneSkippingOne_ReturnsTheThirdValue,
OperatorPostIncrement_MoveOneUnfilteredElementUp_ReturnsTheSecondValue,
OperatorPostIncrement_MoveOneSkippingOne_ReturnsTheThirdValue,
OperatorEqualsEquals_DifferentlyInitializedObjectsPredicatePassesAll_ReturnsFalse,
OperatorEqualsEquals_DifferentlyInitializedObjectsPredicatePassesPart_ReturnsTrue,
OperatorEqualsEquals_SkippingAllEntriesMatchesWithEndIterator_FullySkippedIteratorIsSameAsEnd,
OperatorNotEquals_DifferentObjects_ReturnsTrue,
OperatorDecrement_MoveOneUnfilteredElementDown_ReturnsTheFirstValue,
OperatorDecrement_MoveOneFilteredElementDown_ReturnsTheFirstValue,
OperatorDecrement_MoveDownToLastFilteredElement_ExpectToStayOnCurrentElement,
OperatorDecrement_MoveOneUnfilteredElementDownFromEnd_ReturnsTheSecondValue,
MakeFilterView_InputIsIterator_CorrectFilteredElements,
MakeFilterView_InputIteratorNotStartsAtBegin_CorrectFilteredElements,
Algorithms_CopyFilteredContainer_ContainerIsCopiedWithoutFilteredValue,
Algorithms_FillFilteredContainer_AllValuesAreSetTo42ExceptFilteredValue,
Algorithms_PartialSortCopyFilteredContainer_AllValuesLargerOrEqualThan10AreCopiedAndSorted
);
INSTANTIATE_TYPED_TEST_CASE_P(CommonTests,
FilterIteratorBasicTests,
BasicCollectionTypes);
// Map iterator tests
template<typename CollectionType>
class FilterIteratorMapTests
: public IteratorTypedTestsBase<CollectionType>
{
public:
FilterIteratorMapTests()
{
this->MakeComparePredicate(0);
}
~FilterIteratorMapTests() override = default;
protected:
using BaseIteratorReference = typename IteratorTypedTestsBase<CollectionType>::BaseIteratorReference;
template<typename T>
void MakeComparePredicate(T compareValue)
{
m_testPredicate = [compareValue](const BaseIteratorReference value) -> bool
{
return value.first >= compareValue;
};
}
AZStd::function<bool(const BaseIteratorReference)> m_testPredicate;
};
TYPED_TEST_CASE_P(FilterIteratorMapTests);
TYPED_TEST_P(FilterIteratorMapTests,
MakeFilterView_InputIsIterator_CorrectFilteredElements)
{
using BaseIterator = typename IteratorTypedTestsBase<TypeParam>::BaseIterator;
this->MakeComparePredicate(2);
AddElement(this->m_testCollection, 1);
AddElement(this->m_testCollection, 2);
AddElement(this->m_testCollection, 3);
AZStd::unordered_set<int> expectedElements = { 2, 3 };
View<FilterIterator<BaseIterator> > view = MakeFilterView(this->m_testCollection.begin(), this->m_testCollection.end(),
this->m_testPredicate);
for (auto it : view)
{
if (expectedElements.find(it.first) != expectedElements.end())
{
expectedElements.erase(it.first);
}
}
EXPECT_TRUE(expectedElements.empty());
}
REGISTER_TYPED_TEST_CASE_P(FilterIteratorMapTests,
MakeFilterView_InputIsIterator_CorrectFilteredElements
);
INSTANTIATE_TYPED_TEST_CASE_P(CommonTests,
FilterIteratorMapTests,
MapCollectionTypes);
// Added as separate test to avoid having to write another set of specialized templates.
TEST(FilterIteratorTests, Algorithms_ReverseFilteredContainer_ValuesReversedExceptValuesLargerThan50)
{
AZStd::vector<int> values = { 18, 7, 62, 63, 14 };
View<FilterIterator<AZStd::vector<int>::iterator> > view = MakeFilterView(values.begin(), values.end(),
[](int value) -> bool
{
return value < 50;
});
AZStd::reverse(view.begin(), view.end());
EXPECT_EQ(values[0], 14);
EXPECT_EQ(values[1], 7);
EXPECT_EQ(values[2], 62);
EXPECT_EQ(values[3], 63);
EXPECT_EQ(values[4], 18);
}
}
}
}
}
#undef _SCL_SECURE_NO_WARNINGS
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,153 @@
#pragma once
/*
* 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 <AzTest/AzTest.h>
// These data structures are sufficient to test all current iterator flags
// e.g. forward, bidirectional, random_access
#include <AzCore/std/iterator.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/list.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/forward_list.h>
#include <AzCore/std/containers/unordered_map.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
template <typename Collection>
class IteratorTypedTestsBase
: public ::testing::Test
{
public:
IteratorTypedTestsBase() = default;
virtual ~IteratorTypedTestsBase() = default;
using CollectionType = Collection;
using BaseIterator = typename Collection::iterator;
using ConstBaseIterator = typename Collection::const_iterator;
using ValueType = typename Collection::value_type;
using BaseIteratorReference = typename AZStd::iterator_traits<BaseIterator>::reference;
void SetUp()
{
}
void TearDown()
{
}
ConstBaseIterator GetBaseConstIterator(size_t pos)
{
if (pos <= 0)
{
return m_testCollection.cbegin();
}
else
{
ConstBaseIterator returnIterator = m_testCollection.cbegin();
AZStd::advance(returnIterator, pos);
return returnIterator;
}
}
BaseIterator GetBaseIterator(size_t pos)
{
if (pos <= 0)
{
return m_testCollection.begin();
}
else
{
BaseIterator returnIterator = m_testCollection.begin();
AZStd::advance(returnIterator, pos);
return returnIterator;
}
}
void SetCollectionForTesting(Collection newTestCollection)
{
m_testCollection = newTestCollection;
}
Collection m_testCollection;
};
// Utility functions for building collections.
template<typename T>
void AddElement(AZStd::vector<T>& collection, T newValue)
{
collection.push_back(newValue);
}
template<typename T>
void AddElement(AZStd::list<T>& collection, T newValue)
{
collection.push_back(newValue);
}
template<typename T>
void AddElement(AZStd::forward_list<T>& collection, T newValue)
{
collection.push_front(newValue);
}
// Using key and value of same type for simplicity
template<typename T>
void AddElement(AZStd::map<T, T>& collection, T newValue)
{
collection.emplace(newValue, newValue);
}
template<typename T>
void AddElement(AZStd::unordered_map<T, T>& collection, T newValue)
{
collection[newValue] = newValue;
}
// Utility functions to provide consistency between the order elements are added
// and the order in which they are iterated.
template<typename T>
void ReorderToMatchIterationWithAddition([[maybe_unused]] AZStd::vector<T>& collection)
{
// Already doing iteration in the correct direction.
}
template<typename T>
void ReorderToMatchIterationWithAddition([[maybe_unused]] AZStd::list<T>& collection)
{
// Already doing iteration in the correct direction.
}
template<typename T>
void ReorderToMatchIterationWithAddition(AZStd::forward_list<T>& collection)
{
collection.reverse();
}
// Collection types for common groupings of tests (since different iterator tags support different APIs)
// Generic type list, for functionality supported by all iterator flags
typedef ::testing::Types<AZStd::vector<int>, AZStd::list<int>, AZStd::forward_list<int>,
AZStd::map<int, int>, AZStd::unordered_map<int, int> > GenericCollectionTypes;
typedef ::testing::Types<AZStd::vector<int>, AZStd::list<int>, AZStd::forward_list<int> > BasicCollectionTypes;
typedef ::testing::Types<AZStd::map<int, int>, AZStd::unordered_map<int, int> > MapCollectionTypes;
} // namespace Views
} // namespace Containers
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,307 @@
/*
* 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 <AzTest/AzTest.h>
#if defined(AZ_COMPILER_MSVC)
#define _SCL_SECURE_NO_WARNINGS
#include <algorithm>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/list.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/iterator.h>
#include <AzCore/std/sort.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Tests/Containers/Views/IteratorTestsBase.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
namespace Internal
{
TEST(PairIteratorCategoryTests, Declaration_SameCategory_TwoIteratorsHaveEqualCategory)
{
using Iterator = AZStd::vector<int>::iterator;
using CategoryInfo = PairIteratorCategory<Iterator, Iterator>;
EXPECT_TRUE(CategoryInfo::s_sameCategory);
EXPECT_TRUE(CategoryInfo::s_firstIteratorCategoryIsBaseOfSecondIterator);
EXPECT_TRUE(CategoryInfo::s_SecondIteratorCategoryIsBaseOfFirstIterator);
bool isSameCategory = AZStd::is_same<AZStd::iterator_traits<Iterator>::iterator_category, CategoryInfo::Category>::value;
EXPECT_TRUE(isSameCategory);
}
TEST(PairIteratorCategoryTests, Declaration_DifferentCategoryWithFirstHighest_NotTheSameCategoryAndPicksLowestCategory)
{
using IteratorHigh = AZStd::vector<int>::iterator;
using IteratorLow = AZStd::list<int>::iterator;
using CategoryInfo = PairIteratorCategory<IteratorHigh, IteratorLow>;
EXPECT_FALSE(CategoryInfo::s_sameCategory);
EXPECT_FALSE(CategoryInfo::s_firstIteratorCategoryIsBaseOfSecondIterator);
EXPECT_TRUE(CategoryInfo::s_SecondIteratorCategoryIsBaseOfFirstIterator);
bool isSameCategory = AZStd::is_same<AZStd::iterator_traits<IteratorLow>::iterator_category, CategoryInfo::Category>::value;
EXPECT_TRUE(isSameCategory);
}
TEST(PairIteratorCategoryTests, Declaration_DifferentCategoryWithFirstLowest_NotTheSameCategoryAndPicksLowestCategory)
{
using IteratorHigh = AZStd::vector<int>::iterator;
using IteratorLow = AZStd::list<int>::iterator;
using CategoryInfo = PairIteratorCategory<IteratorLow, IteratorHigh>;
EXPECT_FALSE(CategoryInfo::s_sameCategory);
EXPECT_TRUE(CategoryInfo::s_firstIteratorCategoryIsBaseOfSecondIterator);
EXPECT_FALSE(CategoryInfo::s_SecondIteratorCategoryIsBaseOfFirstIterator);
bool isSameCategory = AZStd::is_same<AZStd::iterator_traits<IteratorLow>::iterator_category, CategoryInfo::Category>::value;
EXPECT_TRUE(isSameCategory);
}
}
template<typename CollectionType>
class PairIteratorTests
: public IteratorTypedTestsBase<CollectionType>
{
public:
void AddElementPair(int first, int second)
{
AddElement(m_firstContainer, first);
AddElement(m_secondContainer, second);
}
PairIteratorTests()
{
AddElementPair(42, 88);
AddElementPair(142, 188);
}
~PairIteratorTests() override = default;
void Clear()
{
m_firstContainer.clear();
m_secondContainer.clear();
}
CollectionType m_firstContainer;
CollectionType m_secondContainer;
};
TYPED_TEST_CASE_P(PairIteratorTests);
TYPED_TEST_P(PairIteratorTests, MakePairIterator_BuildFromTwoSeparateIterators_StoredIteratorsMatchTheGivenIterators)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
EXPECT_EQ(iterator.GetFirstIterator(), this->m_firstContainer.begin());
EXPECT_EQ(iterator.GetSecondIterator(), this->m_secondContainer.begin());
}
TYPED_TEST_P(PairIteratorTests, MakePairIterator_BuildFromTwoSeparateIterators_FirstAndSecondInContainersCanBeAccessedThroughIterator)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
auto first = iterator->first;
auto second = iterator->second;
EXPECT_EQ(first, *this->m_firstContainer.begin());
EXPECT_EQ(second, *this->m_secondContainer.begin());
}
TYPED_TEST_P(PairIteratorTests, MakePairView_CreateFromIterators_IteratorsInViewMatchExplicitlyCreatedIterators)
{
auto begin = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
auto end = MakePairIterator(this->m_firstContainer.end(), this->m_secondContainer.end());
auto view = MakePairView(this->m_firstContainer.begin(), this->m_firstContainer.end(), this->m_secondContainer.begin(), this->m_secondContainer.end());
EXPECT_EQ(view.begin(), begin);
EXPECT_EQ(view.end(), end);
}
TYPED_TEST_P(PairIteratorTests, MakePairView_CreateFromViews_IteratorsInViewMatchExplicitlyCreatedIterators)
{
auto firstView = MakeView(this->m_firstContainer.begin(), this->m_firstContainer.end());
auto secondView = MakeView(this->m_secondContainer.begin(), this->m_secondContainer.end());
auto begin = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
auto end = MakePairIterator(this->m_firstContainer.end(), this->m_secondContainer.end());
auto view = MakePairView(firstView, secondView);
EXPECT_EQ(view.begin(), begin);
EXPECT_EQ(view.end(), end);
}
TYPED_TEST_P(PairIteratorTests, OperatorStar_DereferencingChangesFirst_FirstChangeIsPassedToContainer)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
(*iterator).first = 4;
EXPECT_EQ(4, *this->m_firstContainer.begin());
}
TYPED_TEST_P(PairIteratorTests, OperatorStar_DereferencingChangesSecond_SecondsChangeIsPassedToContainer)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
(*iterator).second = 4;
EXPECT_EQ(4, *this->m_secondContainer.begin());
}
TYPED_TEST_P(PairIteratorTests, OperatorArrow_DereferencingChangesFirst_FirstChangeIsPassedToContainer)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
iterator->first = 4;
EXPECT_EQ(4, *this->m_firstContainer.begin());
}
TYPED_TEST_P(PairIteratorTests, OperatorArrow_DereferencingChangesSecond_SecondsChangeIsPassedToContainer)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
iterator->second = 4;
EXPECT_EQ(4, *this->m_secondContainer.begin());
}
TYPED_TEST_P(PairIteratorTests, PreIncrementOperator_IncrementingMovesBothIterators_BothStoredIteratorsMoved)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
++iterator;
auto cmpFirst = this->m_firstContainer.begin();
auto cmpSecond = this->m_secondContainer.begin();
++cmpFirst;
++cmpSecond;
EXPECT_EQ(iterator.GetFirstIterator(), cmpFirst);
EXPECT_EQ(iterator.GetSecondIterator(), cmpSecond);
}
TYPED_TEST_P(PairIteratorTests, PostIncrementOperator_IncrementingMovesBothIterators_BothStoredIteratorsMoved)
{
auto iterator = MakePairIterator(this->m_firstContainer.begin(), this->m_secondContainer.begin());
iterator++;
auto cmpFirst = this->m_firstContainer.begin();
auto cmpSecond = this->m_secondContainer.begin();
++cmpFirst;
++cmpSecond;
EXPECT_EQ(iterator.GetFirstIterator(), cmpFirst);
EXPECT_EQ(iterator.GetSecondIterator(), cmpSecond);
}
TYPED_TEST_P(PairIteratorTests, Algorithms_Generate_FirstContainerFilledWithTheFirstAndSecondContainerFilledWithSecondInGivenPair)
{
this->Clear();
this->m_firstContainer.resize(10);
this->m_secondContainer.resize(10);
auto view = MakePairView(this->m_firstContainer.begin(), this->m_firstContainer.end(), this->m_secondContainer.begin(), this->m_secondContainer.end());
AZStd::generate(view.begin(), view.end(),
[]() -> AZStd::pair<int, int>
{
return AZStd::make_pair(3, 9);
});
for (auto it : this->m_firstContainer)
{
EXPECT_EQ(3, it);
}
for (auto it : this->m_secondContainer)
{
EXPECT_EQ(9, it);
}
}
REGISTER_TYPED_TEST_CASE_P(PairIteratorTests,
MakePairIterator_BuildFromTwoSeparateIterators_StoredIteratorsMatchTheGivenIterators,
MakePairIterator_BuildFromTwoSeparateIterators_FirstAndSecondInContainersCanBeAccessedThroughIterator,
MakePairView_CreateFromIterators_IteratorsInViewMatchExplicitlyCreatedIterators,
MakePairView_CreateFromViews_IteratorsInViewMatchExplicitlyCreatedIterators,
OperatorStar_DereferencingChangesFirst_FirstChangeIsPassedToContainer,
OperatorStar_DereferencingChangesSecond_SecondsChangeIsPassedToContainer,
OperatorArrow_DereferencingChangesFirst_FirstChangeIsPassedToContainer,
OperatorArrow_DereferencingChangesSecond_SecondsChangeIsPassedToContainer,
PreIncrementOperator_IncrementingMovesBothIterators_BothStoredIteratorsMoved,
PostIncrementOperator_IncrementingMovesBothIterators_BothStoredIteratorsMoved,
Algorithms_Generate_FirstContainerFilledWithTheFirstAndSecondContainerFilledWithSecondInGivenPair);
INSTANTIATE_TYPED_TEST_CASE_P(CommonTests, PairIteratorTests, BasicCollectionTypes);
// The following tests are done as standalone tests as not all iterators support this functionality
TEST(PairIteratorTest, PreDecrementIterator_DecrementingMovesBothIterators_BothStoredIteratorsMoved)
{
AZStd::vector<int> firstContainer = { 42, 142 };
AZStd::vector<int> secondContainer = { 88, 188 };
auto iterator = MakePairIterator(firstContainer.begin(), secondContainer.begin());
++iterator;
--iterator;
EXPECT_EQ(iterator.GetFirstIterator(), firstContainer.begin());
EXPECT_EQ(iterator.GetSecondIterator(), secondContainer.begin());
}
TEST(PairIteratorTest, PostDecrementIterator_DecrementingMovesBothIterators_BothStoredIteratorsMoved)
{
AZStd::vector<int> firstContainer = { 42, 142 };
AZStd::vector<int> secondContainer = { 88, 188 };
auto iterator = MakePairIterator(firstContainer.begin(), secondContainer.begin());
++iterator;
iterator--;
EXPECT_EQ(iterator.GetFirstIterator(), firstContainer.begin());
EXPECT_EQ(iterator.GetSecondIterator(), secondContainer.begin());
}
TEST(PairIteratorTest, Algorithms_Sort_BothListSortedByFirstThenSecondAndPairsNotBroken)
{
AZStd::vector<int> firstContainer = { 105, 106, 101, 104, 103, 108 };
AZStd::vector<int> secondContainer = { 205, 206, 201, 204, 203, 208 };
auto view = MakePairView(firstContainer.begin(), firstContainer.end(), secondContainer.begin(), secondContainer.end());
AZStd::sort(view.begin(), view.end());
EXPECT_EQ((*view.begin()).first + 100, (*view.begin()).second);
for (auto it = view.begin() + 1; it != view.end(); ++it)
{
auto previousIt = it - 1;
EXPECT_LT((*previousIt).first, (*it).first);
EXPECT_EQ((*it).first + 100, (*it).second);
}
}
TEST(PairIteratorTest, Algorithms_Reverse_SecondssAreInDescendingOrder)
{
AZStd::vector<int> firstContainer = { 1, 2, 3, 4, 5 };
AZStd::vector<int> secondContainer = { 1, 2, 3, 4, 5 };
auto view = MakePairView(firstContainer.begin(), firstContainer.end(), secondContainer.begin(), secondContainer.end());
AZStd::reverse(view.begin(), view.end());
for (auto it = view.begin() + 1; it != view.end(); ++it)
{
auto previousIt = it - 1;
EXPECT_GT(*previousIt, *it);
}
}
} // Views
} // Containers
} // SceneAPI
} // AZ
#undef _SCL_SECURE_NO_WARNINGS
#endif // AZ_COMPILER_MSVC
@@ -0,0 +1,292 @@
/*
* 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.
*
*/
/*
* This suite of tests focus on the unique features the SceneGraphUpwardsIterator
* adds as an iterator. The basic functionality and iterator conformity is tested
* in the Iterator Conformity Tests (see IteratorConformityTests.cpp).
*/
#include <AzTest/AzTest.h>
#include <algorithm>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/MockIGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
class SceneGraphChildIteratorTest
: public ::testing::Test
{
public:
void SetUp()
{
/*---------------------------------------\
| Root |
| | |
| A |
| / | \ |
| B C D |
| / \ |
| E F |
\---------------------------------------*/
//Build up the graph
SceneGraph::NodeIndex root = m_graph.GetRoot();
m_graph.SetContent(root, AZStd::make_shared<DataTypes::MockIGraphObject>(0));
SceneGraph::NodeIndex indexA = m_graph.AddChild(root, "A", AZStd::make_shared<DataTypes::MockIGraphObject>(1));
SceneGraph::NodeIndex indexB = m_graph.AddChild(indexA, "B", AZStd::make_shared<DataTypes::MockIGraphObject>(2));
SceneGraph::NodeIndex indexC = m_graph.AddSibling(indexB, "C", AZStd::make_shared<DataTypes::MockIGraphObject>(3));
SceneGraph::NodeIndex indexD = m_graph.AddSibling(indexC, "D", AZStd::make_shared<DataTypes::MockIGraphObject>(4));
SceneGraph::NodeIndex indexE = m_graph.AddChild(indexC, "E", AZStd::make_shared<DataTypes::MockIGraphObject>(5));
m_graph.AddSibling(indexE, "F", AZStd::make_shared<DataTypes::MockIGraphObject>(6));
m_graph.MakeEndPoint(indexB);
m_graph.MakeEndPoint(indexD);
}
SceneGraph::HierarchyStorageConstData::iterator GetHierarchyNodeA()
{
SceneGraph::NodeIndex index = m_graph.Find("A");
return m_graph.ConvertToHierarchyIterator(index);
}
SceneGraph m_graph;
};
TEST_F(SceneGraphChildIteratorTest, MakeSceneGraphChildIterator_UtilityFunctionProducesSameIteratorAsExplicitlyDeclared_IteratorsAreEqual)
{
auto lhsIterator = MakeSceneGraphChildIterator(m_graph, m_graph.Find("A"), m_graph.GetNameStorage().begin(), true);
auto rhsIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator>(m_graph, GetHierarchyNodeA(), m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(lhsIterator, rhsIterator);
}
TEST_F(SceneGraphChildIteratorTest, MakeSceneGraphChildIterator_NodeAndHierarchyVersions_IteratorsAreIdentical)
{
SceneGraph::NodeIndex index = m_graph.Find("A");
auto hierarchy = m_graph.ConvertToHierarchyIterator(index);
auto indexIterator = MakeSceneGraphChildIterator(m_graph, index, m_graph.GetNameStorage().begin(), true);
auto hierarchyIterator = MakeSceneGraphChildIterator(m_graph, hierarchy, m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(indexIterator, hierarchyIterator);
}
TEST_F(SceneGraphChildIteratorTest, MakeSceneGraphChildIterator_ConstructingFromNodeWithoutChildren_ReturnsEndIterator)
{
auto iterator = MakeSceneGraphChildIterator(m_graph, m_graph.Find("A.C.E"), m_graph.GetNameStorage().begin(), true);
auto endIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator>();
EXPECT_EQ(iterator, endIterator);
}
TEST_F(SceneGraphChildIteratorTest, MakeSceneGraphChildView_UtilityFunctionProducesSameIteratorAsExplicitlyDeclared_IteratorsAreEqual)
{
SceneGraph::NodeIndex index = m_graph.Find("A");
auto hierarchy = m_graph.ConvertToHierarchyIterator(index);
auto view = MakeSceneGraphChildView(m_graph, hierarchy, m_graph.GetNameStorage().begin(), true);
auto beginIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator>(m_graph, hierarchy, m_graph.GetNameStorage().begin(), true);
auto endIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator>();
EXPECT_EQ(view.begin(), beginIterator);
EXPECT_EQ(view.end(), endIterator);
}
TEST_F(SceneGraphChildIteratorTest, MakeSceneGraphChildView_NodeAndHierarchyVersions_IteratorsAreIdentical)
{
SceneGraph::NodeIndex index = m_graph.Find("A");
auto hierarchy = m_graph.ConvertToHierarchyIterator(index);
auto indexView = MakeSceneGraphChildView(m_graph, index, m_graph.GetNameStorage().begin(), true);
auto hierarchyView = MakeSceneGraphChildView(m_graph, hierarchy, m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(indexView.begin(), hierarchyView.begin());
EXPECT_EQ(indexView.end(), hierarchyView.end());
}
TEST_F(SceneGraphChildIteratorTest, EmptyGraph_CanDetectEmptyGraph_BeginAndEndIteratorAreEqual)
{
SceneGraph emptyGraph;
auto beginIterator = MakeSceneGraphChildIterator(emptyGraph, emptyGraph.GetHierarchyStorage().begin(), emptyGraph.GetNameStorage().begin(), true);
auto endIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator>();
EXPECT_EQ(beginIterator, endIterator);
}
TEST_F(SceneGraphChildIteratorTest, EmptyGraph_CanDetectEmptyGraphFromView_BeginAndEndIteratorAreEqual)
{
SceneGraph emptyGraph;
auto view = MakeSceneGraphChildView(emptyGraph, emptyGraph.GetHierarchyStorage().begin(), emptyGraph.GetNameStorage().begin(), true);
EXPECT_EQ(view.begin(), view.end());
}
TEST_F(SceneGraphChildIteratorTest, Dereference_DereferencingThroughStarAndArrowOperator_ValuesAreEqual)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphChildIterator(m_graph, m_graph.Find("A"), valueIterator, true);
EXPECT_STREQ(iterator->GetPath(), (*iterator).GetPath());
}
TEST_F(SceneGraphChildIteratorTest, IncrementOperator_ListAllChildren_IteratorGivesAllChildNodes)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphChildIterator(m_graph, m_graph.Find("A"), valueIterator, true);
EXPECT_STREQ("A.B", iterator->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
EXPECT_STREQ("A.D", (++iterator)->GetPath());
}
TEST_F(SceneGraphChildIteratorTest, Dereference_ProvidedIteratorMovedToFirstChildIfRootIterator_ReturnedFirstChildName)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphChildIterator(m_graph, m_graph.Find("A.C"), valueIterator, true);
EXPECT_STREQ("A.C.E", (*iterator).GetPath());
}
TEST_F(SceneGraphChildIteratorTest, Dereference_ProvidedIteratorMovedToFirstChildIfNotRootIterator_ReturnedFirstChildName)
{
SceneGraph::NodeIndex index = m_graph.Find("A.C");
ASSERT_TRUE(index.IsValid()); // Name has been entered in the graph so should be found.
auto valueIterator = m_graph.ConvertToNameIterator(index);
ASSERT_NE(m_graph.GetNameStorage().end(), valueIterator); // Correct iterator should be found.
auto iterator = MakeSceneGraphChildIterator(m_graph, index, valueIterator, false);
EXPECT_STREQ("A.C.E", (*iterator).GetPath());
}
TEST_F(SceneGraphChildIteratorTest, IncrementOperator_MovedPastLastChild_ReturnsEndIterator)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphChildIterator(m_graph, m_graph.Find("A"), valueIterator, true);
++iterator; // A.B
++iterator; // A.C
++iterator; // A.D
EXPECT_EQ(SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator>(), iterator);
}
TEST_F(SceneGraphChildIteratorTest, IncrementOperator_ListNodesChildren_IteratorGivesCOnly)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphChildIterator<AcceptNodesOnly>(m_graph, m_graph.Find("A"), valueIterator, true);
auto endIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator, AcceptNodesOnly>();
EXPECT_STREQ("A.C", iterator->GetPath());
EXPECT_EQ(endIterator, ++iterator);
}
TEST_F(SceneGraphChildIteratorTest, IncrementOperator_ListEndPoint_IteratorGivesBandD)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphChildIterator<AcceptEndPointsOnly>(m_graph, m_graph.Find("A"), valueIterator, true);
auto endIterator = SceneGraphChildIterator<SceneGraph::NameStorage::const_iterator, AcceptEndPointsOnly>();
EXPECT_STREQ("A.B", iterator->GetPath());
EXPECT_STREQ("A.D", (++iterator)->GetPath());
EXPECT_EQ(endIterator, ++iterator);
}
TEST_F(SceneGraphChildIteratorTest, ValueIterator_NonSceneGraphIterator_ExternalIteratorValuesMatchSceneGraphValues)
{
// Commonly containers in the scene graph will be used, but it is possible to specify other containers that shadow
// the scene graph but don't belong to it. This test checks if this works correctly by comparing the values
// stored in the scene graph with the same values stored in an external container.
// (See constructor of SceneGraphChildIterator for more details on arguments.)
AZStd::vector<int> values = { 0, 1, 2, 3, 4, 5, 6 };
auto sceneView = MakeSceneGraphChildView(m_graph, m_graph.Find("A"), m_graph.GetContentStorage().begin(), true);
auto valuesView = MakeSceneGraphChildView(m_graph, m_graph.Find("A"), values.begin(), true);
auto sceneIterator = sceneView.begin();
auto valuesIterator = valuesView.begin();
while (sceneIterator != sceneView.end())
{
EXPECT_NE(valuesView.end(), valuesIterator);
DataTypes::MockIGraphObject* stored = azrtti_cast<DataTypes::MockIGraphObject*>(sceneIterator->get());
ASSERT_NE(stored, nullptr);
EXPECT_EQ(stored->m_id, *valuesIterator);
valuesIterator++;
sceneIterator++;
}
}
TEST_F(SceneGraphChildIteratorTest, Algorithms_RangedForLoop_AllChildNodesTouchedAndExitingLoop)
{
AZStd::vector<const char*> expectedName =
{
"A.B",
"A.C",
"A.D"
};
size_t index = 0;
auto sceneView = MakeSceneGraphChildView(m_graph, m_graph.Find("A"), m_graph.GetNameStorage().begin(), true);
for (auto& it : sceneView)
{
ASSERT_LT(index, expectedName.size());
EXPECT_STREQ(expectedName[index], it.GetPath());
index++;
}
EXPECT_EQ(expectedName.size(), index);
}
TEST_F(SceneGraphChildIteratorTest, Algorithms_Find_AlgorithmFindsRequestedName)
{
auto sceneView = MakeSceneGraphChildView(m_graph, m_graph.Find("A"), m_graph.GetNameStorage().begin(), true);
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> const char*
{
return name.GetPath();
});
// Needs AZStd::string for comparing otherwise two pointers will be compared instead of string content.
auto result = AZStd::find(convertView.begin(), convertView.end(), AZStd::string("A.C"));
auto compare = m_graph.ConvertToHierarchyIterator(m_graph.Find("A.C"));
EXPECT_EQ(compare, result.GetBaseIterator().GetHierarchyIterator());
}
TEST_F(SceneGraphChildIteratorTest, Algorithms_Copy_AllValuesCopiedToNewArray)
{
AZStd::vector<AZStd::string> names(3);
auto sceneView = MakeSceneGraphChildView(m_graph, m_graph.Find("A"), m_graph.GetNameStorage().begin(), true);
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> const char*
{
return name.GetPath();
});
AZStd::copy(convertView.begin(), convertView.end(), names.begin());
EXPECT_STREQ("A.B", names[0].c_str());
EXPECT_STREQ("A.C", names[1].c_str());
EXPECT_STREQ("A.D", names[2].c_str());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,555 @@
/*
* 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.
*
*/
/*
* This suite of tests focus on the unique features the SceneGraphDownwardsIterator
* adds as an iterator. The basic functionality and iterator conformity is tested
* in the Iterator Conformity Tests (see IteratorConformityTests.cpp).
*/
#include <AzTest/AzTest.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/MockIGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
class SceneGraphDownwardsIteratorTest
: public ::testing::Test
{
public:
virtual ~SceneGraphDownwardsIteratorTest() = default;
void SetUp()
{
/*---------------------------------------\
| Root |
| | |
| A |
| / | \ |
| B C D |
| / \ |
| E F |
\---------------------------------------*/
//Build up the graph
SceneGraph::NodeIndex root = m_graph.GetRoot();
m_graph.SetContent(root, AZStd::make_shared<DataTypes::MockIGraphObject>(0));
SceneGraph::NodeIndex indexA = m_graph.AddChild(root, "A", AZStd::make_shared<DataTypes::MockIGraphObject>(1));
SceneGraph::NodeIndex indexB = m_graph.AddChild(indexA, "B", AZStd::make_shared<DataTypes::MockIGraphObject>(2));
SceneGraph::NodeIndex indexC = m_graph.AddSibling(indexB, "C", AZStd::make_shared<DataTypes::MockIGraphObject>(3));
m_graph.AddSibling(indexC, "D", AZStd::make_shared<DataTypes::MockIGraphObject>(4));
SceneGraph::NodeIndex indexE = m_graph.AddChild(indexC, "E", AZStd::make_shared<DataTypes::MockIGraphObject>(5));
m_graph.AddSibling(indexE, "F", AZStd::make_shared<DataTypes::MockIGraphObject>(6));
}
SceneGraph::HierarchyStorageConstData::iterator GetRootHierarchyIterator()
{
return m_graph.ConvertToHierarchyIterator(m_graph.GetRoot());
}
SceneGraph::HierarchyStorageConstData::iterator GetDeepestHierarchyIterator()
{
SceneGraph::NodeIndex index = m_graph.Find("A.C.F");
return m_graph.ConvertToHierarchyIterator(index);
}
SceneGraph m_graph;
};
template<typename T>
class SceneGraphDownwardsIteratorContext
: public SceneGraphDownwardsIteratorTest
{
public:
using Traversal = T;
};
TYPED_TEST_CASE_P(SceneGraphDownwardsIteratorContext);
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, MakeSceneGraphDownwardsIterator_FunctionComparedWithExplicitlyDeclaredIterator_IteratorsAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto lhsIterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->m_graph.GetNameStorage().begin());
auto rhsIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_EQ(lhsIterator, rhsIterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, MakeSceneGraphDownwardsIterator_ExtendedFunctionComparedWithExplicitlyDeclaredIterator_IteratorsAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto lhsIterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
auto rhsIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(lhsIterator, rhsIterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, MakeSceneGraphDownwardsIterator_NodeAndHierarchyVersions_IteratorsAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
SceneGraph::NodeIndex index = this->m_graph.Find("A.C");
auto hierarchy = this->m_graph.ConvertToHierarchyIterator(index);
auto indexIterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, index, this->m_graph.GetNameStorage().begin(), true);
auto hierarchyIterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, hierarchy, this->m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(indexIterator, hierarchyIterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, MakeSceneGraphDownwardsView_FunctionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto view = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->m_graph.GetNameStorage().begin());
auto beginIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>(this->m_graph, this->m_graph.GetNameStorage().begin());
auto endIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>();
EXPECT_EQ(view.begin(), beginIterator);
EXPECT_EQ(view.end(), endIterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, MakeSceneGraphDownwardsView_ExtendedFunctionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto view = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
auto beginIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
auto endIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>();
EXPECT_EQ(view.begin(), beginIterator);
EXPECT_EQ(view.end(), endIterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, MakeSceneGraphDownwardsView_NodeAndHierarchyVersions_IteratorsInViewsAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
SceneGraph::NodeIndex index = this->m_graph.Find("A.C");
auto hierarchy = this->m_graph.ConvertToHierarchyIterator(index);
auto indexView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, index, this->m_graph.GetNameStorage().begin(), true);
auto hierarchyView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, hierarchy, this->m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(indexView.begin(), hierarchyView.begin());
EXPECT_EQ(indexView.end(), hierarchyView.end());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Dereference_GetRootIteratorValue_ReturnsRelativeValueFromGivenValueIterator)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
EXPECT_STREQ("", (*iterator).GetPath());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Dereference_GetDeepestIteratorValue_ReturnsRelativeValueFromGivenValueIterator)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetDeepestHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
EXPECT_STREQ("A.C.F", (*iterator).GetPath());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Dereference_ValueIteratorNotSyncedWithHierarchyIteratorIfNotRequested_ReturnedValueMatchesOriginalValueIterator)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto valueIterator = this->m_graph.GetNameStorage().begin() + 2;
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetDeepestHierarchyIterator(), valueIterator, false);
EXPECT_STREQ((*valueIterator).GetPath(), (*iterator).GetPath());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Dereference_DereferencingThroughStarAndArrowOperator_ValuesAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto valueIterator = this->m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetDeepestHierarchyIterator(), valueIterator, true);
EXPECT_STREQ(iterator->GetPath(), (*iterator).GetPath());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, IncrementOperator_MovePastEnd_ReturnsEndIterator)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto valueIterator = this->m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetDeepestHierarchyIterator(), valueIterator, true);
iterator++;
auto endIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>();
EXPECT_EQ(endIterator, iterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, GetHierarchyIterator_MatchesWithNodeInformationAfterMove_NameEqualToNodeIndexedName)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto valueIterator = this->m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetRootHierarchyIterator(), valueIterator, true);
iterator++;
SceneGraph::HierarchyStorageConstIterator hierarchyIterator = iterator.GetHierarchyIterator();
SceneGraph::NodeIndex index = this->m_graph.ConvertToNodeIndex(hierarchyIterator);
EXPECT_STREQ(this->m_graph.GetNodeName(index).GetPath(), iterator->GetPath());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, GetHierarchyIterator_MovePastEnd_GetEmptyDefaultNode)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto valueIterator = this->m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphDownwardsIterator<Traversal>(this->m_graph, this->GetDeepestHierarchyIterator(), valueIterator, true);
iterator++;
SceneGraph::HierarchyStorageConstIterator hierarchyIterator = iterator.GetHierarchyIterator();
EXPECT_EQ(hierarchyIterator, SceneGraph::HierarchyStorageConstIterator());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, EmptyGraph_CanDetectEmptyGraph_BeginPlusOneAndEndIteratorAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
SceneGraph emptyGraph;
auto beginIterator = MakeSceneGraphDownwardsIterator<Traversal>(emptyGraph, emptyGraph.GetHierarchyStorage().begin(), emptyGraph.GetNameStorage().begin(), true);
beginIterator++; // Even an empty graph will have at least a root entry.
auto endIterator = SceneGraphDownwardsIterator<SceneGraph::NameStorage::const_iterator, Traversal>();
EXPECT_EQ(beginIterator, endIterator);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, EmptyGraph_CanDetectEmptyGraphFromView_BeginPlusOneAndEndIteratorAreEqual)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
SceneGraph emptyGraph;
auto view = MakeSceneGraphDownwardsView<Traversal>(emptyGraph, emptyGraph.GetHierarchyStorage().begin(), emptyGraph.GetNameStorage().begin(), true);
EXPECT_EQ(++view.begin(), view.end());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Algorithm_RangeForLoop_CanSuccesfullyRun)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto sceneView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
for (auto& it : sceneView)
{
}
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, IncrementOperator_TouchesAllNodes_NumberOfIterationStepsMatchesNumberOfNodesInGraph)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
size_t entryCount = this->m_graph.GetHierarchyStorage().end() - this->m_graph.GetHierarchyStorage().begin();
size_t localCount = 0;
auto sceneView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->GetRootHierarchyIterator(), this->m_graph.GetNameStorage().begin(), true);
for (auto& it : sceneView)
{
localCount++;
}
EXPECT_EQ(entryCount, localCount);
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, ValueIterator_NonSceneGraphIterator_ExternalIteratorValuesMatchSceneGraphValues)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
// Commonly containers in the scene graph will be used, but it is possible to specify other containers that shadow
// the scene graph but don't belong to it. This test checks if this works correctly by comparing the values
// stored in the scene graph with the same values stored in an external container.
// (See constructor of SceneGraphUpwardsIterator for more details on arguments.)
AZStd::vector<int> values = { 0, 1, 2, 3, 4, 5, 6 };
auto sceneView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->m_graph.GetContentStorage().begin());
auto valuesView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, values.begin());
auto sceneIterator = sceneView.begin();
auto valuesIterator = valuesView.begin();
while (sceneIterator != sceneView.end())
{
EXPECT_NE(valuesView.end(), valuesIterator);
DataTypes::MockIGraphObject* stored = azrtti_cast<DataTypes::MockIGraphObject*>(sceneIterator->get());
ASSERT_NE(stored, nullptr);
EXPECT_EQ(stored->m_id, *valuesIterator);
valuesIterator++;
sceneIterator++;
}
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Algorithms_Find_AlgorithmFindsRequestedName)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
auto sceneView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->m_graph.GetNameStorage().begin());
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> const char*
{
return name.GetPath();
});
// Needs AZStd::string for comparing otherwise two pointers will be compared instead of string content.
auto result = AZStd::find(convertView.begin(), convertView.end(), AZStd::string("A.C"));
auto compare = this->m_graph.ConvertToHierarchyIterator(this->m_graph.Find("A.C"));
EXPECT_EQ(compare, result.GetBaseIterator().GetHierarchyIterator());
}
TYPED_TEST_P(SceneGraphDownwardsIteratorContext, Algorithms_FindIf_FindsValue3InNodeAdotC)
{
using Traversal = typename SceneGraphDownwardsIteratorContext<TypeParam>::Traversal;
SceneGraph::NodeIndex index = this->m_graph.Find("A.C");
auto sceneView = MakeSceneGraphDownwardsView<Traversal>(this->m_graph, this->m_graph.GetContentStorage().begin());
auto result = AZStd::find_if(sceneView.begin(), sceneView.end(),
[](const AZStd::shared_ptr<DataTypes::IGraphObject>& object) -> bool
{
const DataTypes::MockIGraphObject* value = azrtti_cast<const DataTypes::MockIGraphObject*>(object.get());
return value && value->m_id == 3;
});
ASSERT_NE(sceneView.end(), result);
const DataTypes::MockIGraphObject* value = azrtti_cast<const DataTypes::MockIGraphObject*>(result->get());
ASSERT_NE(nullptr, value);
EXPECT_EQ(3, value->m_id);
}
REGISTER_TYPED_TEST_CASE_P(SceneGraphDownwardsIteratorContext,
MakeSceneGraphDownwardsIterator_FunctionComparedWithExplicitlyDeclaredIterator_IteratorsAreEqual,
MakeSceneGraphDownwardsIterator_ExtendedFunctionComparedWithExplicitlyDeclaredIterator_IteratorsAreEqual,
MakeSceneGraphDownwardsIterator_NodeAndHierarchyVersions_IteratorsAreEqual,
MakeSceneGraphDownwardsView_FunctionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd,
MakeSceneGraphDownwardsView_ExtendedFunctionComparedWithExplicitlyDeclaredIterators_ViewHasEquivalentBeginAndEnd,
MakeSceneGraphDownwardsView_NodeAndHierarchyVersions_IteratorsInViewsAreEqual,
Dereference_GetRootIteratorValue_ReturnsRelativeValueFromGivenValueIterator,
Dereference_GetDeepestIteratorValue_ReturnsRelativeValueFromGivenValueIterator,
Dereference_ValueIteratorNotSyncedWithHierarchyIteratorIfNotRequested_ReturnedValueMatchesOriginalValueIterator,
Dereference_DereferencingThroughStarAndArrowOperator_ValuesAreEqual,
IncrementOperator_MovePastEnd_ReturnsEndIterator,
GetHierarchyIterator_MatchesWithNodeInformationAfterMove_NameEqualToNodeIndexedName,
GetHierarchyIterator_MovePastEnd_GetEmptyDefaultNode,
EmptyGraph_CanDetectEmptyGraph_BeginPlusOneAndEndIteratorAreEqual,
EmptyGraph_CanDetectEmptyGraphFromView_BeginPlusOneAndEndIteratorAreEqual,
Algorithm_RangeForLoop_CanSuccesfullyRun,
IncrementOperator_TouchesAllNodes_NumberOfIterationStepsMatchesNumberOfNodesInGraph,
ValueIterator_NonSceneGraphIterator_ExternalIteratorValuesMatchSceneGraphValues,
Algorithms_Find_AlgorithmFindsRequestedName,
Algorithms_FindIf_FindsValue3InNodeAdotC
);
using Group = ::testing::Types<DepthFirst, BreadthFirst>;
INSTANTIATE_TYPED_TEST_CASE_P(SceneGraphDownwardsIteratorTests, SceneGraphDownwardsIteratorContext, Group);
TEST_F(SceneGraphDownwardsIteratorTest, DepthFirst_IncrementOperator_MoveDownTheTree_IteratorReturnsParentOfPreviousIteration)
{
auto iterator = MakeSceneGraphDownwardsIterator<DepthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("A.B", (++iterator)->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
EXPECT_STREQ("A.C.E", (++iterator)->GetPath());
EXPECT_STREQ("A.C.F", (++iterator)->GetPath());
EXPECT_STREQ("A.D", (++iterator)->GetPath());
}
TEST_F(SceneGraphDownwardsIteratorTest, BreadthFirst_IncrementOperator_MoveDownTheTree_IteratorReturnsParentOfPreviousIteration)
{
auto iterator = MakeSceneGraphDownwardsIterator<BreadthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("A.B", (++iterator)->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
EXPECT_STREQ("A.D", (++iterator)->GetPath());
EXPECT_STREQ("A.C.E", (++iterator)->GetPath());
EXPECT_STREQ("A.C.F", (++iterator)->GetPath());
}
TEST_F(SceneGraphDownwardsIteratorTest, DepthFirst_IncrementOperator_BlockCsChildren_AllNodesIteratedExceptEandF)
{
auto iterator = MakeSceneGraphDownwardsIterator<DepthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("A.B", (++iterator)->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
iterator.IgnoreNodeDescendants();
EXPECT_STREQ("A.D", (++iterator)->GetPath());
++iterator;
EXPECT_EQ(iterator.GetHierarchyIterator(), SceneGraph::HierarchyStorageConstIterator());
}
TEST_F(SceneGraphDownwardsIteratorTest, BreadthFirst_IncrementOperator_BlockCsChildren_AllNodesIteratedExceptEandF)
{
auto iterator = MakeSceneGraphDownwardsIterator<BreadthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("A.B", (++iterator)->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
iterator.IgnoreNodeDescendants();
EXPECT_STREQ("A.D", (++iterator)->GetPath());
++iterator;
EXPECT_EQ(iterator.GetHierarchyIterator(), SceneGraph::HierarchyStorageConstIterator());
}
TEST_F(SceneGraphDownwardsIteratorTest, BreadthFirst_IncrementOperator_SiblingsAreIgnored_SiblingNodesBandDareNotReturned)
{
SceneGraph::NodeIndex index = this->m_graph.Find("A.C");
auto iterator = MakeSceneGraphDownwardsIterator<BreadthFirst>(this->m_graph, index, this->m_graph.GetNameStorage().begin(), true);
EXPECT_STREQ("A.C", iterator->GetPath());
EXPECT_STREQ("A.C.E", (++iterator)->GetPath());
EXPECT_STREQ("A.C.F", (++iterator)->GetPath());
++iterator;
EXPECT_EQ(iterator.GetHierarchyIterator(), SceneGraph::HierarchyStorageConstIterator());
}
TEST_F(SceneGraphDownwardsIteratorTest, DepthFirst_IncrementOperator_SiblingsAreIgnored_SiblingNodesBandDareNotReturned)
{
SceneGraph::NodeIndex index = this->m_graph.Find("A.C");
auto iterator = MakeSceneGraphDownwardsIterator<DepthFirst>(this->m_graph, index, this->m_graph.GetNameStorage().begin(), true);
EXPECT_STREQ("A.C", iterator->GetPath());
EXPECT_STREQ("A.C.E", (++iterator)->GetPath());
EXPECT_STREQ("A.C.F", (++iterator)->GetPath());
++iterator;
EXPECT_EQ(iterator.GetHierarchyIterator(), SceneGraph::HierarchyStorageConstIterator());
}
TEST_F(SceneGraphDownwardsIteratorTest, DepthFirst_IncrementOperator_BlockAllChildren_NoNodesListedAfterRoot)
{
auto iterator = MakeSceneGraphDownwardsIterator<DepthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
iterator.IgnoreNodeDescendants();
++iterator;
EXPECT_EQ(iterator.GetHierarchyIterator(), SceneGraph::HierarchyStorageConstIterator());
}
TEST_F(SceneGraphDownwardsIteratorTest, BreadthFirst_IncrementOperator_BlockAllChildren_NoNodesListedAfterRoot)
{
auto iterator = MakeSceneGraphDownwardsIterator<BreadthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
iterator.IgnoreNodeDescendants();
++iterator;
EXPECT_EQ(iterator.GetHierarchyIterator(), SceneGraph::HierarchyStorageConstIterator());
}
TEST_F(SceneGraphDownwardsIteratorTest, DepthFirst_Algorithms_Copy_AllValuesCopiedToNewArray)
{
AZStd::vector<AZStd::string> names(7);
auto sceneView = MakeSceneGraphDownwardsView<DepthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> AZStd::string
{
return name.GetPath();
});
AZStd::copy(convertView.begin(), convertView.end(), names.begin());
EXPECT_STREQ("", names[0].c_str());
EXPECT_STREQ("A", names[1].c_str());
EXPECT_STREQ("A.B", names[2].c_str());
EXPECT_STREQ("A.C", names[3].c_str());
EXPECT_STREQ("A.C.E", names[4].c_str());
EXPECT_STREQ("A.C.F", names[5].c_str());
EXPECT_STREQ("A.D", names[6].c_str());
}
TEST_F(SceneGraphDownwardsIteratorTest, BreadthFirst_Algorithms_Copy_AllValuesCopiedToNewArray)
{
AZStd::vector<AZStd::string> names(7);
auto sceneView = MakeSceneGraphDownwardsView<BreadthFirst>(this->m_graph, this->m_graph.GetNameStorage().begin());
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> AZStd::string
{
return name.GetPath();
});
AZStd::copy(convertView.begin(), convertView.end(), names.begin());
EXPECT_STREQ("", names[0].c_str());
EXPECT_STREQ("A", names[1].c_str());
EXPECT_STREQ("A.B", names[2].c_str());
EXPECT_STREQ("A.C", names[3].c_str());
EXPECT_STREQ("A.D", names[4].c_str());
EXPECT_STREQ("A.C.E", names[5].c_str());
EXPECT_STREQ("A.C.F", names[6].c_str());
}
TEST(SceneGraphDownwardsIterator, DepthFirst_IncrementOperator_EdgeCase_NodesAreListedInCorrectOrder)
{
/*---------------------------------------\
| Root |
| | |
| A |
| / | |
| B C |
| / / |
| D E |
| / |
| F |
\---------------------------------------*/
SceneGraph graph;
SceneGraph::NodeIndex root = graph.GetRoot();
SceneGraph::NodeIndex indexA = graph.AddChild(root, "A");
SceneGraph::NodeIndex indexB = graph.AddChild(indexA, "B");
SceneGraph::NodeIndex indexC = graph.AddSibling(indexB, "C");
graph.AddChild(indexB, "D");
SceneGraph::NodeIndex indexE = graph.AddChild(indexC, "E");
graph.AddChild(indexE, "F");
auto iterator = MakeSceneGraphDownwardsIterator<DepthFirst>(graph, graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("A.B", (++iterator)->GetPath());
EXPECT_STREQ("A.B.D", (++iterator)->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
EXPECT_STREQ("A.C.E", (++iterator)->GetPath());
EXPECT_STREQ("A.C.E.F", (++iterator)->GetPath());
}
TEST(SceneGraphDownwardsIterator, BreadthFirst_IncrementOperator_EdgeCase_NodesAreListedInCorrectOrder)
{
/*---------------------------------------\
| Root |
| | |
| A |
| / | |
| B C |
| / / |
| D E |
| / |
| F |
\---------------------------------------*/
SceneGraph graph;
SceneGraph::NodeIndex root = graph.GetRoot();
SceneGraph::NodeIndex indexA = graph.AddChild(root, "A");
SceneGraph::NodeIndex indexB = graph.AddChild(indexA, "B");
SceneGraph::NodeIndex indexC = graph.AddSibling(indexB, "C");
graph.AddChild(indexB, "D");
SceneGraph::NodeIndex indexE = graph.AddChild(indexC, "E");
graph.AddChild(indexE, "F");
auto iterator = MakeSceneGraphDownwardsIterator<BreadthFirst>(graph, graph.GetNameStorage().begin());
EXPECT_STREQ("", iterator->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("A.B", (++iterator)->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
EXPECT_STREQ("A.B.D", (++iterator)->GetPath());
EXPECT_STREQ("A.C.E", (++iterator)->GetPath());
EXPECT_STREQ("A.C.E.F", (++iterator)->GetPath());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,279 @@
/*
* 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.
*
*/
/*
* This suite of tests focus on the unique features the SceneGraphUpwardsIterator
* adds as an iterator. The basic functionality and iterator conformity is tested
* in the Iterator Conformity Tests (see IteratorConformityTests.cpp).
*/
#include <AzTest/AzTest.h>
#include <algorithm>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/MockIGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
class SceneGraphUpwardsIteratorTest
: public ::testing::Test
{
public:
void SetUp()
{
/*---------------------------------------\
| Root |
| | |
| A |
| / | \ |
| B C D |
| / \ |
| E F |
\---------------------------------------*/
//Build up the graph
SceneGraph::NodeIndex root = m_graph.GetRoot();
m_graph.SetContent(root, AZStd::make_shared<DataTypes::MockIGraphObject>(0));
SceneGraph::NodeIndex indexA = m_graph.AddChild(root, "A", AZStd::make_shared<DataTypes::MockIGraphObject>(1));
SceneGraph::NodeIndex indexB = m_graph.AddChild(indexA, "B", AZStd::make_shared<DataTypes::MockIGraphObject>(2));
SceneGraph::NodeIndex indexC = m_graph.AddSibling(indexB, "C", AZStd::make_shared<DataTypes::MockIGraphObject>(3));
m_graph.AddSibling(indexC, "D", AZStd::make_shared<DataTypes::MockIGraphObject>(4));
SceneGraph::NodeIndex indexE = m_graph.AddChild(indexC, "E", AZStd::make_shared<DataTypes::MockIGraphObject>(5));
m_graph.AddSibling(indexE, "F", AZStd::make_shared<DataTypes::MockIGraphObject>(6));
}
SceneGraph::HierarchyStorageConstData::iterator GetRootHierarchyIterator()
{
return m_graph.ConvertToHierarchyIterator(m_graph.GetRoot());
}
SceneGraph::HierarchyStorageConstData::iterator GetDeepestHierarchyIterator()
{
SceneGraph::NodeIndex index = m_graph.Find("A.C.E");
return m_graph.ConvertToHierarchyIterator(index);
}
SceneGraph m_graph;
};
TEST_F(SceneGraphUpwardsIteratorTest, MakeSceneGraphUpwardsIterator_UtilityFunctionProducesSameIteratorAsExplicitlyDeclared_IteratorsAreEqual)
{
auto lhsIterator = MakeSceneGraphUpwardsIterator(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
auto rhsIterator = SceneGraphUpwardsIterator<SceneGraph::NameStorage::const_iterator>(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(lhsIterator, rhsIterator);
}
TEST_F(SceneGraphUpwardsIteratorTest, MakeSceneGraphUpwardsIterator_NodeAndHierarchyVersions_IteratorsAreIdentical)
{
SceneGraph::NodeIndex index = m_graph.Find("A.C.E");
auto hierarchy = m_graph.ConvertToHierarchyIterator(index);
auto indexIterator = MakeSceneGraphUpwardsIterator(m_graph, index, m_graph.GetNameStorage().begin(), true);
auto hierarchyIterator = MakeSceneGraphUpwardsIterator(m_graph, hierarchy, m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(indexIterator, hierarchyIterator);
}
TEST_F(SceneGraphUpwardsIteratorTest, MakeSceneGraphUpwardsView_UtilityFunctionProducesSameIteratorAsExplicitlyDeclared_IteratorsAreEqual)
{
auto view = MakeSceneGraphUpwardsView(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
auto beginIterator = SceneGraphUpwardsIterator<SceneGraph::NameStorage::const_iterator>(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
auto endIterator = SceneGraphUpwardsIterator<SceneGraph::NameStorage::const_iterator>();
EXPECT_EQ(view.begin(), beginIterator);
EXPECT_EQ(view.end(), endIterator);
}
TEST_F(SceneGraphUpwardsIteratorTest, MakeSceneGraphUpwardsView_NodeAndHierarchyVersions_IteratorsAreIdentical)
{
SceneGraph::NodeIndex index = m_graph.Find("A.C.E");
auto hierarchy = m_graph.ConvertToHierarchyIterator(index);
auto indexView = MakeSceneGraphUpwardsView(m_graph, index, m_graph.GetNameStorage().begin(), true);
auto hierarchyView = MakeSceneGraphUpwardsView(m_graph, hierarchy, m_graph.GetNameStorage().begin(), true);
EXPECT_EQ(indexView.begin(), hierarchyView.begin());
EXPECT_EQ(indexView.end(), hierarchyView.end());
}
TEST_F(SceneGraphUpwardsIteratorTest, EmptyGraph_CanDetectEmptyGraph_BeginAndEndIteratorAreEqual)
{
SceneGraph emptyGraph;
auto beginIterator = MakeSceneGraphUpwardsIterator(emptyGraph, emptyGraph.GetHierarchyStorage().begin(), emptyGraph.GetNameStorage().begin(), true);
beginIterator++; // Even an empty graph will have at least a root entry.
auto endIterator = SceneGraphUpwardsIterator<SceneGraph::NameStorage::const_iterator>();
EXPECT_EQ(beginIterator, endIterator);
}
TEST_F(SceneGraphUpwardsIteratorTest, EmptyGraph_CanDetectEmptyGraphFromView_BeginAndEndIteratorAreEqual)
{
SceneGraph emptyGraph;
auto view = MakeSceneGraphUpwardsView(emptyGraph, emptyGraph.GetHierarchyStorage().begin(), emptyGraph.GetNameStorage().begin(), true);
EXPECT_EQ(++view.begin(), view.end());
}
TEST_F(SceneGraphUpwardsIteratorTest, Dereference_GetRootIteratorValue_ReturnsRelativeValueFromGivenValueIterator)
{
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetRootHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
EXPECT_STREQ("", (*iterator).GetPath());
}
TEST_F(SceneGraphUpwardsIteratorTest, Dereference_GetDeepestIteratorValue_ReturnsRelativeValueFromGivenValueIterator)
{
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
EXPECT_STREQ("A.C.E", (*iterator).GetPath());
}
TEST_F(SceneGraphUpwardsIteratorTest, Dereference_ValueIteratorNotSyncedWithHierarchyIteratorIfNotRequested_ReturnedValueMatchesOriginalValueIterator)
{
auto valueIterator = m_graph.GetNameStorage().begin() + 2;
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetDeepestHierarchyIterator(), valueIterator, false);
EXPECT_STREQ((*valueIterator).GetPath(), (*iterator).GetPath());
}
TEST_F(SceneGraphUpwardsIteratorTest, Dereference_DereferencingThroughStarAndArrowOperator_ValuesAreEqual)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetDeepestHierarchyIterator(), valueIterator, true);
EXPECT_STREQ(iterator->GetPath(), (*iterator).GetPath());
}
TEST_F(SceneGraphUpwardsIteratorTest, IncrementOperator_MoveUpTheTree_IteratorReturnsParentOfPreviousIteration)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetDeepestHierarchyIterator(), valueIterator, true);
EXPECT_STREQ("A.C.E", iterator->GetPath());
EXPECT_STREQ("A.C", (++iterator)->GetPath());
EXPECT_STREQ("A", (++iterator)->GetPath());
EXPECT_STREQ("", (++iterator)->GetPath());
}
TEST_F(SceneGraphUpwardsIteratorTest, IncrementOperator_MovePastRoot_ReturnsEndIterator)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetRootHierarchyIterator(), valueIterator, true);
iterator++;
EXPECT_EQ(SceneGraphUpwardsIterator<SceneGraph::NameStorage::const_iterator>(), iterator);
}
TEST_F(SceneGraphUpwardsIteratorTest, GetHierarchyIterator_MatchesWithNodeInformationAfterMove_NameEqualToNodeIndexedName)
{
auto valueIterator = m_graph.GetNameStorage().begin();
auto iterator = MakeSceneGraphUpwardsIterator(m_graph, GetDeepestHierarchyIterator(), valueIterator, true);
iterator++;
SceneGraph::HierarchyStorageConstIterator hierarchyIterator = iterator.GetHierarchyIterator();
SceneGraph::NodeIndex index = m_graph.ConvertToNodeIndex(hierarchyIterator);
EXPECT_STREQ(m_graph.GetNodeName(index).GetPath(), iterator->GetPath());
}
TEST_F(SceneGraphUpwardsIteratorTest, ValueIterator_NonSceneGraphIterator_ExternalIteratorValuesMatchSceneGraphValues)
{
// Commonly containers in the scene graph will be used, but it is possible to specify other containers that shadow
// the scene graph but don't belong to it. This test checks if this works correctly by comparing the values
// stored in the scene graph with the same values stored in an external container.
// (See constructor of SceneGraphUpwardsIterator for more details on arguments.)
AZStd::vector<int> values = { 0, 1, 2, 3, 4, 5, 6 };
auto sceneView = MakeSceneGraphUpwardsView(m_graph, GetDeepestHierarchyIterator(), m_graph.GetContentStorage().begin(), true);
auto valuesView = MakeSceneGraphUpwardsView(m_graph, GetDeepestHierarchyIterator(), values.begin(), true);
auto sceneIterator = sceneView.begin();
auto valuesIterator = valuesView.begin();
while (sceneIterator != sceneView.end())
{
EXPECT_NE(valuesView.end(), valuesIterator);
DataTypes::MockIGraphObject* stored = azrtti_cast<DataTypes::MockIGraphObject*>(sceneIterator->get());
ASSERT_NE(stored, nullptr);
EXPECT_EQ(stored->m_id, *valuesIterator);
valuesIterator++;
sceneIterator++;
}
}
TEST_F(SceneGraphUpwardsIteratorTest, Algorithms_RangedForLoop_AllParentNodesTouchedAndExitingLoop)
{
AZStd::vector<const char*> expectedName =
{
"A.C.E",
"A.C",
"A",
""
};
size_t index = 0;
auto sceneView = MakeSceneGraphUpwardsView(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
for (auto& it : sceneView)
{
ASSERT_LT(index, expectedName.size());
EXPECT_STREQ(expectedName[index], it.GetPath());
index++;
}
EXPECT_EQ(expectedName.size(), index);
}
TEST_F(SceneGraphUpwardsIteratorTest, Algorithms_Find_AlgorithmFindsRequestedName)
{
auto sceneView = MakeSceneGraphUpwardsView(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> const char*
{
return name.GetPath();
});
// Needs AZStd::string for comparing otherwise two pointers will be compared instead of string content.
auto result = AZStd::find(convertView.begin(), convertView.end(), AZStd::string("A.C"));
auto compare = m_graph.ConvertToHierarchyIterator(m_graph.Find("A.C"));
EXPECT_EQ(compare, result.GetBaseIterator().GetHierarchyIterator());
}
TEST_F(SceneGraphUpwardsIteratorTest, Algorithms_Copy_AllValuesCopiedToNewArray)
{
AZStd::vector<AZStd::string> names(4);
auto sceneView = MakeSceneGraphUpwardsView(m_graph, GetDeepestHierarchyIterator(), m_graph.GetNameStorage().begin(), true);
auto convertView = MakeConvertView(sceneView,
[](const SceneGraph::Name& name) -> const char*
{
return name.GetPath();
});
AZStd::copy(convertView.begin(), convertView.end(), names.begin());
EXPECT_STREQ("A.C.E", names[0].c_str());
EXPECT_STREQ("A.C", names[1].c_str());
EXPECT_STREQ("A", names[2].c_str());
EXPECT_STREQ("", names[3].c_str());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,299 @@
/*
* 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 <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <ScenePopulation/ScenePopulation/Containers/DataObject.h>
namespace Containers = AZ::ScenePopulation::Containers;
class ComplexObject
{
public:
AZ_RTTI(ComplexObject, "{1969D4A3-3714-4E1C-816E-E066538A2A0B}")
ComplexObject()
: m_value0(42)
, m_value1("test")
{}
explicit ComplexObject(int value0)
: m_value0(value0)
, m_value1("test")
{}
ComplexObject(int value0, const std::string& value1)
: m_value0(value0)
, m_value1(value1)
{}
bool operator==(const ComplexObject& rhs) const
{
return m_value0 == rhs.m_value0 && m_value1 == rhs.m_value1;
}
int m_value0;
std::string m_value1;
};
class DestructionClass
{
public:
AZ_RTTI(DestructionClass, "{6EFE6C0C-80E8-4D62-9705-A7315049DFBF}")
~DestructionClass()
{
Destructor();
}
MOCK_METHOD0(Destructor, void());
};
class BaseInterface
{
public:
AZ_RTTI(BaseInterface, "{723F701D-B718-432B-AE67-78F999A64883}")
};
class SecondInterface
{
public:
AZ_RTTI(SecondInterface, "{8D0420F1-C102-4615-94F3-9D39E0D3A272}")
};
class SingleInheritance
: public BaseInterface
{
public:
AZ_RTTI(SingleInheritance, "{2D5EA157-8137-4FD4-A08D-58941FB149B2}", BaseInterface);
};
class MultipleInheritance
: public BaseInterface
, public SecondInterface
{
public:
AZ_RTTI(MultipleInheritance, "{277E1CAA-EB89-4820-B37E-B49922FD0DF9}", BaseInterface, SecondInterface);
};
class ReflectionClass
{
public:
AZ_RTTI(ReflectionClass, "{81E5CB64-B879-440F-9659-9D45AA544144}")
uint32_t testVar;
MOCK_METHOD0(Reflect, void());
static ReflectionClass* currentTestClass;
static void Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->
Class<ReflectionClass>()->
Version(1)->
Field("testVar", &ReflectionClass::testVar);
}
currentTestClass->Reflect();
}
};
ReflectionClass* ReflectionClass::currentTestClass = nullptr;
class DataObjectTest
: public ::testing::Test
{
public:
DataObjectTest()
{
}
};
namespace TestNamespace
{
class TestClassInNamespace
{
public:
AZ_RTTI(TestClassInNamespace, "{F6CF64ED-6255-4E93-A34D-8BE58546C12E}")
};
}
// Create
TEST_F(DataObjectTest, Create_CreateUninitializedPOD_ValidDataObject)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>();
EXPECT_NE(nullptr, result);
}
TEST_F(DataObjectTest, Create_CreateInitializedPOD_ValidDataObject)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>(42);
EXPECT_NE(nullptr, result);
}
TEST_F(DataObjectTest, Create_CreateUninitializedComplexObject_ValidDataObject)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ComplexObject>();
EXPECT_NE(nullptr, result);
}
TEST_F(DataObjectTest, Create_CreateComplexObjectWithSingleParamter_ValidDataObject)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ComplexObject>(42);
EXPECT_NE(nullptr, result);
}
TEST_F(DataObjectTest, Create_CreateComplexObjectWithMultipileParamters_ValidDataObject)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ComplexObject>(42, "Test string");
EXPECT_NE(nullptr, result);
}
// IsType
TEST_F(DataObjectTest, IsType_GetPODType_PODIsRecognizedAsType)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>();
ASSERT_NE(nullptr, result);
EXPECT_TRUE(result->IsType<int>());
}
TEST_F(DataObjectTest, IsType_GetComplexClassType_ComplexObjectIsRecognizedAsType)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ComplexObject>();
ASSERT_NE(nullptr, result);
EXPECT_TRUE(result->IsType<ComplexObject>());
}
TEST_F(DataObjectTest, IsType_SingleInheritance_BaseInterfaceFoundFromDerivedClass)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<SingleInheritance>();
ASSERT_NE(nullptr, result);
EXPECT_TRUE(result->IsType<BaseInterface>());
}
TEST_F(DataObjectTest, IsType_MultipleInheritance_BothInterfacesFoundFromDerivedClass)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<MultipleInheritance>();
ASSERT_NE(nullptr, result);
EXPECT_TRUE(result->IsType<BaseInterface>());
EXPECT_TRUE(result->IsType<SecondInterface>());
}
// GetTypeName
TEST_F(DataObjectTest, GetTypeName_GetNameOfPOD_NameOfPODIsInt)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>();
ASSERT_NE(nullptr, result);
EXPECT_STRCASEEQ("int", result->GetTypeName());
}
TEST_F(DataObjectTest, GetTypeName_GetNameOfComplexClass_NameIsComplexObject)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ComplexObject>();
ASSERT_NE(nullptr, result);
EXPECT_STRCASEEQ("ComplexObject", result->GetTypeName());
}
TEST_F(DataObjectTest, GetTypeName_GetNameOfComplexClassInNamespace_TypeNameOfClassWithoutNamespace)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<TestNamespace::TestClassInNamespace>();
ASSERT_NE(nullptr, result);
EXPECT_STRCASEEQ("TestClassInNamespace", result->GetTypeName());
}
TEST_F(DataObjectTest, GetTypeName_GetNameOfTypedefedType_NameOfOriginalType)
{
using U32 = int;
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<U32>();
ASSERT_NE(nullptr, result);
EXPECT_STRCASEEQ("int", result->GetTypeName());
}
// DynamicCast
TEST_F(DataObjectTest, DynamicCast_CastToGivenPOD_ValidPointer)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>();
ASSERT_NE(nullptr, result);
EXPECT_NE(nullptr, result->DynamicCast<int*>());
}
TEST_F(DataObjectTest, DynamicCast_CastToInvalidType_Nullptr)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>();
ASSERT_NE(nullptr, result);
EXPECT_EQ(nullptr, result->DynamicCast<float*>());
}
TEST_F(DataObjectTest, DynamicCast_GivenPODDataIsAccesible_SameValueAsStored)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<int>(42);
ASSERT_NE(nullptr, result);
int* value = result->DynamicCast<int*>();
EXPECT_EQ(42, *value);
}
TEST_F(DataObjectTest, DynamicCast_GivenComplextDataIsAccesible_SameValueAsStored)
{
ComplexObject comparison = ComplexObject(42, "test");
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ComplexObject>(42, "test");
ASSERT_NE(nullptr, result);
ComplexObject* value = result->DynamicCast<ComplexObject*>();
EXPECT_EQ(comparison, *value);
}
// Destruction
TEST_F(DataObjectTest, Destruction_DestructorCalledOnConstructedObject_DestructorCalled)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<DestructionClass>();
ASSERT_NE(nullptr, result);
DestructionClass* value = result->DynamicCast<DestructionClass*>();
ASSERT_NE(nullptr, value);
EXPECT_CALL(*value, Destructor()).Times(1);
}
// Reflect
TEST_F(DataObjectTest, Reflect_ReflectIsCalledOnStoredObject_ReflectCalled)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ReflectionClass>();
ReflectionClass* value = result->DynamicCast<ReflectionClass*>();
ASSERT_NE(nullptr, value);
ReflectionClass::currentTestClass = value;
EXPECT_CALL(*value, Reflect()).Times(1);
AZ::SerializeContext context;
result->ReflectData(&context);
}
TEST_F(DataObjectTest, Reflect_ReflectIsCalledMultipleTimesOnSameStoredObject_ReflectCalledOnceAndNowAssertsFromSerializeContext)
{
std::unique_ptr<Containers::DataObject> result = Containers::DataObject::Create<ReflectionClass>();
ReflectionClass* value = result->DynamicCast<ReflectionClass*>();
ASSERT_NE(nullptr, value);
ReflectionClass::currentTestClass = value;
EXPECT_CALL(*value, Reflect()).Times(1);
AZ::SerializeContext context;
result->ReflectData(&context);
result->ReflectData(&context);
}
@@ -0,0 +1,326 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzCore/Math/Guid.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
#include <SceneAPI/SceneCore/Mocks/Events/MockAssetImportRequest.h>
namespace AZ
{
namespace SceneAPI
{
namespace Events
{
using ::testing::StrictMock;
using ::testing::NiceMock;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::Matcher;
using ::testing::_;
/*
* ProcessingResultCombinerTests
*/
TEST(ProcessingResultCombinerTests, GetResult_GetStoredValue_ReturnsTheDefaultValue)
{
ProcessingResultCombiner combiner;
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetResult());
}
TEST(ProcessingResultCombinerTests, OperatorEquals_SuccessIsStored_ResultIsSuccess)
{
ProcessingResultCombiner combiner;
combiner = ProcessingResult::Success;
EXPECT_EQ(ProcessingResult::Success, combiner.GetResult());
}
TEST(ProcessingResultCombinerTests, OperatorEquals_FailureIsStored_ResultIsFailure)
{
ProcessingResultCombiner combiner;
combiner = ProcessingResult::Failure;
EXPECT_EQ(ProcessingResult::Failure, combiner.GetResult());
}
TEST(ProcessingResultCombinerTests, OperatorEquals_SuccessDoesNotOverwriteFailure_ResultIsFailure)
{
ProcessingResultCombiner combiner;
combiner = ProcessingResult::Failure;
combiner = ProcessingResult::Success;
EXPECT_EQ(ProcessingResult::Failure, combiner.GetResult());
}
TEST(ProcessingResultCombinerTests, OperatorEquals_IgnoreDoesNotChangeTheStoredValue_ResultIsSuccess)
{
ProcessingResultCombiner combiner;
combiner = ProcessingResult::Success;
combiner = ProcessingResult::Ignored;
EXPECT_EQ(ProcessingResult::Success, combiner.GetResult());
}
/*
* LoadingResultCombinerTests
*/
TEST(LoadingResultCombinerTests, GetResult_GetStoredValues_ReturnsTheDefaultValues)
{
LoadingResultCombiner combiner;
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetManifestResult());
}
TEST(LoadingResultCombinerTests, OperatorEquals_AssetLoadedIsStored_ResultIsSuccess)
{
LoadingResultCombiner combiner;
combiner = LoadingResult::AssetLoaded;
EXPECT_EQ(ProcessingResult::Success, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetManifestResult());
}
TEST(LoadingResultCombinerTests, OperatorEquals_ManifestLoadedIsStored_ResultIsSuccess)
{
LoadingResultCombiner combiner;
combiner = LoadingResult::ManifestLoaded;
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Success, combiner.GetManifestResult());
}
TEST(LoadingResultCombinerTests, OperatorEquals_AssetFailureIsStored_ResultIsFailure)
{
LoadingResultCombiner combiner;
combiner = LoadingResult::AssetFailure;
EXPECT_EQ(ProcessingResult::Failure, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetManifestResult());
}
TEST(LoadingResultCombinerTests, OperatorEquals_ManifestFailureIsStored_ResultIsFailure)
{
LoadingResultCombiner combiner;
combiner = LoadingResult::ManifestFailure;
EXPECT_EQ(ProcessingResult::Ignored, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Failure, combiner.GetManifestResult());
}
TEST(LoadingResultCombinerTests, OperatorEquals_LoadedDoesNotOverwriteFailure_ResultIsFailure)
{
LoadingResultCombiner combiner;
combiner = LoadingResult::AssetFailure;
combiner = LoadingResult::ManifestFailure;
combiner = LoadingResult::AssetLoaded;
combiner = LoadingResult::ManifestLoaded;
EXPECT_EQ(ProcessingResult::Failure, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Failure, combiner.GetManifestResult());
}
TEST(LoadingResultCombinerTests, OperatorEquals_IgnoreDoesNotChangeTheStoredValue_ResultIsSuccess)
{
LoadingResultCombiner combiner;
combiner = LoadingResult::AssetLoaded;
combiner = LoadingResult::ManifestLoaded;
combiner = LoadingResult::Ignored;
combiner = LoadingResult::Ignored;
EXPECT_EQ(ProcessingResult::Success, combiner.GetAssetResult());
EXPECT_EQ(ProcessingResult::Success, combiner.GetManifestResult());
}
/*
* AssetImporterRequestTests
*/
class AssetImporterRequestTests
: public ::testing::Test
, public Debug::TraceMessageBus::Handler
{
public:
void SetUp() override
{
BusConnect();
m_testId = Uuid::CreateString("{46CAD46C-A3CB-4E2A-A775-2ED9DCF018FC}");
}
void TearDown() override
{
BusDisconnect();
}
bool OnPreAssert(const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override
{
m_assertTriggered = true;
return true;
}
Uuid m_testId;
bool m_assertTriggered = false;
};
TEST_F(AssetImporterRequestTests, LoadSceneFromVerifiedPath_FailureToPrepare_LoadAndFollowingStepsNotCalledAndReturnsNullptr)
{
StrictMock<MockAssetImportRequestHandler> handler;
handler.SetDefaultExtensions();
handler.SetDefaultProcessingResults(false);
ON_CALL(handler, PrepareForAssetLoading(Matcher<Containers::Scene&>(_), Matcher<AssetImportRequest::RequestingApplication>(_)))
.WillByDefault(Return(ProcessingResult::Failure));
EXPECT_CALL(handler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(handler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(handler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, LoadAsset(_, _, _, _)).Times(0);
EXPECT_CALL(handler, FinalizeAssetLoading(_, _)).Times(0);
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
AZStd::shared_ptr<Containers::Scene> result =
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
EXPECT_EQ(nullptr, result);
}
TEST_F(AssetImporterRequestTests, LoadSceneFromVerifiedPath_AssetFailureToLoad_UpdateManifestNotCalledAndReturnsNullptr)
{
StrictMock<MockAssetImportRequestHandler> handler;
handler.SetDefaultExtensions();
handler.SetDefaultProcessingResults(false);
ON_CALL(handler, LoadAsset(
Matcher<Containers::Scene&>(_), Matcher<const AZStd::string&>(_), Matcher<const Uuid&>(_), Matcher<AssetImportRequest::RequestingApplication>(_)))
.WillByDefault(Return(LoadingResult::AssetFailure));
EXPECT_CALL(handler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(handler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(handler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(handler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
AZStd::shared_ptr<Containers::Scene> result =
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
EXPECT_EQ(nullptr, result);
}
TEST_F(AssetImporterRequestTests, LoadSceneFromVerifiedPath_ManifestFailureToLoad_UpdateManifestNotCalledAndReturnsNullptr)
{
StrictMock<MockAssetImportRequestHandler> handler;
handler.SetDefaultExtensions();
handler.SetDefaultProcessingResults(true);
ON_CALL(handler, LoadAsset(
Matcher<Containers::Scene&>(_), Matcher<const AZStd::string&>(_), Matcher<const Uuid&>(_), Matcher<AssetImportRequest::RequestingApplication>(_)))
.WillByDefault(Return(LoadingResult::ManifestFailure));
EXPECT_CALL(handler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(handler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(handler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(handler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
AZStd::shared_ptr<Containers::Scene> result =
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
EXPECT_EQ(nullptr, result);
}
TEST_F(AssetImporterRequestTests, LoadSceneFromVerifiedPath_NothingLoaded_UpdateManifestNotCalledAndReturnsNullptr)
{
StrictMock<MockAssetImportRequestHandler> handler;
handler.SetDefaultExtensions();
handler.SetDefaultProcessingResults(false);
ON_CALL(handler, LoadAsset(
Matcher<Containers::Scene&>(_), Matcher<const AZStd::string&>(_), Matcher<const Uuid&>(_), Matcher<AssetImportRequest::RequestingApplication>(_)))
.WillByDefault(Return(LoadingResult::Ignored));
EXPECT_CALL(handler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(handler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(handler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(handler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(handler, UpdateManifest(_, _, _)).Times(0);
AZStd::shared_ptr<Containers::Scene> result =
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
EXPECT_EQ(nullptr, result);
}
TEST_F(AssetImporterRequestTests, LoadSceneFromVerifiedPath_ManifestUpdateFailed_ReturnsNullptr)
{
StrictMock<MockAssetImportRequestHandler> assetHandler;
assetHandler.SetDefaultExtensions();
assetHandler.SetDefaultProcessingResults(false);
StrictMock<MockAssetImportRequestHandler> manifestHandler;
manifestHandler.SetDefaultExtensions();
manifestHandler.SetDefaultProcessingResults(true);
ON_CALL(assetHandler, UpdateManifest(Matcher<Containers::Scene&>(_), Matcher<AssetImportRequest::ManifestAction>(_),
Matcher<AssetImportRequest::RequestingApplication>(_)))
.WillByDefault(Return(ProcessingResult::Failure));
EXPECT_CALL(assetHandler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(assetHandler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(manifestHandler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(manifestHandler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(assetHandler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(assetHandler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(assetHandler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(assetHandler, UpdateManifest(_, _, _)).Times(1);
EXPECT_CALL(manifestHandler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(manifestHandler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(manifestHandler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(manifestHandler, UpdateManifest(_, _, _)).Times(1);
AZStd::shared_ptr<Containers::Scene> result =
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
EXPECT_EQ(nullptr, result);
}
TEST_F(AssetImporterRequestTests, LoadSceneFromVerifiedPath_FullLoad_ReturnsValidScenePointer)
{
StrictMock<MockAssetImportRequestHandler> assetHandler;
assetHandler.SetDefaultExtensions();
assetHandler.SetDefaultProcessingResults(false);
StrictMock<MockAssetImportRequestHandler> manifestHandler;
manifestHandler.SetDefaultExtensions();
manifestHandler.SetDefaultProcessingResults(true);
EXPECT_CALL(assetHandler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(assetHandler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(manifestHandler, GetManifestExtension(_)).Times(0);
EXPECT_CALL(manifestHandler, GetSupportedFileExtensions(_)).Times(0);
EXPECT_CALL(assetHandler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(assetHandler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(assetHandler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(assetHandler, UpdateManifest(_, _, _)).Times(1);
EXPECT_CALL(manifestHandler, PrepareForAssetLoading(_, _)).Times(1);
EXPECT_CALL(manifestHandler, LoadAsset(_, _, _, _)).Times(1);
EXPECT_CALL(manifestHandler, FinalizeAssetLoading(_, _)).Times(1);
EXPECT_CALL(manifestHandler, UpdateManifest(_, _, _)).Times(1);
AZStd::shared_ptr<Containers::Scene> result =
AssetImportRequest::LoadSceneFromVerifiedPath("test.asset", m_testId, Events::AssetImportRequest::RequestingApplication::Generic);
EXPECT_NE(nullptr, result);
}
} // Events
} // SceneAPI
} // AZ
@@ -0,0 +1,58 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <GFxFramework/MaterialIO/Material.h>
TEST(MaterialIO, Material_SetDataFromMtl_TexModAsNextSibling_DoesNotGetStuckInInfiniteLoop)
{
AZStd::string xmlTextModAsNextSibling(
"<Material MtlFlags=\"524288\" Shader=\"Illum\" GenMask=\"400000000001\" StringGenMask=\"%ALLOW_SILHOUETTE_POM%SUBSURFACE_SCATTERING\" SurfaceType=\"mat_default\" MatTemplate=\"\" Diffuse=\"0.50196099,0.50196099,0.50196099\" Specular=\"0.50196099,0.50196099,0.50196099\" Emissive=\"0,0,0\" Shininess=\"10\" Opacity=\"1\" LayerAct=\"1\">\
<Textures>\
<Texture Map = \"Diffuse\" File=\"Environment_Global\\Props\\piles\\Global_Debris_Gravel_pile_02\\Global_Debris_Gravel_pile_02_ddiff.dds\"/>\
<TexMod TexMod_RotateType = \"0\" TexMod_TexGenType=\"0\" TexMod_bTexGenProjected=\"0\" TileU=\"4\" TileV=\"4\"/>\
</Textures>\
<PublicParams GlossFromDiffuseContrast = \"1\" FresnelScale=\"1\" GlossFromDiffuseOffset=\"0\" FresnelBias=\"1\" GlossFromDiffuseAmount=\"0\" GlossFromDiffuseBrightness=\"0.333\" IndirectColor=\"0.25,0.25,0.25\"/>\
</Material>"
);
AZ::rapidxml::xml_document<char>* xmlDoc = azcreate(AZ::rapidxml::xml_document<char>, (), AZ::SystemAllocator);
EXPECT_TRUE(xmlDoc->parse<0>(xmlTextModAsNextSibling.data()));
AZ::rapidxml::xml_node<char>* materialXmlNode = xmlDoc->first_node("Material");
AZ::GFxFramework::Material material;
material.SetDataFromMtl(materialXmlNode);
azdestroy(xmlDoc);
}
TEST(MaterialIO, Material_SetDataFromMtl_TextureMissingMapAndFile_DoesNotGetStuckInInfiniteLoop)
{
AZStd::string xmlTextureMissingMapAndFile(
"<Material MtlFlags=\"524288\" Shader=\"Illum\" GenMask=\"400000000001\" StringGenMask=\"%ALLOW_SILHOUETTE_POM%SUBSURFACE_SCATTERING\" SurfaceType=\"mat_default\" MatTemplate=\"\" Diffuse=\"0.50196099,0.50196099,0.50196099\" Specular=\"0.50196099,0.50196099,0.50196099\" Emissive=\"0,0,0\" Shininess=\"10\" Opacity=\"1\" LayerAct=\"1\">\
<Textures>\
<texture/>\
<texture Map = \"Specular\" File=\"z:/amazongdc/artworking/characters/jack/textures/jack_s.tga\"/>\
</Textures>\
<PublicParams GlossFromDiffuseContrast = \"1\" FresnelScale=\"1\" GlossFromDiffuseOffset=\"0\" FresnelBias=\"1\" GlossFromDiffuseAmount=\"0\" GlossFromDiffuseBrightness=\"0.333\" IndirectColor=\"0.25,0.25,0.25\"/>\
</Material>"
);
AZ::rapidxml::xml_document<char>* xmlDoc = azcreate(AZ::rapidxml::xml_document<char>, (), AZ::SystemAllocator);
EXPECT_TRUE(xmlDoc->parse<0>(xmlTextureMissingMapAndFile.data()));
AZ::rapidxml::xml_node<char>* materialXmlNode = xmlDoc->first_node("Material");
AZ::GFxFramework::Material material;
material.SetDataFromMtl(materialXmlNode);
azdestroy(xmlDoc);
}
@@ -0,0 +1,37 @@
/*
* 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 <AzTest/AzTest.h>
#include <SceneAPI/SceneCore/SceneCoreStandaloneAllocator.h>
class SceneCoreTestEnvironment
: public AZ::Test::ITestEnvironment
{
public:
virtual ~SceneCoreTestEnvironment() {}
protected:
void SetupEnvironment() override
{
AZ::Environment::Create(nullptr);
AZ::SceneAPI::SceneCoreStandaloneAllocator::Initialize(AZ::Environment::GetInstance());
}
void TeardownEnvironment() override
{
AZ::SceneAPI::SceneCoreStandaloneAllocator::TearDown();
AZ::Environment::Destroy();
}
};
AZ_UNIT_TEST_HOOK(new SceneCoreTestEnvironment);
@@ -0,0 +1,65 @@
/*
* 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 <AzTest/AzTest.h>
#include <SceneAPI/SceneCore/Utilities/PatternMatcher.h>
namespace AZ
{
namespace SceneAPI
{
namespace SceneCore
{
TEST(PatternMatcherTest, MatchesPattern_MatchingNameWithPostFix_ReturnsTrue)
{
PatternMatcher matcher("_postfix", PatternMatcher::MatchApproach::PostFix);
EXPECT_TRUE(matcher.MatchesPattern("string_with_postfix"));
}
TEST(PatternMatcherTest, MatchesPattern_NonMatchingNameWithPostFix_ReturnsFalse)
{
PatternMatcher matcher("_postfix", PatternMatcher::MatchApproach::PostFix);
EXPECT_FALSE(matcher.MatchesPattern("string_with_something_else"));
}
TEST(PatternMatcherTest, MatchesPattern_NonMatchingNameWithPostFixAndEarlyOutForSmallerTestThanPattern_ReturnsFalse)
{
PatternMatcher matcher("_postfix", PatternMatcher::MatchApproach::PostFix);
EXPECT_FALSE(matcher.MatchesPattern("small"));
}
TEST(PatternMatcherTest, MatchesPattern_MatchingNameWithPreFix_ReturnsTrue)
{
PatternMatcher matcher("prefix_", PatternMatcher::MatchApproach::PreFix);
EXPECT_TRUE(matcher.MatchesPattern("prefix_for_string"));
}
TEST(PatternMatcherTest, MatchesPattern_NonMatchingNameWithPreFix_ReturnsFalse)
{
PatternMatcher matcher("prefix_", PatternMatcher::MatchApproach::PreFix);
EXPECT_FALSE(matcher.MatchesPattern("string_with_something_else"));
}
TEST(PatternMatcherTest, MatchesPattern_MatchingNameWithRegex_ReturnsTrue)
{
PatternMatcher matcher("^.{4}$", PatternMatcher::MatchApproach::Regex);
EXPECT_TRUE(matcher.MatchesPattern("fits"));
}
TEST(PatternMatcherTest, MatchesPattern_NonMatchingNameWithRegex_ReturnsFalse)
{
PatternMatcher matcher("^.{4}$", PatternMatcher::MatchApproach::Regex);
EXPECT_FALSE(matcher.MatchesPattern("string_to_long_for_regex"));
}
} // SceneCore
} // SceneAPI
} // AZ
@@ -0,0 +1,352 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/ManifestBase/MockISceneNodeSelectionList.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/GraphData/MockIMeshData.h>
namespace AZ
{
namespace SceneAPI
{
namespace Utilities
{
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::_;
using ::testing::Matcher;
class SceneGraphSelectorTest
: public ::testing::Test
{
public:
virtual ~SceneGraphSelectorTest() = default;
void SetUp()
{
/*---------------------------------------\
| Root |
| | |
| A |
| / | \ |
| B C D |
| \ |
| E |
| |
\---------------------------------------*/
Containers::SceneGraph::NodeIndex root = m_graph.GetRoot();
Containers::SceneGraph::NodeIndex indexA = m_graph.AddChild(root, "A");
Containers::SceneGraph::NodeIndex indexB = m_graph.AddChild(indexA, "B");
Containers::SceneGraph::NodeIndex indexC = m_graph.AddSibling(indexB, "C");
Containers::SceneGraph::NodeIndex indexD = m_graph.AddSibling(indexC, "D");
m_graph.AddChild(indexD, "E");
}
void CreateMeshGroup(AZStd::vector<AZStd::string>& selectedNodes, AZStd::vector<AZStd::string>& unselectedNodes)
{
EXPECT_CALL(m_testNodeSelectionList, GetSelectedNodeCount())
.WillRepeatedly(Return(selectedNodes.size()));
EXPECT_CALL(m_testNodeSelectionList, GetUnselectedNodeCount())
.WillRepeatedly(Return(unselectedNodes.size()));
for (size_t i = 0; i < selectedNodes.size(); ++i)
{
EXPECT_CALL(m_testNodeSelectionList, GetSelectedNode(Eq(i)))
.WillRepeatedly(ReturnRef(selectedNodes[i]));
}
for (size_t i = 0; i < unselectedNodes.size(); ++i)
{
EXPECT_CALL(m_testNodeSelectionList, GetUnselectedNode(Eq(i)))
.WillRepeatedly(ReturnRef(unselectedNodes[i]));
}
auto selectedNodeInvoke = [&selectedNodes](const AZStd::string& name) -> size_t
{
size_t index = selectedNodes.size();
selectedNodes.push_back(name);
return index;
};
EXPECT_CALL(m_testNodeSelectionList, AddSelectedNode(_))
.WillRepeatedly(Invoke(selectedNodeInvoke));
auto removeNodeInvoke = [&unselectedNodes](const AZStd::string& name)
{
unselectedNodes.push_back(name);
};
EXPECT_CALL(m_testNodeSelectionList, RemoveSelectedNode(Matcher<const AZStd::string&>(_)))
.WillRepeatedly(Invoke(removeNodeInvoke));
auto clearSelectedNodes = [&selectedNodes]()
{
selectedNodes.clear();
};
EXPECT_CALL(m_testNodeSelectionList, ClearSelectedNodes())
.WillRepeatedly(Invoke(clearSelectedNodes));
auto clearUnselectedNodes = [&unselectedNodes]()
{
unselectedNodes.clear();
};
EXPECT_CALL(m_testNodeSelectionList, ClearUnselectedNodes())
.WillRepeatedly(Invoke(clearUnselectedNodes));
}
static bool IsValidTestNodeType([[maybe_unused]] const Containers::SceneGraph& graph, [[maybe_unused]] Containers::SceneGraph::NodeIndex& index)
{
return true;
}
static bool IsValidTestNodeTypeSomeInvalid(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex& index)
{
if (strcmp(graph.GetNodeName(index).GetPath(), "") == 0 || strcmp(graph.GetNodeName(index).GetPath(), "A.D") == 0)
{
return false;
}
else
{
return true;
}
}
protected:
using TestNodeSelectionList = DataTypes::MockISceneNodeSelectionList;
Containers::SceneGraph m_graph;
NiceMock<TestNodeSelectionList> m_testNodeSelectionList;
};
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_EmptySelectedAndEmptyUnselectedNodes_AllTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes;
AZStd::vector<AZStd::string> unselectedNodes;
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 5);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.B", targetNodes[1].c_str());
EXPECT_STREQ("A.C", targetNodes[2].c_str());
EXPECT_STREQ("A.D", targetNodes[3].c_str());
EXPECT_STREQ("A.D.E", targetNodes[4].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_OnlySelectedRootNode_AllNodesInTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A" };
AZStd::vector<AZStd::string> unselectedNodes;
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 5);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.B", targetNodes[1].c_str());
EXPECT_STREQ("A.C", targetNodes[2].c_str());
EXPECT_STREQ("A.D", targetNodes[3].c_str());
EXPECT_STREQ("A.D.E", targetNodes[4].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_OnlyUnselectedRootNode_NoTargetNode)
{
AZStd::vector<AZStd::string> selectedNodes;
AZStd::vector<AZStd::string> unselectedNodes = { "A" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_TRUE(targetNodes.empty());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_NonemptySelectedAndEmptyUnselectedNodes_AllNodesInTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A", "A.B", "A.D" };
AZStd::vector<AZStd::string> unselectedNodes;
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 5);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.B", targetNodes[1].c_str());
EXPECT_STREQ("A.C", targetNodes[2].c_str());
EXPECT_STREQ("A.D", targetNodes[3].c_str());
EXPECT_STREQ("A.D.E", targetNodes[4].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_EmptySelectedAndNonemptyUnselectedNodes_NoTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes;
AZStd::vector<AZStd::string> unselectedNodes = { "A", "A.B", "A.D" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_TRUE(targetNodes.empty());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_SelectedParentNodeUnselectedChildNode_NodeAandAB)
{
AZStd::vector<AZStd::string> selectedNodes = { "A", "A.B" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.C", "A.D" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 2);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.B", targetNodes[1].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_UnselectedParentNodeSelectedChildNode_NodeACandADandADE)
{
AZStd::vector<AZStd::string> selectedNodes = { "A.C", "A.D" };
AZStd::vector<AZStd::string> unselectedNodes = { "A", "A.B" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 3);
EXPECT_STREQ("A.C", targetNodes[0].c_str());
EXPECT_STREQ("A.D", targetNodes[1].c_str());
EXPECT_STREQ("A.D.E", targetNodes[2].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_SelectedParentUnselectedChild_ParentNodeInTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A.D" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.D.E" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_NE(targetNodes.end(), AZStd::find(targetNodes.begin(), targetNodes.end(), "A.D"));
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_UnselectedParentSelectedChild_ChildNodeInTargetNodesButNotParent)
{
AZStd::vector<AZStd::string> selectedNodes = { "A.D.E" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.D" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.end(), AZStd::find(targetNodes.begin(), targetNodes.end(), "A.D"));
EXPECT_NE(targetNodes.end(), AZStd::find(targetNodes.begin(), targetNodes.end(), "A.D.E"));
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_GrandparentNodeSelectedParentNodeUnknown_GrandchildNodeInTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.B", "A.C" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 3);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.D", targetNodes[1].c_str());
EXPECT_STREQ("A.D.E", targetNodes[2].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_GrandparentNodeUnselectedParentNodeUnknown_GrandchildNodeNotInTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A.B", "A.C" };
AZStd::vector<AZStd::string> unselectedNodes = { "A" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 2);
EXPECT_STREQ("A.B", targetNodes[0].c_str());
EXPECT_STREQ("A.C", targetNodes[1].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_OverlappedSelectedAndUnselectedNodes_OverlappedNodeNotInTargetNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A", "A.B", "A.D" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.B", "A.D" };
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeType);
EXPECT_EQ(targetNodes.size(), 2);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.C", targetNodes[1].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_OnlySelectedRootNodeSomeInvalidNodes_NodeAandABandACandADE)
{
AZStd::vector<AZStd::string> selectedNodes = { "A" };
AZStd::vector<AZStd::string> unselectedNodes;
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeTypeSomeInvalid);
EXPECT_EQ(targetNodes.size(), 4);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.B", targetNodes[1].c_str());
EXPECT_STREQ("A.C", targetNodes[2].c_str());
EXPECT_STREQ("A.D.E", targetNodes[3].c_str());
}
TEST_F(SceneGraphSelectorTest, GenerateTargetNodes_NonemptySelectedandUnselectedNodseSomeInvalidNodes_NodeAandAC)
{
AZStd::vector<AZStd::string> selectedNodes = { "A" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.B", "A.D.E"};
CreateMeshGroup(selectedNodes, unselectedNodes);
auto targetNodes = SceneGraphSelector::GenerateTargetNodes(m_graph, m_testNodeSelectionList, IsValidTestNodeTypeSomeInvalid);
EXPECT_EQ(targetNodes.size(), 2);
EXPECT_STREQ("A", targetNodes[0].c_str());
EXPECT_STREQ("A.C", targetNodes[1].c_str());
}
TEST_F(SceneGraphSelectorTest, UpdateNodeSelection_EmptySelection_AllNodesInSelected)
{
AZStd::vector<AZStd::string> selectedNodes;
AZStd::vector<AZStd::string> unselectedNodes;
CreateMeshGroup(selectedNodes, unselectedNodes);
SceneGraphSelector::UpdateNodeSelection(m_graph, m_testNodeSelectionList);
EXPECT_EQ(5, selectedNodes.size());
EXPECT_EQ(0, unselectedNodes.size());
}
TEST_F(SceneGraphSelectorTest, UpdateNodeSelection_UnselectedNodeA_AllNodesUnselectedExceptRoot)
{
AZStd::vector<AZStd::string> selectedNodes;
AZStd::vector<AZStd::string> unselectedNodes = { "A" };
CreateMeshGroup(selectedNodes, unselectedNodes);
SceneGraphSelector::UpdateNodeSelection(m_graph, m_testNodeSelectionList);
EXPECT_EQ(0, selectedNodes.size());
EXPECT_EQ(5, unselectedNodes.size());
}
TEST_F(SceneGraphSelectorTest, UpdateNodeSelection_DuplicateEntryRemovedFromSelected_ADotDNotFoundInSelectedNodes)
{
AZStd::vector<AZStd::string> selectedNodes = { "A", "A.B", "A.C", "A.D", "A.D.E" };
AZStd::vector<AZStd::string> unselectedNodes = { "A.D" };
CreateMeshGroup(selectedNodes, unselectedNodes);
SceneGraphSelector::UpdateNodeSelection(m_graph, m_testNodeSelectionList);
EXPECT_EQ(4, selectedNodes.size());
EXPECT_EQ(1, unselectedNodes.size());
EXPECT_EQ(selectedNodes.end(), AZStd::find(selectedNodes.begin(), selectedNodes.end(), "A.D"));
EXPECT_NE(unselectedNodes.end(), AZStd::find(unselectedNodes.begin(), unselectedNodes.end(), "A.D"));
}
TEST_F(SceneGraphSelectorTest, UpdateNodeSelection_InvalidEntryInSelected_InvalidEntryRemoved)
{
AZStd::vector<AZStd::string> selectedNodes = { "A", "A.B", "X", "A.C", "A.D", "A.D.E" };
AZStd::vector<AZStd::string> unselectedNodes;
CreateMeshGroup(selectedNodes, unselectedNodes);
SceneGraphSelector::UpdateNodeSelection(m_graph, m_testNodeSelectionList);
EXPECT_EQ(selectedNodes.end(), AZStd::find(selectedNodes.begin(), selectedNodes.end(), "X"));
}
TEST_F(SceneGraphSelectorTest, UpdateNodeSelection_InvalidEntryInUnselected_InvalidEntryRemoved)
{
AZStd::vector<AZStd::string> selectedNodes = { "A", "A.B", "A.C", "A.D", "A.D.E" };
AZStd::vector<AZStd::string> unselectedNodes = { "X" };
CreateMeshGroup(selectedNodes, unselectedNodes);
SceneGraphSelector::UpdateNodeSelection(m_graph, m_testNodeSelectionList);
EXPECT_EQ(unselectedNodes.end(), AZStd::find(unselectedNodes.begin(), unselectedNodes.end(), "X"));
}
}
}
}