From c9ea34d45fbdea80778b58ea8b64ac150ab89554 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Wed, 29 Sep 2021 14:58:22 -0700 Subject: [PATCH 1/6] 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/6] 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 ffbc3f1c800b97b390199911878c1b2045e79b04 Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Thu, 30 Sep 2021 20:56:11 +0530 Subject: [PATCH 3/6] Fix a bug in recursion of prefab links when checking for dirty prefabs (#4392) * Fix a bug in recursion of prefab links when checking for dirty prefabs Signed-off-by: srikappa-amzn * Added a missing EntityId header Signed-off-by: srikappa-amzn --- .../AzToolsFramework/Prefab/PrefabSystemComponent.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 0d2696f14b..6ef2d756fb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -818,7 +818,14 @@ namespace AzToolsFramework auto linkIterator = m_linkIdMap.find(linkId); if (linkIterator != m_linkIdMap.end()) { - return AreDirtyTemplatesPresent(linkIterator->second.GetSourceTemplateId()); + if (AreDirtyTemplatesPresent(linkIterator->second.GetSourceTemplateId())) + { + return true; + } + else + { + continue; + } } } return false; From b1c82fc0458f51760f391199191df82a38580c4e Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 30 Sep 2021 10:57:54 -0500 Subject: [PATCH 4/6] Updated references to Engine.pak to be lowercase engine.pak (#4397) * Updated references to Engine.pak to be lowercase engine.pak This makes the engine.pak file consistent with naming scheme of other pak files such as assets.pak. It will also help avoid issues with mounting the file on Linux. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Engine.pak now loads correctly in release builds. The check for the file existing was failing in release builds because it was only checking inside packs. OpenPack first checks if the file exists, anyways, so it was safe to remove. Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Co-authored-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- .../Application/GameApplication.cpp | 15 ++++++--------- Code/Legacy/CrySystem/SystemInit.cpp | 4 ++-- cmake/Projects.cmake | 6 +++--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index f759857505..475a7d5504 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -32,17 +32,14 @@ namespace AzGameFramework // at the Assets alias, otherwise to attempting to mount the engine pak // from the Cache folder AZ::IO::FixedMaxPath enginePakPath = AZ::Utils::GetExecutableDirectory(); - enginePakPath /= "Engine.pak"; - if (m_archiveFileIO->Exists(enginePakPath.c_str())) + enginePakPath /= "engine.pak"; + if (!m_archive->OpenPack("@assets@", enginePakPath.Native())) { - m_archive->OpenPack("@assets@", enginePakPath.Native()); - } - else if (enginePakPath.clear(); m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) - { - // fall back to checking if there is an Engine.pak in the Asset Cache - enginePakPath /= "Engine.pak"; - if (m_archiveFileIO->Exists(enginePakPath.c_str())) + enginePakPath.clear(); + if (m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { + // fall back to checking Project Cache Root. + enginePakPath /= "engine.pak"; m_archive->OpenPack("@assets@", enginePakPath.Native()); } } diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 2c70717e8f..3187095094 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -808,7 +808,7 @@ void CSystem::OpenBasicPaks() const char* const assetsDir = "@assets@"; // After game paks to have same search order as with files on disk - m_env.pCryPak->OpenPack(assetsDir, "Engine.pak"); + m_env.pCryPak->OpenPack(assetsDir, "engine.pak"); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15 @@ -1261,7 +1261,7 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init Create console"); // Need to load the engine.pak that includes the config files needed during initialization - m_env.pCryPak->OpenPack("@assets@", "Engine.pak"); + m_env.pCryPak->OpenPack("@assets@", "engine.pak"); InitFileSystem_LoadEngineFolders(startupParams); diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index d3f4b33b03..61cb101909 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -151,18 +151,18 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") if(NOT DEFINED LY_ASSET_DEPLOY_ASSET_TYPE) set(LY_ASSET_DEPLOY_ASSET_TYPE @LY_ASSET_DEPLOY_ASSET_TYPE@) endif() - message(STATUS "Generating ${install_output_folder}/Engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") + message(STATUS "Generating ${install_output_folder}/engine.pak from @full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(MAKE_DIRECTORY "${install_output_folder}") cmake_path(SET cache_product_path "@full_directory_path@/Cache/${LY_ASSET_DEPLOY_ASSET_TYPE}") file(GLOB product_assets "${cache_product_path}/*") if(product_assets) execute_process( - COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_output_folder}/Engine.pak" --format=zip -- ${product_assets} + COMMAND ${CMAKE_COMMAND} -E tar "cf" "${install_output_folder}/engine.pak" --format=zip -- ${product_assets} WORKING_DIRECTORY "${cache_product_path}" RESULT_VARIABLE archive_creation_result ) if(archive_creation_result EQUAL 0) - message(STATUS "${install_output_folder}/Engine.pak generated") + message(STATUS "${install_output_folder}/engine.pak generated") endif() endif() endif() 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 5/6] 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 | 172 ++++++++---------- .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 156 ++++++++++------ .../Tests/aztoolsframeworktests_files.cmake | 5 + 9 files changed, 544 insertions(+), 235 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); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } - GenerateTestHierarchy(); - } + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_ClearFocus) + { + // Change the value from the default. + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - 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"]); - } + // Calling ClearFocusRoot restores the default focus root (which is an invalid EntityId). + m_focusModeInterface->ClearFocusRoot(); + EXPECT_EQ(m_focusModeInterface->GetFocusRoot(), AZ::EntityId()); + } - AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId) + 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. { - AZ::Entity* entity = nullptr; - UnitTest::CreateDefaultEditorEntity(name, &entity); - - // Parent - AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId); - - return entity->GetId(); + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); + + 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); } - void TearDown() override + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } + + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings) + { + // If the root entity has siblings, they are also outside of the focus subtree. { - m_app.Stop(); + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); + + 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); } - UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" }; - AZ::ComponentApplication::Descriptor m_descriptor; - AZStd::unordered_map m_entityMap; - }; + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); + } - TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus) + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf) { - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - EXPECT_TRUE(focusModeInterface != nullptr); - - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]); + // 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); + } - focusModeInterface->ClearFocusRoot(); - EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId()); + // Restore default expected focus. + m_focusModeInterface->ClearFocusRoot(); } - TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree) + TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear) { - FocusModeInterface* focusModeInterface = AZ::Interface::Get(); - EXPECT_TRUE(focusModeInterface != nullptr); - - 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); - - focusModeInterface->SetFocusRoot(m_entityMap["streetId"]); - - 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); - - focusModeInterface->SetFocusRoot(m_entityMap["carId"]); - - 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); - - focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]); - - 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); - - focusModeInterface->ClearFocusRoot(); + // 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 6/6] 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());