CommandAdjustSimulatedObjectTests.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  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 <AzTest/AzTest.h>
  9. #include <sstream>
  10. #include <AzCore/Memory/Memory.h>
  11. #include <AzCore/UnitTest/TestTypes.h>
  12. #include <AzCore/std/optional.h>
  13. #include <AzCore/std/smart_ptr/make_shared.h>
  14. #include <AzCore/std/string/conversions.h>
  15. #include <AzCore/std/string/string.h>
  16. #include <AzFramework/Physics/SystemBus.h>
  17. #include <EMotionFX/CommandSystem/Source/CommandManager.h>
  18. #include <EMotionFX/Source/Actor.h>
  19. #include <EMotionFX/Source/ActorManager.h>
  20. #include <EMotionFX/Source/Allocators.h>
  21. #include <EMotionFX/Source/AnimGraph.h>
  22. #include <EMotionFX/Source/AnimGraphManager.h>
  23. #include <EMotionFX/Source/AnimGraphNode.h>
  24. #include <EMotionFX/Source/AnimGraphObjectIds.h>
  25. #include <EMotionFX/Source/EMotionFXManager.h>
  26. #include <EMotionFX/Source/Node.h>
  27. #include <EMotionFX/Source/SimulatedObjectSetup.h>
  28. #include <EMotionFX/Source/SimulatedObjectBus.h>
  29. #include <EMotionFX/Source/AnimGraphStateTransition.h>
  30. #include <EMotionFX/Source/AnimGraphTransitionCondition.h>
  31. #include <MCore/Source/Command.h>
  32. #include <MCore/Source/ReflectionSerializer.h>
  33. #include <Tests/Printers.h>
  34. #include <Tests/Matchers.h>
  35. namespace CommandAdjustSimulatedObjectTests
  36. {
  37. namespace EMotionFX
  38. {
  39. // Import real types from the production namespace
  40. using ::EMotionFX::AnimGraphConnectionId;
  41. using ::EMotionFX::AnimGraphNodeId;
  42. using ::EMotionFX::AnimGraphObject;
  43. using ::EMotionFX::BlendTreeConnection;
  44. using ::EMotionFX::ValueParameter;
  45. using ::EMotionFX::CommandAllocator;
  46. using ::EMotionFX::AnimGraphAllocator;
  47. using ::EMotionFX::PhysicsSetup;
  48. using ::EMotionFX::SimulatedObjectNotificationBus;
  49. // Forward-declare types that will be mocked
  50. class Actor;
  51. class ActorManager;
  52. class AnimGraph;
  53. class AnimGraphInstance;
  54. class AnimGraphManager;
  55. class AnimGraphNode;
  56. class AnimGraphStateTransition;
  57. class EMotionFXManager;
  58. class GroupParameter;
  59. class Parameter;
  60. class SimulatedJoint;
  61. class SimulatedObject;
  62. class SimulatedObjectSetup;
  63. } // namespace EMotionFX
  64. namespace EMotionFX
  65. {
  66. typedef AZStd::vector<GroupParameter*> GroupParameterVector;
  67. typedef AZStd::vector<Parameter*> ParameterVector;
  68. typedef AZStd::vector<ValueParameter*> ValueParameterVector;
  69. }
  70. #include <Tests/Mocks/Parameter.h>
  71. #include <Tests/Mocks/GroupParameter.h>
  72. #include <Tests/Mocks/Actor.h>
  73. #include <Tests/Mocks/ActorManager.h>
  74. #include <Tests/Mocks/AnimGraphTransitionCondition.h>
  75. #include <Tests/Mocks/AnimGraph.h>
  76. #include <Tests/Mocks/AnimGraphInstance.h>
  77. #include <Tests/Mocks/AnimGraphManager.h>
  78. #include <Tests/Mocks/AnimGraphNode.h>
  79. #include <Tests/Mocks/AnimGraphStateTransition.h>
  80. #include <Tests/Mocks/EMotionFXManager.h>
  81. #include <Tests/Mocks/SimulatedJoint.h>
  82. #include <Tests/Mocks/SimulatedObject.h>
  83. #include <Tests/Mocks/SimulatedObjectSetup.h>
  84. #include <EMotionFX/CommandSystem/Source/ParameterMixins_Interface.inl>
  85. #include <EMotionFX/CommandSystem/Source/ParameterMixins_Impl.inl>
  86. #include <EMotionFX/CommandSystem/Source/SimulatedObjectCommands_Interface.inl>
  87. #include <EMotionFX/CommandSystem/Source/SimulatedObjectCommands_Impl.inl>
  88. } // namespace CommandAdjustSimulatedObjectTests
  89. namespace EMotionFX
  90. {
  91. namespace UnderTest
  92. {
  93. using namespace ::CommandAdjustSimulatedObjectTests::EMotionFX;
  94. } // namespace UnderTest
  95. ///////////////////////////////////////////////////////////////////////////
  96. // CommandAdjustSimulatedObject tests
  97. ///////////////////////////////////////////////////////////////////////////
  98. struct CommandAdjustSimulatedObjectTestsParam
  99. {
  100. AZStd::optional<std::string> objectName;
  101. AZStd::optional<float> gravityFactor;
  102. AZStd::optional<float> stiffnessFactor;
  103. AZStd::optional<float> dampingFactor;
  104. AZStd::optional<std::vector<std::string>> colliderTags;
  105. void (*setExecuteExpectations)(UnderTest::SimulatedObject*);
  106. void (*setUndoExpectations)(UnderTest::SimulatedObject*);
  107. };
  108. class CommandAdjustSimulatedObjectTestsFixture
  109. : public UnitTest::LeakDetectionFixture
  110. , public ::testing::WithParamInterface<::testing::tuple<bool, bool, CommandAdjustSimulatedObjectTestsParam>>
  111. {
  112. public:
  113. static std::string buildCommandLineFromTestParam(const CommandAdjustSimulatedObjectTestsParam& param)
  114. {
  115. std::string string;
  116. std::stringstream stream(string);
  117. if (param.objectName.has_value())
  118. {
  119. stream << " -" << UnderTest::CommandAdjustSimulatedObject::s_objectNameParameterName << ' ' << param.objectName.value();
  120. }
  121. if (param.gravityFactor.has_value())
  122. {
  123. stream << " -" << UnderTest::CommandAdjustSimulatedObject::s_gravityFactorParameterName << ' ' << param.gravityFactor.value();
  124. }
  125. if (param.stiffnessFactor.has_value())
  126. {
  127. stream << " -" << UnderTest::CommandAdjustSimulatedObject::s_stiffnessFactorParameterName << ' ' << param.stiffnessFactor.value();
  128. }
  129. if (param.dampingFactor.has_value())
  130. {
  131. stream << " -" << UnderTest::CommandAdjustSimulatedObject::s_dampingFactorParameterName << ' ' << param.dampingFactor.value();
  132. }
  133. if (param.colliderTags.has_value())
  134. {
  135. stream << " -" << UnderTest::CommandAdjustSimulatedObject::s_colliderTagsParameterName << ' ';
  136. for (const std::string& val : *param.colliderTags)
  137. {
  138. stream << val;
  139. if (&val != std::addressof(*(param.colliderTags->end() - 1)))
  140. {
  141. stream << ";";
  142. }
  143. }
  144. }
  145. return stream.str();
  146. }
  147. };
  148. TEST_P(CommandAdjustSimulatedObjectTestsFixture, TestExecute)
  149. {
  150. using ::testing::Return;
  151. using ::testing::ReturnRef;
  152. const AZStd::string nameString {"Old name"};
  153. UnderTest::EMotionFXManager& manager = UnderTest::GetEMotionFX();
  154. UnderTest::ActorManager actorManager;
  155. UnderTest::Actor actor;
  156. auto simulatedObjectSetup = AZStd::make_shared<UnderTest::SimulatedObjectSetup>();
  157. UnderTest::SimulatedObject simulatedObject;
  158. EXPECT_CALL(manager, GetActorManager())
  159. .WillRepeatedly(Return(&actorManager));
  160. EXPECT_CALL(actorManager, FindActorByID(0))
  161. .WillRepeatedly(Return(&actor));
  162. EXPECT_CALL(actor, GetSimulatedObjectSetup())
  163. .WillRepeatedly(ReturnRef(simulatedObjectSetup));
  164. EXPECT_CALL(actor, GetDirtyFlag())
  165. .WillOnce(Return(false));
  166. EXPECT_CALL(*simulatedObjectSetup, GetSimulatedObject(0))
  167. .WillRepeatedly(Return(&simulatedObject));
  168. EXPECT_CALL(*simulatedObjectSetup, IsSimulatedObjectNameUnique(StrEq("New name"), &simulatedObject))
  169. .WillRepeatedly(Return(true));
  170. EXPECT_CALL(*simulatedObjectSetup, IsSimulatedObjectNameUnique(StrEq("Old name"), &simulatedObject))
  171. .WillRepeatedly(Return(true));
  172. // GetName returns a reference, so the return value for it has to be
  173. // defined in a place where that reference will exist
  174. EXPECT_CALL(simulatedObject, GetName())
  175. .WillRepeatedly(::testing::ReturnRef(nameString));
  176. AZStd::vector<AZStd::string> defaultColliderTags;
  177. EXPECT_CALL(simulatedObject, GetColliderTags())
  178. .WillRepeatedly(testing::ReturnRef(defaultColliderTags));
  179. const bool doExecuteOnly = ::testing::get<0>(GetParam());
  180. const bool useCommandString = ::testing::get<1>(GetParam());
  181. const CommandAdjustSimulatedObjectTestsParam& testParams = ::testing::get<2>(GetParam());
  182. if (doExecuteOnly)
  183. {
  184. EXPECT_CALL(actor, SetDirtyFlag(true));
  185. testParams.setExecuteExpectations(&simulatedObject);
  186. }
  187. else
  188. {
  189. {
  190. testing::InSequence sequence;
  191. EXPECT_CALL(actor, SetDirtyFlag(true))
  192. .RetiresOnSaturation();
  193. EXPECT_CALL(actor, SetDirtyFlag(false))
  194. .RetiresOnSaturation();
  195. }
  196. testParams.setUndoExpectations(&simulatedObject);
  197. }
  198. AZStd::string paramString {"-actorId 0 -objectIndex 0"};
  199. paramString += AZStd::string(buildCommandLineFromTestParam(testParams).c_str());
  200. MCore::CommandLine parameters(paramString);
  201. AZStd::string outResult;
  202. UnderTest::CommandAdjustSimulatedObject command(/*actorId=*/0, /*objectIndex=*/0);
  203. if (useCommandString)
  204. {
  205. EXPECT_TRUE(command.SetCommandParameters(parameters));
  206. }
  207. else
  208. {
  209. if (testParams.objectName)
  210. {
  211. command.SetObjectName(AZStd::string(testParams.objectName->c_str(), testParams.objectName->size()));
  212. }
  213. command.SetGravityFactor(testParams.gravityFactor);
  214. command.SetStiffnessFactor(testParams.stiffnessFactor);
  215. command.SetDampingFactor(testParams.dampingFactor);
  216. if (testParams.colliderTags)
  217. {
  218. AZStd::vector<AZStd::string> value;
  219. for (const std::string& stdstring : testParams.colliderTags.value())
  220. {
  221. value.emplace_back(stdstring.c_str(), stdstring.size());
  222. }
  223. command.SetColliderTags(value);
  224. }
  225. }
  226. EXPECT_TRUE(command.Execute(parameters, outResult)) << outResult.c_str();
  227. if (!doExecuteOnly)
  228. {
  229. EXPECT_TRUE(command.Undo(parameters, outResult)) << outResult.c_str();
  230. }
  231. }
  232. INSTANTIATE_TEST_CASE_P(TestCommandAdjustSimulatedObject, CommandAdjustSimulatedObjectTestsFixture,
  233. ::testing::Combine(
  234. ::testing::Bool(), // Test execute or test undo
  235. ::testing::Bool(), // Use command strings or not
  236. ::testing::ValuesIn({
  237. CommandAdjustSimulatedObjectTestsParam
  238. {
  239. "New name",
  240. AZStd::nullopt,
  241. AZStd::nullopt,
  242. AZStd::nullopt,
  243. AZStd::nullopt,
  244. [](UnderTest::SimulatedObject* simulatedObject)
  245. {
  246. EXPECT_CALL(*simulatedObject, SetName(StrEq("New name")))
  247. .Times(1);
  248. },
  249. [](UnderTest::SimulatedObject* simulatedObject)
  250. {
  251. ::testing::InSequence sequence;
  252. EXPECT_CALL(*simulatedObject, SetName(StrEq("New name")))
  253. .Times(1);
  254. EXPECT_CALL(*simulatedObject, SetName(StrEq("Old name")))
  255. .Times(1);
  256. }
  257. },
  258. CommandAdjustSimulatedObjectTestsParam
  259. {
  260. AZStd::nullopt,
  261. 2.2f,
  262. AZStd::nullopt,
  263. AZStd::nullopt,
  264. AZStd::nullopt,
  265. [](UnderTest::SimulatedObject* simulatedObject)
  266. {
  267. ::testing::InSequence sequence;
  268. EXPECT_CALL(*simulatedObject, GetGravityFactor())
  269. .Times(1)
  270. .WillOnce(::testing::Return(1.2f));
  271. EXPECT_CALL(*simulatedObject, SetGravityFactor(::testing::FloatEq(2.2f)))
  272. .Times(1);
  273. },
  274. [](UnderTest::SimulatedObject* simulatedObject)
  275. {
  276. ::testing::InSequence sequence;
  277. EXPECT_CALL(*simulatedObject, GetGravityFactor())
  278. .Times(1)
  279. .WillOnce(::testing::Return(1.2f));
  280. EXPECT_CALL(*simulatedObject, SetGravityFactor(::testing::FloatEq(2.2f)))
  281. .Times(1);
  282. EXPECT_CALL(*simulatedObject, SetGravityFactor(::testing::FloatEq(1.2f)))
  283. .Times(1);
  284. }
  285. },
  286. CommandAdjustSimulatedObjectTestsParam
  287. {
  288. AZStd::nullopt,
  289. AZStd::nullopt,
  290. 3.2f,
  291. AZStd::nullopt,
  292. AZStd::nullopt,
  293. [](UnderTest::SimulatedObject* simulatedObject)
  294. {
  295. ::testing::InSequence sequence;
  296. EXPECT_CALL(*simulatedObject, GetStiffnessFactor())
  297. .Times(1)
  298. .WillOnce(::testing::Return(2.2f));
  299. EXPECT_CALL(*simulatedObject, SetStiffnessFactor(::testing::FloatEq(3.2f)))
  300. .Times(1);
  301. },
  302. [](UnderTest::SimulatedObject* simulatedObject)
  303. {
  304. ::testing::InSequence sequence;
  305. EXPECT_CALL(*simulatedObject, GetStiffnessFactor())
  306. .Times(1)
  307. .WillOnce(::testing::Return(2.2f));
  308. EXPECT_CALL(*simulatedObject, SetStiffnessFactor(::testing::FloatEq(3.2f)))
  309. .Times(1);
  310. EXPECT_CALL(*simulatedObject, SetStiffnessFactor(::testing::FloatEq(2.2f)))
  311. .Times(1);
  312. }
  313. },
  314. CommandAdjustSimulatedObjectTestsParam
  315. {
  316. AZStd::nullopt,
  317. AZStd::nullopt,
  318. AZStd::nullopt,
  319. 4.2f,
  320. AZStd::nullopt,
  321. [](UnderTest::SimulatedObject* simulatedObject)
  322. {
  323. ::testing::InSequence sequence;
  324. EXPECT_CALL(*simulatedObject, GetDampingFactor())
  325. .Times(1)
  326. .WillOnce(::testing::Return(3.2f));
  327. EXPECT_CALL(*simulatedObject, SetDampingFactor(::testing::FloatEq(4.2f)))
  328. .Times(1);
  329. },
  330. [](UnderTest::SimulatedObject* simulatedObject)
  331. {
  332. ::testing::InSequence sequence;
  333. EXPECT_CALL(*simulatedObject, GetDampingFactor())
  334. .Times(1)
  335. .WillOnce(::testing::Return(3.2f));
  336. EXPECT_CALL(*simulatedObject, SetDampingFactor(::testing::FloatEq(4.2f)))
  337. .Times(1);
  338. EXPECT_CALL(*simulatedObject, SetDampingFactor(::testing::FloatEq(3.2f)))
  339. .Times(1);
  340. }
  341. },
  342. CommandAdjustSimulatedObjectTestsParam
  343. {
  344. AZStd::nullopt,
  345. AZStd::nullopt,
  346. AZStd::nullopt,
  347. AZStd::nullopt,
  348. std::vector<std::string>{"left_knee", "right_knee"},
  349. [](UnderTest::SimulatedObject* simulatedObject)
  350. {
  351. EXPECT_CALL(*simulatedObject, SetColliderTags(::testing::Pointwise(StrEq(), std::vector<std::string> {"left_knee", "right_knee"})))
  352. .Times(1);
  353. },
  354. [](UnderTest::SimulatedObject* simulatedObject)
  355. {
  356. ::testing::InSequence sequence;
  357. EXPECT_CALL(*simulatedObject, SetColliderTags(::testing::Pointwise(StrEq(), std::vector<std::string> {"left_knee", "right_knee"})))
  358. .Times(1);
  359. EXPECT_CALL(*simulatedObject, SetColliderTags(::testing::Pointwise(StrEq(), std::vector<std::string> {})))
  360. .Times(1);
  361. }
  362. },
  363. })
  364. ),
  365. [](const ::testing::TestParamInfo<::testing::tuple<bool, bool, CommandAdjustSimulatedObjectTestsParam>>& info)
  366. {
  367. std::string cmdline =
  368. (::testing::get<0>(info.param) ? std::string {"Execute_"} : std::string {"Undo_"})
  369. + (::testing::get<1>(info.param) ? std::string {"UseCommandString"} : std::string {"UseSetters"})
  370. + CommandAdjustSimulatedObjectTestsFixture::buildCommandLineFromTestParam(::testing::get<2>(info.param));
  371. std::replace(cmdline.begin(), cmdline.end(), ' ', '_');
  372. std::replace(cmdline.begin(), cmdline.end(), ';', '_');
  373. cmdline.erase(std::remove(cmdline.begin(), cmdline.end(), '-'), cmdline.end());
  374. cmdline.erase(std::remove(cmdline.begin(), cmdline.end(), '.'), cmdline.end());
  375. return cmdline;
  376. }
  377. );
  378. ///////////////////////////////////////////////////////////////////////////
  379. // CommandAdjustSimulatedJoint tests
  380. ///////////////////////////////////////////////////////////////////////////
  381. struct CommandAdjustSimulatedJointTestsParam
  382. {
  383. AZStd::optional<float> coneAngleLimit;
  384. AZStd::optional<float> mass;
  385. AZStd::optional<float> stiffness;
  386. AZStd::optional<float> damping;
  387. AZStd::optional<float> gravityFactor;
  388. AZStd::optional<float> friction;
  389. AZStd::optional<bool> pinned;
  390. AZStd::optional<std::vector<std::string>> colliderExclusionTags;
  391. AZStd::optional<SimulatedJoint::AutoExcludeMode> autoExcludeMode;
  392. AZStd::optional<bool> geometricAutoExclusion;
  393. void (*setExecuteExpectations)(UnderTest::SimulatedJoint*);
  394. void (*setUndoExpectations)(UnderTest::SimulatedJoint*);
  395. };
  396. class CommandAdjustSimulatedJointTestsFixture
  397. : public UnitTest::LeakDetectionFixture
  398. , public ::testing::WithParamInterface<::testing::tuple<bool, bool, CommandAdjustSimulatedJointTestsParam>>
  399. {
  400. public:
  401. static std::string buildCommandLineFromTestParam(const CommandAdjustSimulatedJointTestsParam& param)
  402. {
  403. std::string string;
  404. std::stringstream stream(string);
  405. if (param.coneAngleLimit.has_value())
  406. {
  407. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_coneAngleLimitParameterName << ' ' << param.coneAngleLimit.value();
  408. }
  409. if (param.mass.has_value())
  410. {
  411. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_massParameterName << ' ' << param.mass.value();
  412. }
  413. if (param.stiffness.has_value())
  414. {
  415. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_stiffnessParameterName << ' ' << param.stiffness.value();
  416. }
  417. if (param.damping.has_value())
  418. {
  419. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_dampingParameterName << ' ' << param.damping.value();
  420. }
  421. if (param.gravityFactor.has_value())
  422. {
  423. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_gravityFactorParameterName << ' ' << param.gravityFactor.value();
  424. }
  425. if (param.friction.has_value())
  426. {
  427. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_frictionParameterName << ' ' << param.friction.value();
  428. }
  429. if (param.pinned.has_value())
  430. {
  431. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_pinnedParameterName << ' ' << (param.pinned.value() ? "true" : "false");
  432. }
  433. if (param.colliderExclusionTags.has_value())
  434. {
  435. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_colliderExclusionTagsParameterName << ' ';
  436. for (const std::string& val : *param.colliderExclusionTags)
  437. {
  438. stream << val;
  439. if (&val != std::addressof(*(param.colliderExclusionTags->end() - 1)))
  440. {
  441. stream << ";";
  442. }
  443. }
  444. }
  445. if (param.autoExcludeMode.has_value())
  446. {
  447. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_autoExcludeModeParameterName << ' ';
  448. switch (param.autoExcludeMode.value())
  449. {
  450. case SimulatedJoint::AutoExcludeMode::None:
  451. stream << "None";
  452. break;
  453. case SimulatedJoint::AutoExcludeMode::Self:
  454. stream << "Self";
  455. break;
  456. case SimulatedJoint::AutoExcludeMode::SelfAndNeighbors:
  457. stream << "SelfAndNeighbors";
  458. break;
  459. case SimulatedJoint::AutoExcludeMode::All:
  460. stream << "All";
  461. break;
  462. };
  463. }
  464. if (param.geometricAutoExclusion.has_value())
  465. {
  466. stream << " -" << UnderTest::CommandAdjustSimulatedJoint::s_geometricAutoExclusionParameterName << ' ' << (param.geometricAutoExclusion.value() ? "true" : "false");
  467. }
  468. return stream.str();
  469. }
  470. };
  471. TEST_P(CommandAdjustSimulatedJointTestsFixture, TestExecute)
  472. {
  473. using ::testing::Return;
  474. using ::testing::ReturnRef;
  475. UnderTest::EMotionFXManager& manager = UnderTest::GetEMotionFX();
  476. UnderTest::ActorManager actorManager;
  477. UnderTest::Actor actor;
  478. auto simulatedObjectSetup = AZStd::make_shared<UnderTest::SimulatedObjectSetup>();
  479. UnderTest::SimulatedObject simulatedObject;
  480. UnderTest::SimulatedJoint simulatedJoint;
  481. EXPECT_CALL(manager, GetActorManager())
  482. .WillRepeatedly(Return(&actorManager));
  483. EXPECT_CALL(actorManager, FindActorByID(0))
  484. .WillRepeatedly(Return(&actor));
  485. EXPECT_CALL(actor, GetSimulatedObjectSetup())
  486. .WillRepeatedly(ReturnRef(simulatedObjectSetup));
  487. EXPECT_CALL(actor, GetDirtyFlag())
  488. .WillOnce(Return(false));
  489. EXPECT_CALL(*simulatedObjectSetup, GetSimulatedObject(0))
  490. .WillRepeatedly(Return(&simulatedObject));
  491. EXPECT_CALL(simulatedObject, GetSimulatedJoint(0))
  492. .WillRepeatedly(Return(&simulatedJoint));
  493. AZStd::vector<AZStd::string> defaultColliderExclusionTags;
  494. EXPECT_CALL(simulatedJoint, GetColliderExclusionTags())
  495. .WillRepeatedly(testing::ReturnRef(defaultColliderExclusionTags));
  496. const bool doExecuteOnly = ::testing::get<0>(GetParam());
  497. const bool useCommandString = ::testing::get<1>(GetParam());
  498. const auto& testParams = ::testing::get<2>(GetParam());
  499. if (doExecuteOnly)
  500. {
  501. EXPECT_CALL(actor, SetDirtyFlag(true));
  502. testParams.setExecuteExpectations(&simulatedJoint);
  503. }
  504. else
  505. {
  506. {
  507. testing::InSequence sequence;
  508. EXPECT_CALL(actor, SetDirtyFlag(true))
  509. .RetiresOnSaturation();
  510. EXPECT_CALL(actor, SetDirtyFlag(false))
  511. .RetiresOnSaturation();
  512. }
  513. testParams.setUndoExpectations(&simulatedJoint);
  514. }
  515. AZStd::string paramString {"-actorId 0 -objectIndex 0 -jointIndex 0"};
  516. paramString += AZStd::string(buildCommandLineFromTestParam(testParams).c_str());
  517. MCore::CommandLine parameters(paramString);
  518. AZStd::string outResult;
  519. UnderTest::CommandAdjustSimulatedJoint command(/*actorId=*/0, /*objectIndex=*/0, /*jointIndex=*/0);
  520. if (useCommandString)
  521. {
  522. EXPECT_TRUE(command.SetCommandParameters(parameters));
  523. }
  524. else
  525. {
  526. if (testParams.coneAngleLimit.has_value())
  527. {
  528. command.SetConeAngleLimit(testParams.coneAngleLimit.value());
  529. }
  530. if (testParams.mass.has_value())
  531. {
  532. command.SetMass(testParams.mass.value());
  533. }
  534. if (testParams.stiffness.has_value())
  535. {
  536. command.SetStiffness(testParams.stiffness.value());
  537. }
  538. if (testParams.damping.has_value())
  539. {
  540. command.SetDamping(testParams.damping.value());
  541. }
  542. if (testParams.gravityFactor.has_value())
  543. {
  544. command.SetGravityFactor(testParams.gravityFactor.value());
  545. }
  546. if (testParams.friction.has_value())
  547. {
  548. command.SetFriction(testParams.friction.value());
  549. }
  550. if (testParams.pinned.has_value())
  551. {
  552. command.SetPinned(testParams.pinned.value());
  553. }
  554. if (testParams.colliderExclusionTags.has_value())
  555. {
  556. AZStd::vector<AZStd::string> value;
  557. for (const std::string& stdstring : testParams.colliderExclusionTags.value())
  558. {
  559. value.emplace_back(stdstring.c_str(), stdstring.size());
  560. }
  561. command.SetColliderExclusionTags(value);
  562. }
  563. if (testParams.autoExcludeMode.has_value())
  564. {
  565. command.SetAutoExcludeMode(testParams.autoExcludeMode.value());
  566. }
  567. if (testParams.geometricAutoExclusion.has_value())
  568. {
  569. command.SetGeometricAutoExclusion(testParams.geometricAutoExclusion.has_value());
  570. }
  571. }
  572. EXPECT_TRUE(command.Execute(parameters, outResult)) << outResult.c_str();
  573. if (!doExecuteOnly)
  574. {
  575. EXPECT_TRUE(command.Undo(parameters, outResult)) << outResult.c_str();
  576. }
  577. }
  578. INSTANTIATE_TEST_CASE_P(TestCommandAdjustSimulatedJoint, CommandAdjustSimulatedJointTestsFixture,
  579. ::testing::Combine(
  580. ::testing::Bool(), // Test execute or test undo
  581. ::testing::Bool(), // Use command strings or not
  582. ::testing::ValuesIn(
  583. {
  584. CommandAdjustSimulatedJointTestsParam
  585. {
  586. /* coneAngleLimit = */ 0.3f,
  587. /* mass = */ AZStd::nullopt,
  588. /* stiffness = */ AZStd::nullopt,
  589. /* damping = */ AZStd::nullopt,
  590. /* gravityFactor = */ AZStd::nullopt,
  591. /* friction = */ AZStd::nullopt,
  592. /* pinned = */ AZStd::nullopt,
  593. /* colliderExclusionTags = */ AZStd::nullopt,
  594. /* autoExcludeMode = */ AZStd::nullopt,
  595. /* geometricAutoExclusion = */ AZStd::nullopt,
  596. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  597. {
  598. ::testing::InSequence sequence;
  599. EXPECT_CALL(*simulatedJoint, GetConeAngleLimit())
  600. .Times(1)
  601. .WillOnce(::testing::Return(0.8f));
  602. EXPECT_CALL(*simulatedJoint, SetConeAngleLimit(::testing::FloatEq(0.3f)))
  603. .Times(1);
  604. },
  605. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  606. {
  607. ::testing::InSequence sequence;
  608. EXPECT_CALL(*simulatedJoint, GetConeAngleLimit())
  609. .Times(1)
  610. .WillOnce(::testing::Return(0.8f));
  611. EXPECT_CALL(*simulatedJoint, SetConeAngleLimit(::testing::FloatEq(0.3f)))
  612. .Times(1);
  613. EXPECT_CALL(*simulatedJoint, SetConeAngleLimit(::testing::FloatEq(0.8f)))
  614. .Times(1);
  615. }
  616. },
  617. CommandAdjustSimulatedJointTestsParam
  618. {
  619. /* coneAngleLimit = */ AZStd::nullopt,
  620. /* mass = */ 0.3f,
  621. /* stiffness = */ AZStd::nullopt,
  622. /* damping = */ AZStd::nullopt,
  623. /* gravityFactor = */ AZStd::nullopt,
  624. /* friction = */ AZStd::nullopt,
  625. /* pinned = */ AZStd::nullopt,
  626. /* colliderExclusionTags = */ AZStd::nullopt,
  627. /* autoExcludeMode = */ AZStd::nullopt,
  628. /* geometricAutoExclusion = */ AZStd::nullopt,
  629. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  630. {
  631. ::testing::InSequence sequence;
  632. EXPECT_CALL(*simulatedJoint, GetMass())
  633. .Times(1)
  634. .WillOnce(::testing::Return(0.8f));
  635. EXPECT_CALL(*simulatedJoint, SetMass(::testing::FloatEq(0.3f)))
  636. .Times(1);
  637. },
  638. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  639. {
  640. ::testing::InSequence sequence;
  641. EXPECT_CALL(*simulatedJoint, GetMass())
  642. .Times(1)
  643. .WillOnce(::testing::Return(0.8f));
  644. EXPECT_CALL(*simulatedJoint, SetMass(::testing::FloatEq(0.3f)))
  645. .Times(1);
  646. EXPECT_CALL(*simulatedJoint, SetMass(::testing::FloatEq(0.8f)))
  647. .Times(1);
  648. }
  649. },
  650. CommandAdjustSimulatedJointTestsParam
  651. {
  652. /* coneAngleLimit = */ AZStd::nullopt,
  653. /* mass = */ AZStd::nullopt,
  654. /* stiffness = */ 0.3f,
  655. /* damping = */ AZStd::nullopt,
  656. /* gravityFactor = */ AZStd::nullopt,
  657. /* friction = */ AZStd::nullopt,
  658. /* pinned = */ AZStd::nullopt,
  659. /* colliderExclusionTags = */ AZStd::nullopt,
  660. /* autoExcludeMode = */ AZStd::nullopt,
  661. /* geometricAutoExclusion = */ AZStd::nullopt,
  662. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  663. {
  664. ::testing::InSequence sequence;
  665. EXPECT_CALL(*simulatedJoint, GetStiffness())
  666. .Times(1)
  667. .WillOnce(::testing::Return(0.8f));
  668. EXPECT_CALL(*simulatedJoint, SetStiffness(::testing::FloatEq(0.3f)))
  669. .Times(1);
  670. },
  671. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  672. {
  673. ::testing::InSequence sequence;
  674. EXPECT_CALL(*simulatedJoint, GetStiffness())
  675. .Times(1)
  676. .WillOnce(::testing::Return(0.8f));
  677. EXPECT_CALL(*simulatedJoint, SetStiffness(::testing::FloatEq(0.3f)))
  678. .Times(1);
  679. EXPECT_CALL(*simulatedJoint, SetStiffness(::testing::FloatEq(0.8f)))
  680. .Times(1);
  681. }
  682. },
  683. CommandAdjustSimulatedJointTestsParam
  684. {
  685. /* coneAngleLimit = */ AZStd::nullopt,
  686. /* mass = */ AZStd::nullopt,
  687. /* stiffness = */ AZStd::nullopt,
  688. /* damping = */ 0.3f,
  689. /* gravityFactor = */ AZStd::nullopt,
  690. /* friction = */ AZStd::nullopt,
  691. /* pinned = */ AZStd::nullopt,
  692. /* colliderExclusionTags = */ AZStd::nullopt,
  693. /* autoExcludeMode = */ AZStd::nullopt,
  694. /* geometricAutoExclusion = */ AZStd::nullopt,
  695. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  696. {
  697. ::testing::InSequence sequence;
  698. EXPECT_CALL(*simulatedJoint, GetDamping())
  699. .Times(1)
  700. .WillOnce(::testing::Return(0.8f));
  701. EXPECT_CALL(*simulatedJoint, SetDamping(::testing::FloatEq(0.3f)))
  702. .Times(1);
  703. },
  704. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  705. {
  706. ::testing::InSequence sequence;
  707. EXPECT_CALL(*simulatedJoint, GetDamping())
  708. .Times(1)
  709. .WillOnce(::testing::Return(0.8f));
  710. EXPECT_CALL(*simulatedJoint, SetDamping(::testing::FloatEq(0.3f)))
  711. .Times(1);
  712. EXPECT_CALL(*simulatedJoint, SetDamping(::testing::FloatEq(0.8f)))
  713. .Times(1);
  714. }
  715. },
  716. CommandAdjustSimulatedJointTestsParam
  717. {
  718. /* coneAngleLimit = */ AZStd::nullopt,
  719. /* mass = */ AZStd::nullopt,
  720. /* stiffness = */ AZStd::nullopt,
  721. /* damping = */ AZStd::nullopt,
  722. /* gravityFactor = */ 0.3f,
  723. /* friction = */ AZStd::nullopt,
  724. /* pinned = */ AZStd::nullopt,
  725. /* colliderExclusionTags = */ AZStd::nullopt,
  726. /* autoExcludeMode = */ AZStd::nullopt,
  727. /* geometricAutoExclusion = */ AZStd::nullopt,
  728. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  729. {
  730. ::testing::InSequence sequence;
  731. EXPECT_CALL(*simulatedJoint, GetGravityFactor())
  732. .Times(1)
  733. .WillOnce(::testing::Return(0.8f));
  734. EXPECT_CALL(*simulatedJoint, SetGravityFactor(::testing::FloatEq(0.3f)))
  735. .Times(1);
  736. },
  737. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  738. {
  739. ::testing::InSequence sequence;
  740. EXPECT_CALL(*simulatedJoint, GetGravityFactor())
  741. .Times(1)
  742. .WillOnce(::testing::Return(0.8f));
  743. EXPECT_CALL(*simulatedJoint, SetGravityFactor(::testing::FloatEq(0.3f)))
  744. .Times(1);
  745. EXPECT_CALL(*simulatedJoint, SetGravityFactor(::testing::FloatEq(0.8f)))
  746. .Times(1);
  747. }
  748. },
  749. CommandAdjustSimulatedJointTestsParam
  750. {
  751. /* coneAngleLimit = */ AZStd::nullopt,
  752. /* mass = */ AZStd::nullopt,
  753. /* stiffness = */ AZStd::nullopt,
  754. /* damping = */ AZStd::nullopt,
  755. /* gravityFactor = */ AZStd::nullopt,
  756. /* friction = */ 0.3f,
  757. /* pinned = */ AZStd::nullopt,
  758. /* colliderExclusionTags = */ AZStd::nullopt,
  759. /* autoExcludeMode = */ AZStd::nullopt,
  760. /* geometricAutoExclusion = */ AZStd::nullopt,
  761. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  762. {
  763. ::testing::InSequence sequence;
  764. EXPECT_CALL(*simulatedJoint, GetFriction())
  765. .Times(1)
  766. .WillOnce(::testing::Return(0.8f));
  767. EXPECT_CALL(*simulatedJoint, SetFriction(::testing::FloatEq(0.3f)))
  768. .Times(1);
  769. },
  770. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  771. {
  772. ::testing::InSequence sequence;
  773. EXPECT_CALL(*simulatedJoint, GetFriction())
  774. .Times(1)
  775. .WillOnce(::testing::Return(0.8f));
  776. EXPECT_CALL(*simulatedJoint, SetFriction(::testing::FloatEq(0.3f)))
  777. .Times(1);
  778. EXPECT_CALL(*simulatedJoint, SetFriction(::testing::FloatEq(0.8f)))
  779. .Times(1);
  780. }
  781. },
  782. CommandAdjustSimulatedJointTestsParam
  783. {
  784. /* coneAngleLimit = */ AZStd::nullopt,
  785. /* mass = */ AZStd::nullopt,
  786. /* stiffness = */ AZStd::nullopt,
  787. /* damping = */ AZStd::nullopt,
  788. /* gravityFactor = */ AZStd::nullopt,
  789. /* friction = */ AZStd::nullopt,
  790. /* pinned = */ true,
  791. /* colliderExclusionTags = */ AZStd::nullopt,
  792. /* autoExcludeMode = */ AZStd::nullopt,
  793. /* geometricAutoExclusion = */ AZStd::nullopt,
  794. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  795. {
  796. ::testing::InSequence sequence;
  797. EXPECT_CALL(*simulatedJoint, IsPinned())
  798. .Times(1)
  799. .WillOnce(::testing::Return(false));
  800. EXPECT_CALL(*simulatedJoint, SetPinned(true))
  801. .Times(1);
  802. },
  803. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint* simulatedJoint)
  804. {
  805. ::testing::InSequence sequence;
  806. EXPECT_CALL(*simulatedJoint, IsPinned())
  807. .Times(1)
  808. .WillOnce(::testing::Return(false));
  809. EXPECT_CALL(*simulatedJoint, SetPinned(true))
  810. .Times(1);
  811. EXPECT_CALL(*simulatedJoint, SetPinned(false))
  812. .Times(1);
  813. }
  814. },
  815. CommandAdjustSimulatedJointTestsParam
  816. {
  817. /* coneAngleLimit = */ AZStd::nullopt,
  818. /* mass = */ AZStd::nullopt,
  819. /* stiffness = */ AZStd::nullopt,
  820. /* damping = */ AZStd::nullopt,
  821. /* gravityFactor = */ AZStd::nullopt,
  822. /* friction = */ AZStd::nullopt,
  823. /* pinned = */ AZStd::nullopt,
  824. /* colliderExclusionTags = */ std::vector<std::string>{"left_knee", "right_knee"},
  825. /* autoExcludeMode = */ AZStd::nullopt,
  826. /* geometricAutoExclusion = */ AZStd::nullopt,
  827. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint * simulatedJoint)
  828. {
  829. EXPECT_CALL(*simulatedJoint, SetColliderExclusionTags(::testing::Pointwise(StrEq(), std::vector<std::string> {"left_knee", "right_knee"})))
  830. .Times(1);
  831. },
  832. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint * simulatedJoint)
  833. {
  834. ::testing::InSequence sequence;
  835. EXPECT_CALL(*simulatedJoint, SetColliderExclusionTags(::testing::Pointwise(StrEq(), std::vector<std::string> {"left_knee", "right_knee"})))
  836. .Times(1);
  837. EXPECT_CALL(*simulatedJoint, SetColliderExclusionTags(::testing::Pointwise(StrEq(), std::vector<std::string> {})))
  838. .Times(1);
  839. }
  840. },
  841. CommandAdjustSimulatedJointTestsParam
  842. {
  843. /* coneAngleLimit = */ AZStd::nullopt,
  844. /* mass = */ AZStd::nullopt,
  845. /* stiffness = */ AZStd::nullopt,
  846. /* damping = */ AZStd::nullopt,
  847. /* gravityFactor = */ AZStd::nullopt,
  848. /* friction = */ AZStd::nullopt,
  849. /* pinned = */ AZStd::nullopt,
  850. /* colliderExclusionTags = */ AZStd::nullopt,
  851. /* autoExcludeMode = */ SimulatedJoint::AutoExcludeMode::All,
  852. /* geometricAutoExclusion = */ AZStd::nullopt,
  853. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint * simulatedJoint)
  854. {
  855. EXPECT_CALL(*simulatedJoint, GetAutoExcludeMode())
  856. .Times(1)
  857. .WillOnce(::testing::Return(SimulatedJoint::AutoExcludeMode::None));
  858. EXPECT_CALL(*simulatedJoint, SetAutoExcludeMode(SimulatedJoint::AutoExcludeMode::All))
  859. .Times(1);
  860. },
  861. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint * simulatedJoint)
  862. {
  863. ::testing::InSequence sequence;
  864. EXPECT_CALL(*simulatedJoint, GetAutoExcludeMode())
  865. .Times(1)
  866. .WillOnce(::testing::Return(SimulatedJoint::AutoExcludeMode::None));
  867. EXPECT_CALL(*simulatedJoint, SetAutoExcludeMode(SimulatedJoint::AutoExcludeMode::All))
  868. .Times(1);
  869. EXPECT_CALL(*simulatedJoint, SetAutoExcludeMode(SimulatedJoint::AutoExcludeMode::None))
  870. .Times(1);
  871. }
  872. },
  873. CommandAdjustSimulatedJointTestsParam
  874. {
  875. /* coneAngleLimit = */ AZStd::nullopt,
  876. /* mass = */ AZStd::nullopt,
  877. /* stiffness = */ AZStd::nullopt,
  878. /* damping = */ AZStd::nullopt,
  879. /* gravityFactor = */ AZStd::nullopt,
  880. /* friction = */ AZStd::nullopt,
  881. /* pinned = */ AZStd::nullopt,
  882. /* colliderExclusionTags = */ AZStd::nullopt,
  883. /* autoExcludeMode = */ AZStd::nullopt,
  884. /* geometricAutoExclusion = */ true,
  885. /* setExecuteExpectations = */ [](UnderTest::SimulatedJoint * simulatedJoint)
  886. {
  887. EXPECT_CALL(*simulatedJoint, IsGeometricAutoExclusion())
  888. .Times(1)
  889. .WillOnce(::testing::Return(false));
  890. EXPECT_CALL(*simulatedJoint, SetGeometricAutoExclusion(true))
  891. .Times(1);
  892. },
  893. /* setUndoExpectations = */ [](UnderTest::SimulatedJoint * simulatedJoint)
  894. {
  895. ::testing::InSequence sequence;
  896. EXPECT_CALL(*simulatedJoint, IsGeometricAutoExclusion())
  897. .Times(1)
  898. .WillOnce(::testing::Return(false));
  899. EXPECT_CALL(*simulatedJoint, SetGeometricAutoExclusion(true))
  900. .Times(1);
  901. EXPECT_CALL(*simulatedJoint, SetGeometricAutoExclusion(false))
  902. .Times(1);
  903. }
  904. },
  905. })
  906. ),
  907. [](const ::testing::TestParamInfo<::testing::tuple<bool, bool, CommandAdjustSimulatedJointTestsParam>>& info)
  908. {
  909. std::string cmdline =
  910. (::testing::get<0>(info.param) ? std::string {"Execute_"} : std::string {"Undo_"})
  911. + (::testing::get<1>(info.param) ? std::string {"UseCommandString"} : std::string {"UseSetters"})
  912. + CommandAdjustSimulatedJointTestsFixture::buildCommandLineFromTestParam(::testing::get<2>(info.param));
  913. std::replace(cmdline.begin(), cmdline.end(), ' ', '_');
  914. std::replace(cmdline.begin(), cmdline.end(), ';', '_');
  915. cmdline.erase(std::remove(cmdline.begin(), cmdline.end(), '-'), cmdline.end());
  916. cmdline.erase(std::remove(cmdline.begin(), cmdline.end(), '.'), cmdline.end());
  917. return cmdline;
  918. }
  919. );
  920. } // namespace EMotionFX