From c9ea34d45fbdea80778b58ea8b64ac150ab89554 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 29 Sep 2021 14:58:22 -0700 Subject: [PATCH 1/4] Quick updates to AzNetworking unit tests Signed-off-by: puvvadar --- .../DataStructures/FixedSizeBitsetView.inl | 6 ++--- .../DataStructures/FixedSizeBitsetTests.cpp | 3 +++ .../FixedSizeBitsetViewTests.cpp | 23 +++++++++++++++++++ .../Tests/TcpTransport/TcpTransportTests.cpp | 5 ++++ .../Tests/UdpTransport/UdpTransportTests.cpp | 21 +++++++++++++++++ .../Tests/Utilities/IpAddressTests.cpp | 12 ++++++++++ .../Tests/Utilities/QuantizedValuesTests.cpp | 5 ++-- 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl index 8cbdd27e09..6192cfa878 100644 --- a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl +++ b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitsetView.inl @@ -15,12 +15,12 @@ namespace AzNetworking , m_startOffset(startOffset) , m_count(startOffset < bitset.GetValidBitCount() && startOffset + count <= bitset.GetValidBitCount() ? count : 0) { - AZ_Assert(startOffset + count <= bitset.GetValidBitCount(), "Out of bounds setup in BitsetSubset. Defaulting to 0 bit count."); + AZ_Warning("FixedSizeBitsetView", startOffset + count <= bitset.GetValidBitCount(), "Out of bounds setup in BitsetSubset. Defaulting to 0 bit count."); } inline void FixedSizeBitsetView::SetBit(uint32_t index, bool value) { - AZ_Assert(index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); + AZ_Warning("FixedSizeBitsetView", index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); if (m_count) { m_bitset.SetBit(m_startOffset + index, value); @@ -29,7 +29,7 @@ namespace AzNetworking inline bool FixedSizeBitsetView::GetBit(uint32_t index) const { - AZ_Assert(index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); + AZ_Warning("FixedSizeBitsetView", index < m_count, "Out of bounds access in BitsetSubset (requested %u, count %u)", index, m_count); if (m_count) { return m_bitset.GetBit(m_startOffset + index); diff --git a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp index f22e815526..12e242c86c 100644 --- a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp +++ b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetTests.cpp @@ -55,5 +55,8 @@ namespace UnitTest unusedBitTest.SetBit(i, false); } EXPECT_FALSE(unusedBitTest.AnySet()); + + unusedBitTest.SetBit(0, true); + EXPECT_TRUE(unusedBitTest.AnySet()); } } diff --git a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp index 6f32eacda9..37547ce5e9 100644 --- a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp +++ b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp @@ -42,4 +42,27 @@ namespace UnitTest EXPECT_FALSE(view.GetBit(0)); } } + + TEST(FixedSizeBitsetView, EmptyBitset) + { + AzNetworking::FixedSizeBitset<32> bitset; + AzNetworking::FixedSizeBitsetView view(bitset, 10, 0); + EXPECT_FALSE(view.GetBit(0)); + } + + TEST(FixedSizeBitsetView, TestAnySet) + { + AzNetworking::FixedSizeBitset<9> unusedBitTest(true); + AzNetworking::FixedSizeBitsetView view(unusedBitTest, 0, 5); + for (uint32_t i = 0; i < 5; ++i) + { + view.SetBit(i, false); + } + EXPECT_FALSE(view.AnySet()); + + view.SetBit(0, true); + EXPECT_TRUE(view.AnySet()); + + EXPECT_EQ(view.GetValidBitCount(), 5); + } } diff --git a/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp b/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp index bc9ecab2cb..3031f66774 100644 --- a/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp +++ b/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp @@ -148,6 +148,11 @@ namespace UnitTest EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); + + testClient.m_clientNetworkInterface->SetTimeoutEnabled(true); + EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled()); + + EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening()); } #if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS diff --git a/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp b/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp index c4de3fc6dd..91db3b4549 100644 --- a/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp +++ b/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp @@ -125,6 +125,18 @@ namespace UnitTest AzNetworking::NetworkingSystemComponent* m_networkingSystemComponent; }; + TEST_F(UdpTransportTests, PacketIdWrap) + { + const uint32_t SEQUENCE_BOUNDARY = 0xFFFF; + UdpPacketTracker tracker; + + for (uint32_t i = 0; i < SEQUENCE_BOUNDARY; ++i) + { + tracker.GetNextPacketId(); + } + EXPECT_EQ(tracker.GetNextPacketId(), PacketId(SEQUENCE_BOUNDARY + 1)); + } + TEST_F(UdpTransportTests, AckReplication) { static const SequenceId TestReliableSequenceId = InvalidSequenceId; @@ -266,6 +278,15 @@ namespace UnitTest EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1); + + testClient.m_clientNetworkInterface->SetTimeoutEnabled(true); + EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled()); + + EXPECT_FALSE(dynamic_cast(testClient.m_clientNetworkInterface)->IsEncrypted()); + + EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening()); + EXPECT_FALSE(testServer.m_serverNetworkInterface->StopListening()); + EXPECT_FALSE(dynamic_cast(testServer.m_serverNetworkInterface)->IsOpen()); } TEST_F(UdpTransportTests, TestMultipleClients) diff --git a/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp b/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp index 435ebb48e0..c143556670 100644 --- a/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Utilities/IpAddressTests.cpp @@ -11,4 +11,16 @@ namespace UnitTest { + TEST(IpAddressTests, TestIpQuads) + { + const AzNetworking::IpAddress ip = AzNetworking::IpAddress(127, 0, 0, 1, 12345); + + EXPECT_EQ(ip.GetQuadA(), 127); + EXPECT_EQ(ip.GetQuadB(), 0); + EXPECT_EQ(ip.GetQuadC(), 0); + EXPECT_EQ(ip.GetQuadD(), 1); + + EXPECT_EQ(ip.GetString(), "127.0.0.1:12345"); + EXPECT_EQ(ip.GetIpString(), "127.0.0.1"); + } } diff --git a/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp b/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp index 13bf9bdb0a..0f0bcac54d 100644 --- a/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp +++ b/Code/Framework/AzNetworking/Tests/Utilities/QuantizedValuesTests.cpp @@ -79,13 +79,12 @@ namespace UnitTest template void TestQuantizedValuesHelper01() { - AzNetworking::QuantizedValues testIn, testOut; // Transmits float values between 0 and 1 using NUM_BYTES + AzNetworking::QuantizedValues testIn(ValueFromFloat::Construct(0.0f)), testOut; // Transmits float values between 0 and 1 using NUM_BYTES AZStd::array buffer; AzNetworking::NetworkInputSerializer inputSerializer(buffer.data(), static_cast(buffer.size())); AzNetworking::NetworkOutputSerializer outputSerializer(buffer.data(), static_cast(buffer.size())); - testIn = ValueFromFloat::Construct(0.0f); EXPECT_EQ(static_cast::ValueType>(testIn), ValueFromFloat::Construct(0.0f)); testIn.Serialize(inputSerializer); EXPECT_EQ(inputSerializer.GetSize(), NUM_BYTES * NUM_ELEMENTS); @@ -95,6 +94,8 @@ namespace UnitTest testIn = ValueFromFloat::Construct(1.0f); EXPECT_EQ(static_cast::ValueType>(testIn), ValueFromFloat::Construct(1.0f)); testIn.Serialize(inputSerializer); + EXPECT_NE(testIn, testOut); + EXPECT_NE(testIn.GetQuantizedIntegralValues()[0], testOut.GetQuantizedIntegralValues()[0]); testOut.Serialize(outputSerializer); EXPECT_EQ(testIn, testOut); From 325294aef887f61f1552fd99518bc1170255ca00 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 29 Sep 2021 15:28:57 -0700 Subject: [PATCH 2/4] Remove magic number in AZN unit Signed-off-by: puvvadar --- .../Tests/DataStructures/FixedSizeBitsetViewTests.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp index 37547ce5e9..8ac3b63f1b 100644 --- a/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp +++ b/Code/Framework/AzNetworking/Tests/DataStructures/FixedSizeBitsetViewTests.cpp @@ -52,9 +52,11 @@ namespace UnitTest TEST(FixedSizeBitsetView, TestAnySet) { + const uint32_t VIEW_SIZE = 5; + AzNetworking::FixedSizeBitset<9> unusedBitTest(true); - AzNetworking::FixedSizeBitsetView view(unusedBitTest, 0, 5); - for (uint32_t i = 0; i < 5; ++i) + AzNetworking::FixedSizeBitsetView view(unusedBitTest, 0, VIEW_SIZE); + for (uint32_t i = 0; i < VIEW_SIZE; ++i) { view.SetBit(i, false); } @@ -63,6 +65,6 @@ namespace UnitTest view.SetBit(0, true); EXPECT_TRUE(view.AnySet()); - EXPECT_EQ(view.GetValidBitCount(), 5); + EXPECT_EQ(view.GetValidBitCount(), VIEW_SIZE); } } From 8d67f184c886a6c01b303329201b52b2e588bd6f Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:05:50 -0700 Subject: [PATCH 3/4] LYN-7008 | Focus Mode - Selection unit tests (#4357) * Refactor existing tests and fixtures, split them up in more granular tests, and add more comments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Refactor test fixture for FocusMode to make it more reusable Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fixture rename, draft of selection test Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Split SetFocus and ClearFocus tests for Editor Focus Mode Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Move BoundsTestComponent to its own file so that it can be reused in Focus Mode Selection tests Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Making progress on selection test. Test compiles now, but selection doesn't seem to be working. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Removed commented out code from previous iteration. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Move BoundsTestComponent under the UnitTest namespace Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Viewport selection tests + minor fixes. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor fixes Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Tests/BoundsTestComponent.cpp | 60 ++++++ .../Tests/BoundsTestComponent.h | 46 +++++ ...EditorTransformComponentSelectionTests.cpp | 79 +------- .../FocusMode/EditorFocusModeFixture.cpp | 78 ++++++++ .../Tests/FocusMode/EditorFocusModeFixture.h | 48 +++++ .../EditorFocusModeSelectionTests.cpp | 135 +++++++++++++ .../Tests/FocusMode/EditorFocusModeTests.cpp | 180 ++++++++---------- .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 156 +++++++++------ .../Tests/aztoolsframeworktests_files.cmake | 5 + 9 files changed, 548 insertions(+), 239 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp diff --git a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp new file mode 100644 index 0000000000..11a077f53c --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include + +namespace UnitTest +{ + AZ::Aabb BoundsTestComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo) + { + return GetWorldBounds(); + } + + bool BoundsTestComponent::EditorSelectionIntersectRayViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) + { + return AzToolsFramework::AabbIntersectRay(src, dir, GetWorldBounds(), distance); + } + + bool BoundsTestComponent::SupportsEditorRayIntersect() + { + return true; + } + + void BoundsTestComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) + { + // noop + } + + void BoundsTestComponent::Activate() + { + AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId()); + AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId()); + } + + void BoundsTestComponent::Deactivate() + { + AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect(); + AzFramework::BoundsRequestBus::Handler::BusDisconnect(); + } + + AZ::Aabb BoundsTestComponent::GetWorldBounds() + { + AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(worldFromLocal, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM); + return GetLocalBounds().GetTransformedAabb(worldFromLocal); + } + + AZ::Aabb BoundsTestComponent::GetLocalBounds() + { + return AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f), AZ::Vector3(0.5f)); + } + +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h new file mode 100644 index 0000000000..1aabcfcd64 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace UnitTest +{ + //! Basic component that implements BoundsRequestBus and EditorComponentSelectionRequestsBus to be compatible + //! with the Editor visibility system. + //! Note: Used for simulating selection (picking) in the viewport. + class BoundsTestComponent + : public AzToolsFramework::Components::EditorComponentBase + , public AzFramework::BoundsRequestBus::Handler + , public AzToolsFramework::EditorComponentSelectionRequestsBus::Handler + { + public: + AZ_EDITOR_COMPONENT( + BoundsTestComponent, "{E6312E9D-8489-4677-9980-C93C328BC92C}", AzToolsFramework::Components::EditorComponentBase); + + static void Reflect(AZ::ReflectContext* context); + + // AZ::Component overrides ... + void Activate() override; + void Deactivate() override; + + // EditorComponentSelectionRequestsBus overrides ... + AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override; + bool EditorSelectionIntersectRayViewport( + const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override; + bool SupportsEditorRayIntersect() override; + + // BoundsRequestBus overrides ... + AZ::Aabb GetWorldBounds() override; + AZ::Aabb GetLocalBounds() override; + }; + +} // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp index 4229ebb8c4..81909ac511 100644 --- a/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -22,12 +21,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -41,6 +38,8 @@ #include #include +#include + namespace AZ { std::ostream& operator<<(std::ostream& os, const EntityId entityId) @@ -123,80 +122,6 @@ namespace UnitTest EXPECT_FALSE(m_cache.IsVisibleEntityVisible(m_cache.GetVisibleEntityIndexFromId(m_entityIds[2]).value())); } - //! Basic component that implements BoundsRequestBus and EditorComponentSelectionRequestsBus to be compatible - //! with the Editor visibility system. - //! Note: Used for simulating selection (picking) in the viewport. - class BoundsTestComponent - : public AzToolsFramework::Components::EditorComponentBase - , public AzFramework::BoundsRequestBus::Handler - , public AzToolsFramework::EditorComponentSelectionRequestsBus::Handler - { - public: - AZ_EDITOR_COMPONENT( - BoundsTestComponent, "{E6312E9D-8489-4677-9980-C93C328BC92C}", AzToolsFramework::Components::EditorComponentBase); - - static void Reflect(AZ::ReflectContext* context); - - // AZ::Component overrides ... - void Activate() override; - void Deactivate() override; - - // EditorComponentSelectionRequestsBus overrides ... - AZ::Aabb GetEditorSelectionBoundsViewport(const AzFramework::ViewportInfo& viewportInfo) override; - bool EditorSelectionIntersectRayViewport( - const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override; - bool SupportsEditorRayIntersect() override; - - // BoundsRequestBus overrides ... - AZ::Aabb GetWorldBounds() override; - AZ::Aabb GetLocalBounds() override; - }; - - AZ::Aabb BoundsTestComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo) - { - return GetWorldBounds(); - } - - bool BoundsTestComponent::EditorSelectionIntersectRayViewport( - [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) - { - return AzToolsFramework::AabbIntersectRay(src, dir, GetWorldBounds(), distance); - } - - bool BoundsTestComponent::SupportsEditorRayIntersect() - { - return true; - } - - void BoundsTestComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) - { - // noop - } - - void BoundsTestComponent::Activate() - { - AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId()); - AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId()); - } - - void BoundsTestComponent::Deactivate() - { - AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect(); - AzFramework::BoundsRequestBus::Handler::BusDisconnect(); - } - - AZ::Aabb BoundsTestComponent::GetWorldBounds() - { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult(worldFromLocal, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM); - return GetLocalBounds().GetTransformedAabb(worldFromLocal); - } - - AZ::Aabb BoundsTestComponent::GetLocalBounds() - { - return AZ::Aabb::CreateFromMinMax(AZ::Vector3(-0.5f), AZ::Vector3(0.5f)); - } - // Fixture to support testing EditorTransformComponentSelection functionality on an Entity selection. class EditorTransformComponentSelectionFixture : public ToolsApplicationFixture { diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp new file mode 100644 index 0000000000..bc026a4baf --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include + +#include + +namespace AzToolsFramework +{ + void EditorFocusModeFixture::SetUpEditorFixtureImpl() + { + // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // in the unit tests. + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); + + m_focusModeInterface = AZ::Interface::Get(); + ASSERT_TRUE(m_focusModeInterface != nullptr); + + // register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus + GetApplication()->RegisterComponentDescriptor(UnitTest::BoundsTestComponent::CreateDescriptor()); + + GenerateTestHierarchy(); + } + + void EditorFocusModeFixture::GenerateTestHierarchy() + { + /* + * City + * |_ Street + * |_ Car + * | |_ Passenger + * |_ SportsCar + * |_ Passenger + */ + + m_entityMap[CityEntityName] = CreateEditorEntity(CityEntityName, AZ::EntityId()); + m_entityMap[StreetEntityName] = CreateEditorEntity(StreetEntityName, m_entityMap[CityEntityName]); + m_entityMap[CarEntityName] = CreateEditorEntity(CarEntityName, m_entityMap[StreetEntityName]); + m_entityMap[Passenger1EntityName] = CreateEditorEntity(Passenger1EntityName, m_entityMap[CarEntityName]); + m_entityMap[SportsCarEntityName] = CreateEditorEntity(SportsCarEntityName, m_entityMap[StreetEntityName]); + m_entityMap[Passenger2EntityName] = CreateEditorEntity(Passenger2EntityName, m_entityMap[SportsCarEntityName]); + + // Add a BoundsTestComponent to the Car entity. + AZ::Entity* entity = GetEntityById(m_entityMap[CarEntityName]); + + entity->Deactivate(); + entity->CreateComponent(); + entity->Activate(); + + // Move the CarEntity so it's out of the way. + AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, CarEntityPosition); + + // Setup the camera so the Car entity is in view. + AzFramework::SetCameraTransform( + m_cameraState, + AZ::Transform::CreateFromQuaternionAndTranslation( + AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 0.0f)), CameraPosition)); + } + + AZ::EntityId EditorFocusModeFixture::CreateEditorEntity(const char* name, AZ::EntityId parentId) + { + AZ::Entity* entity = nullptr; + UnitTest::CreateDefaultEditorEntity(name, &entity); + + // Parent + AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId); + + return entity->GetId(); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h new file mode 100644 index 0000000000..a461b45e1b --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include + +namespace AzToolsFramework +{ + class EditorFocusModeFixture + : public UnitTest::ToolsApplicationFixture + { + protected: + void SetUpEditorFixtureImpl() override; + + void GenerateTestHierarchy(); + AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId); + + AZStd::unordered_map m_entityMap; + FocusModeInterface* m_focusModeInterface = nullptr; + + public: + AzFramework::CameraState m_cameraState; + + inline static const AZ::Vector3 CameraPosition = AZ::Vector3(10.0f, 15.0f, 10.0f); + + inline static const char* CityEntityName = "City"; + inline static const char* StreetEntityName = "Street"; + inline static const char* CarEntityName = "Car"; + inline static const char* SportsCarEntityName = "SportsCar"; + inline static const char* Passenger1EntityName = "Passenger1"; + inline static const char* Passenger2EntityName = "Passenger2"; + + inline static AZ::Vector3 CarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f); + }; +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp new file mode 100644 index 0000000000..750137814d --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace AzToolsFramework +{ + class EditorFocusModeSelectionFixture + : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin + { + public: + void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition) + { + // Calculate the world position in screen space + const auto carScreenPosition = AzFramework::WorldToScreen(worldPosition, m_cameraState); + + // Click the entity in the viewport + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); + } + }; + + void ClearSelectedEntities() + { + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::SetSelectedEntities, AzToolsFramework::EntityIdList()); + } + + AzToolsFramework::EntityIdList GetSelectedEntities() + { + AzToolsFramework::EntityIdList selectedEntities; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( + selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities); + return selectedEntities; + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnLevel) + { + // Clear the focus, disabling focus mode + m_focusModeInterface->ClearFocusRoot(); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // Verify entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnAncestor) + { + // Set the focus on the Street Entity (parent of the test entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // Verify entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnItself) + { + // Set the focus on the Car Entity (test entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // Verify entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnSibling) + { + // Set the focus on the SportsCar Entity (sibling of the test entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 0); + } + + TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnDescendant) + { + // Set the focus on the Passenger1 Entity (child of the entity) + m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]); + // Clear selection + ClearSelectedEntities(); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(CarEntityPosition); + + // entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 0); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp index 5972da58a7..7dfdff655a 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp @@ -6,123 +6,99 @@ * */ -#include -#include -#include -#include -#include +#include namespace AzToolsFramework { - class EditorFocusModeTests - : public ::testing::Test + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_SetFocus) { - protected: - void SetUp() override - { - m_app.Start(m_descriptor); + // When an entity is set as the focus root, GetFocusRoot should return its EntityId. + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); + EXPECT_EQ(m_focusModeInterface->GetFocusRoot(), m_entityMap[CarEntityName]); - // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash - // in the unit tests. - AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - - GenerateTestHierarchy(); - } - - void GenerateTestHierarchy() - { - /* - * City - * |_ Street - * |_ Car - * | |_ Passenger - * |_ SportsCar - * |_ Passenger - */ - - m_entityMap["cityId"] = CreateEditorEntity("City", AZ::EntityId()); - m_entityMap["streetId"] = CreateEditorEntity("Street", m_entityMap["cityId"]); - m_entityMap["carId"] = CreateEditorEntity("Car", m_entityMap["streetId"]); - m_entityMap["passengerId1"] = CreateEditorEntity("Passenger", m_entityMap["carId"]); - m_entityMap["sportsCarId"] = CreateEditorEntity("SportsCar", m_entityMap["streetId"]); - m_entityMap["passengerId2"] = CreateEditorEntity("Passenger", m_entityMap["sportsCarId"]); - } - - AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId) - { - AZ::Entity* entity = nullptr; - UnitTest::CreateDefaultEditorEntity(name, &entity); - - // Parent - AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId); - - return entity->GetId(); - } - - void TearDown() override - { - m_app.Stop(); - } - - UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" }; - AZ::ComponentApplication::Descriptor m_descriptor; - AZStd::unordered_map m_entityMap; - }; - - TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus) - { - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - EXPECT_TRUE(focusModeInterface != nullptr); - - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]); - - focusModeInterface->ClearFocusRoot(); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId()); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); } - TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree) + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_ClearFocus) { - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - EXPECT_TRUE(focusModeInterface != nullptr); + // Change the value from the default. + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - focusModeInterface->ClearFocusRoot(); - - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); + // Calling ClearFocusRoot restores the default focus root (which is an invalid EntityId). + m_focusModeInterface->ClearFocusRoot(); + EXPECT_EQ(m_focusModeInterface->GetFocusRoot(), AZ::EntityId()); + } - focusModeInterface->SetFocusRoot(m_entityMap["streetId"]); + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants) + { + // When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't. + { + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); + } - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), false); + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings) + { + // If the root entity has siblings, they are also outside of the focus subtree. + { + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false); + } - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false); - EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } - focusModeInterface->ClearFocusRoot(); + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf) + { + // If the root is a leaf, then the focus subtree will consists of just that entity. + { + m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]); + + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); + } + + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } + + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear) + { + // Change the value from the default. + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); + + // When the focus is cleared, the whole level is in the focus subtree; so we expect all entities to return true. + { + m_focusModeInterface->ClearFocusRoot(); + + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); + } } } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index ffd6cd2a44..d3c3a2250b 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -30,88 +30,127 @@ namespace UnitTest * |_ Passenger */ - m_entityMap["passenger1"] = CreateEntity("Passenger1"); - m_entityMap["passenger2"] = CreateEntity("Passenger2"); - m_entityMap["city"] = CreateEntity("City"); + // Create loose entities + m_entityMap[Passenger1EntityName] = CreateEntity(Passenger1EntityName); + m_entityMap[Passenger2EntityName] = CreateEntity(Passenger2EntityName); + m_entityMap[CityEntityName] = CreateEntity(CityEntityName); + // Call HandleEntitiesAdded to the loose entities to register them with the Prefab EOS AzToolsFramework::EditorEntityContextRequestBus::Broadcast( &AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, - AzToolsFramework::EntityList{ m_entityMap["passenger1"], m_entityMap["passenger2"], m_entityMap["city"] }); + AzToolsFramework::EntityList{ m_entityMap[Passenger1EntityName], m_entityMap[Passenger2EntityName], m_entityMap[CityEntityName] }); + // Create a car prefab from the passenger1 entity. The container entity will be created as part of the process. AZStd::unique_ptr carInstance = - m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car"); + m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger1EntityName] }, {}, "test/car"); ASSERT_TRUE(carInstance); - m_instanceMap["car"] = carInstance.get(); + m_instanceMap[CarEntityName] = carInstance.get(); + // Create a sportscar prefab from the passenger2 entity. The container entity will be created as part of the process. AZStd::unique_ptr sportsCarInstance = - m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar"); + m_prefabSystemComponent->CreatePrefab({ m_entityMap[Passenger2EntityName] }, {}, "test/sportsCar"); ASSERT_TRUE(sportsCarInstance); - m_instanceMap["sportsCar"] = sportsCarInstance.get(); + m_instanceMap[SportsCarEntityName] = sportsCarInstance.get(); + // Create a street prefab that nests the car and sportscar instances created above. The container entity will be created as part of the process. AZStd::unique_ptr streetInstance = m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street"); ASSERT_TRUE(streetInstance); - m_instanceMap["street"] = streetInstance.get(); + m_instanceMap[StreetEntityName] = streetInstance.get(); + // Create a city prefab that nests the street instances created above and the city entity. The container entity will be created as part of the process. m_rootInstance = - m_prefabSystemComponent->CreatePrefab({ m_entityMap["city"] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city"); + m_prefabSystemComponent->CreatePrefab({ m_entityMap[CityEntityName] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city"); ASSERT_TRUE(m_rootInstance); - m_instanceMap["city"] = m_rootInstance.get(); + m_instanceMap[CityEntityName] = m_rootInstance.get(); + } + + void SetUpEditorFixtureImpl() override + { + PrefabTestFixture::SetUpEditorFixtureImpl(); + + m_prefabFocusInterface = AZ::Interface::Get(); + ASSERT_TRUE(m_prefabFocusInterface != nullptr); + + GenerateTestHierarchy(); + } + + void TearDownEditorFixtureImpl() override + { + m_rootInstance.release(); + + PrefabTestFixture::TearDownEditorFixtureImpl(); } AZStd::unordered_map m_entityMap; AZStd::unordered_map m_instanceMap; AZStd::unique_ptr m_rootInstance; + + PrefabFocusInterface* m_prefabFocusInterface = nullptr; + + inline static const char* CityEntityName = "City"; + inline static const char* StreetEntityName = "Street"; + inline static const char* CarEntityName = "Car"; + inline static const char* SportsCarEntityName = "SportsCar"; + inline static const char* Passenger1EntityName = "Passenger1"; + inline static const char* Passenger2EntityName = "Passenger2"; }; - TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab) + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_RootContainer) { - GenerateTestHierarchy(); - - PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get(); - EXPECT_TRUE(prefabFocusInterface != nullptr); - // Verify FocusOnOwningPrefab works when passing the container entity of the root prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CityEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["city"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_RootEntity) + { // Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_entityMap[CityEntityName]->GetId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CityEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["city"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CityEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedContainer) + { // Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CarEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["car"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_NestedEntity) + { // Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab. { - prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_entityMap[Passenger1EntityName]->GetId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap[CarEntityName]->GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); - EXPECT_EQ(&instance->get(), m_instanceMap["car"]); + EXPECT_EQ(&instance->get(), m_instanceMap[CarEntityName]); } + } + TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab_Clear) + { // Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared. { AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = @@ -120,54 +159,51 @@ namespace UnitTest prefabEditorEntityOwnershipInterface->GetRootPrefabInstance(); EXPECT_TRUE(rootPrefabInstance.has_value()); - prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); - EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId()); + m_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); + EXPECT_EQ(m_prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId()); - auto instance = prefabFocusInterface->GetFocusedPrefabInstance(); + auto instance = m_prefabFocusInterface->GetFocusedPrefabInstance(); EXPECT_TRUE(instance.has_value()); EXPECT_EQ(&instance->get(), &rootPrefabInstance->get()); } - - m_rootInstance.release(); } - TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused) + TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Content) { - GenerateTestHierarchy(); - - PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get(); - EXPECT_TRUE(prefabFocusInterface != nullptr); - // Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested) { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId())); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); } + } + TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_AncestorsDescendants) + { // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants) { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["street"]->GetContainerEntityId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[StreetEntityName]->GetContainerEntityId()); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["street"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[StreetEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); } + } + TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused_Siblings) + { // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings) { - prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["sportsCar"]->GetContainerEntityId()); + m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[SportsCarEntityName]->GetContainerEntityId()); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["sportsCar"]->GetContainerEntityId())); - EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger2"]->GetId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId())); - EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[SportsCarEntityName]->GetContainerEntityId())); + EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger2EntityName]->GetId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); } - - m_rootInstance.release(); } } diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index ecc7d17ccc..11ea5a0b38 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -12,6 +12,8 @@ set(FILES AssetFileInfoListComparison.cpp AssetSeedManager.cpp AssetSystemMocks.h + BoundsTestComponent.cpp + BoundsTestComponent.h ComponentAdapterTests.cpp ComponentAddRemove.cpp ComponentModeTestDoubles.cpp @@ -34,6 +36,9 @@ set(FILES EntityTestbed.h FileFunc.cpp FingerprintingTests.cpp + FocusMode/EditorFocusModeFixture.cpp + FocusMode/EditorFocusModeFixture.h + FocusMode/EditorFocusModeSelectionTests.cpp FocusMode/EditorFocusModeTests.cpp GenericComponentWrapperTest.cpp InstanceDataHierarchy.cpp From 3635e5ed355ada79b1e362576116d3d6e1fef384 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Thu, 30 Sep 2021 11:09:04 -0600 Subject: [PATCH 4/4] Put the ShaderMetrics.json in the @user@ folder, plus an unrelated #include path fix. (#4402) Signed-off-by: bosnichd --- .../Common/Unimplemented/Platform_Unimplemented.cpp | 2 +- .../Shader/Metrics/ShaderMetricsSystem.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp b/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp index ea6c6bc5b8..afa75d8333 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp +++ b/Code/Framework/AzTest/AzTest/Platform/Common/Unimplemented/Platform_Unimplemented.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include "Platform.h" +#include #include class ModuleHandle diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp index 528d32e217..e11624a921 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp @@ -23,11 +23,11 @@ namespace AZ { namespace RPI { - AZStd::string GetMetricsFilePath() + AZ::IO::FixedMaxPath GetMetricsFilePath() { - char shaderMetricPath[AZ_MAX_PATH_LEN]; - AZ::Utils::GetExecutableDirectory(shaderMetricPath, AZ_MAX_PATH_LEN); - return AZStd::string(shaderMetricPath) + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "ShaderMetrics.json"; + AZ::IO::FixedMaxPath resolvedPath; + AZ::IO::LocalFileIO::GetInstance()->ResolvePath(resolvedPath, "@user@/ShaderMetrics.json"); + return resolvedPath; } ShaderMetricsSystemInterface* ShaderMetricsSystemInterface::Get() @@ -64,7 +64,7 @@ namespace AZ void ShaderMetricsSystem::ReadLog() { - const AZStd::string metricsFilePath = GetMetricsFilePath(); + const AZ::IO::FixedMaxPath metricsFilePath = GetMetricsFilePath(); if (AZ::IO::LocalFileIO::GetInstance()->Exists(metricsFilePath.c_str())) { @@ -80,7 +80,7 @@ namespace AZ void ShaderMetricsSystem::WriteLog() { - const AZStd::string metricsFilePath = GetMetricsFilePath(); + const AZ::IO::FixedMaxPath metricsFilePath = GetMetricsFilePath(); auto saveResult = AZ::JsonSerializationUtils::SaveObjectToFile(&m_metrics, metricsFilePath.c_str());