RagdollEditTests.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <gmock/gmock.h>
  9. #include <gtest/gtest.h>
  10. #include <QtTest>
  11. #include <QTreeView>
  12. #include <QPushButton>
  13. #include <Editor/Plugins/ColliderWidgets/RagdollOutlinerNotificationHandler.h>
  14. #include <Editor/Plugins/ColliderWidgets/RagdollNodeWidget.h>
  15. #include <Editor/Plugins/SkeletonOutliner/SkeletonOutlinerPlugin.h>
  16. #include <Editor/ColliderHelpers.h>
  17. #include <EMotionFX/Source/Actor.h>
  18. #include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
  19. #include <Tests/TestAssetCode/ActorFactory.h>
  20. #include <Tests/TestAssetCode/SimpleActors.h>
  21. #include <Tests/TestAssetCode/TestActorAssets.h>
  22. #include <Tests/UI/UIFixture.h>
  23. #include <Tests/UI/SkeletonOutlinerTestFixture.h>
  24. #include <Editor/ReselectingTreeView.h>
  25. #include <Tests/D6JointLimitConfiguration.h>
  26. #include <Tests/Mocks/PhysicsSystem.h>
  27. namespace EMotionFX
  28. {
  29. class RagdollEditTestsFixture : public SkeletonOutlinerTestFixture
  30. {
  31. public:
  32. void SetUp() override
  33. {
  34. //first setup expect_call, then run SetUp
  35. using ::testing::_;
  36. EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeIds)
  37. .WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{ azrtti_typeid<D6JointLimitConfiguration>() }));
  38. EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeId(_))
  39. .WillRepeatedly(
  40. [](AzPhysics::JointType jointType) -> AZStd::optional<const AZ::TypeId>
  41. {
  42. if (jointType == AzPhysics::JointType::D6Joint)
  43. {
  44. return azrtti_typeid<D6JointLimitConfiguration>();
  45. }
  46. return AZStd::nullopt;
  47. });
  48. EXPECT_CALL(m_jointHelpers, ComputeInitialJointLimitConfiguration(_, _, _, _, _))
  49. .WillRepeatedly(
  50. []([[maybe_unused]] const AZ::TypeId& jointLimitTypeId,
  51. [[maybe_unused]] const AZ::Quaternion& parentWorldRotation,
  52. [[maybe_unused]] const AZ::Quaternion& childWorldRotation,
  53. [[maybe_unused]] const AZ::Vector3& axis,
  54. [[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
  55. {
  56. return AZStd::make_unique<D6JointLimitConfiguration>();
  57. });
  58. UIFixture::SetUp();
  59. }
  60. void TearDown() override
  61. {
  62. QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
  63. UIFixture::TearDown();
  64. }
  65. protected:
  66. virtual bool ShouldReflectPhysicSystem() override { return true; }
  67. Physics::MockPhysicsSystem m_physicsSystem;
  68. Physics::MockPhysicsInterface m_physicsInterface;
  69. Physics::MockJointHelpersInterface m_jointHelpers;
  70. };
  71. TEST_F(RagdollEditTestsFixture, RagdollAddJoint)
  72. {
  73. const int numJoints = 6;
  74. RecordProperty("test_case_id", "C3122249");
  75. AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
  76. AZ::Data::Asset<Integration::ActorAsset> actorAsset =
  77. TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, numJoints, "RagdollEditTestsActor");
  78. CreateSkeletonAndModelIndices();
  79. EXPECT_EQ(m_indexList.size(), numJoints);
  80. // Find the 3rd joint after the RootJoint in the TreeView and select it
  81. SelectIndexes(m_indexList, m_treeView, 3, 3);
  82. QTreeView* treeView = GetAddCollidersTreeView();
  83. auto index = treeView->model()->index(2, 0);
  84. treeView->clicked(index);
  85. // Check the node is in the ragdoll
  86. EXPECT_TRUE(ColliderHelpers::NodeHasRagdoll(m_indexList[3]));
  87. }
  88. TEST_F(RagdollEditTestsFixture, RagdollAddJointsAndRemove)
  89. {
  90. const int numJoints = 8;
  91. RecordProperty("test_case_id", "C3122248");
  92. AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}");
  93. AZ::Data::Asset<Integration::ActorAsset> actorAsset =
  94. TestActorAssets::CreateActorAssetAndRegister<SimpleJointChainActor>(actorAssetId, numJoints, "RagdollEditTestsActor");
  95. CreateSkeletonAndModelIndices();
  96. EXPECT_EQ(m_indexList.size(), numJoints);
  97. // Select four Indexes
  98. SelectIndexes(m_indexList, m_treeView, 3, 6);
  99. // Bring up the contextMenu
  100. const QRect rect = m_treeView->visualRect(m_indexList[5]);
  101. EXPECT_TRUE(rect.isValid());
  102. BringUpContextMenu(m_treeView, rect);
  103. QMenu* contextMenu = m_skeletonOutlinerPlugin->GetDockWidget()->findChild<QMenu*>("EMFX.SkeletonOutlinerPlugin.ContextMenu");
  104. EXPECT_TRUE(contextMenu);
  105. QAction* ragdollAction;
  106. EXPECT_TRUE(UIFixture::GetActionFromContextMenu(ragdollAction, contextMenu, "Ragdoll"));
  107. QMenu* ragdollMenu = ragdollAction->menu();
  108. EXPECT_TRUE(ragdollMenu);
  109. QAction* addToRagdollAction;
  110. EXPECT_TRUE(UIFixture::GetActionFromContextMenu(addToRagdollAction, ragdollMenu, "Add to ragdoll"));
  111. addToRagdollAction->trigger();
  112. // Check the nodes are in the ragdoll
  113. EXPECT_TRUE(ColliderHelpers::NodeHasRagdoll(m_indexList[3]));
  114. EXPECT_TRUE(ColliderHelpers::NodeHasRagdoll(m_indexList[4]));
  115. EXPECT_TRUE(ColliderHelpers::NodeHasRagdoll(m_indexList[5]));
  116. EXPECT_TRUE(ColliderHelpers::NodeHasRagdoll(m_indexList[6]));
  117. // Remove context menu as it is rebuild below
  118. delete contextMenu;
  119. const QRect rect2 = m_treeView->visualRect(m_indexList[4]);
  120. EXPECT_TRUE(rect2.isValid());
  121. BringUpContextMenu(m_treeView, rect2);
  122. // Find the "Remove from ragdoll" entry and trigger it.
  123. contextMenu = m_skeletonOutlinerPlugin->GetDockWidget()->findChild<QMenu*>("EMFX.SkeletonOutlinerPlugin.ContextMenu");
  124. EXPECT_TRUE(contextMenu);
  125. EXPECT_TRUE(UIFixture::GetActionFromContextMenu(ragdollAction, contextMenu, "Ragdoll"));
  126. ragdollMenu = ragdollAction->menu();
  127. QAction* removeFromRagdollAction;
  128. EXPECT_TRUE(UIFixture::GetActionFromContextMenu(removeFromRagdollAction, ragdollMenu, "Remove from ragdoll"));
  129. removeFromRagdollAction->trigger();
  130. // Check the nodes are removed from ragdoll
  131. EXPECT_FALSE(ColliderHelpers::NodeHasRagdoll(m_indexList[3]));
  132. EXPECT_FALSE(ColliderHelpers::NodeHasRagdoll(m_indexList[4]));
  133. EXPECT_FALSE(ColliderHelpers::NodeHasRagdoll(m_indexList[5]));
  134. EXPECT_FALSE(ColliderHelpers::NodeHasRagdoll(m_indexList[6]));
  135. }
  136. }