ConsoleTests.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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 <AzCore/UnitTest/TestTypes.h>
  9. #include <AzCore/Interface/Interface.h>
  10. #include <AzCore/Console/Console.h>
  11. #include <AzCore/Settings/SettingsRegistryImpl.h>
  12. #include <AzCore/Utils/Utils.h>
  13. namespace AZ
  14. {
  15. using namespace UnitTest;
  16. AZ_CVAR(bool, testBool, false, nullptr, ConsoleFunctorFlags::Null, "");
  17. AZ_CVAR(char, testChar, 0, nullptr, ConsoleFunctorFlags::Null, "");
  18. AZ_CVAR(int8_t, testInt8, 0, nullptr, ConsoleFunctorFlags::Null, "");
  19. AZ_CVAR(int16_t, testInt16, 0, nullptr, ConsoleFunctorFlags::Null, "");
  20. AZ_CVAR(int32_t, testInt32, 0, nullptr, ConsoleFunctorFlags::Null, "");
  21. AZ_CVAR(int64_t, testInt64, 0, nullptr, ConsoleFunctorFlags::Null, "");
  22. AZ_CVAR(uint8_t, testUInt8, 0, nullptr, ConsoleFunctorFlags::Null, "");
  23. AZ_CVAR(uint16_t, testUInt16, 0, nullptr, ConsoleFunctorFlags::Null, "");
  24. AZ_CVAR(uint32_t, testUInt32, 0, nullptr, ConsoleFunctorFlags::Null, "");
  25. AZ_CVAR(uint64_t, testUInt64, 0, nullptr, ConsoleFunctorFlags::Null, "");
  26. AZ_CVAR(float, testFloat, 0, nullptr, ConsoleFunctorFlags::Null, "");
  27. AZ_CVAR(double, testDouble, 0, nullptr, ConsoleFunctorFlags::Null, "");
  28. AZ_CVAR(AZ::CVarFixedString, testString, "default", nullptr, ConsoleFunctorFlags::Null, "");
  29. AZ_CVAR(AZ::Vector2, testVec2, AZ::Vector2(0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  30. AZ_CVAR(AZ::Vector3, testVec3, AZ::Vector3(0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  31. AZ_CVAR(AZ::Vector4, testVec4, AZ::Vector4(0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  32. AZ_CVAR(AZ::Quaternion, testQuat, AZ::Quaternion(0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  33. AZ_CVAR(AZ::Color, testColorNormalized, AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  34. AZ_CVAR(AZ::Color, testColorNormalizedMixed, AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  35. AZ_CVAR(AZ::Color, testColorRgba, AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), nullptr, ConsoleFunctorFlags::Null, "");
  36. // Creates an enum class with values that aren't consecutive(0, 5, 6)
  37. AZ_ENUM_CLASS(ConsoleTestEnum,
  38. Option1,
  39. (Option2, 5),
  40. Option3);
  41. AZ_CVAR(ConsoleTestEnum, testEnum, ConsoleTestEnum::Option1, nullptr, ConsoleFunctorFlags::Null,
  42. "Supports setting the ConsoleTestEnum via the string or integer argument."
  43. " Option1/0 sets the CVar to the Option1 value"
  44. ", Option2/5 sets the CVar to the Option2 value"
  45. ", Option3/6 sets the CVar to the Option3 value");
  46. class ConsoleTests
  47. : public LeakDetectionFixture
  48. {
  49. public:
  50. void SetUp() override
  51. {
  52. m_console = AZStd::make_unique<AZ::Console>();
  53. m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
  54. AZ::Interface<AZ::IConsole>::Register(m_console.get());
  55. }
  56. void TearDown() override
  57. {
  58. AZ::Interface<AZ::IConsole>::Unregister(m_console.get());
  59. m_console = nullptr;
  60. }
  61. void TestClassFunc(const AZ::ConsoleCommandContainer& someStrings)
  62. {
  63. m_classFuncArgs = someStrings.size();
  64. }
  65. AZ_CONSOLEFUNC(ConsoleTests, TestClassFunc, AZ::ConsoleFunctorFlags::Null, "");
  66. size_t m_classFuncArgs = 0;
  67. inline static size_t s_consoleFreeFuncArgs = 0;
  68. AZStd::unique_ptr<AZ::Console> m_console;
  69. template <typename _CVAR_TYPE, typename _TYPE>
  70. void TestCVarHelper(_CVAR_TYPE& cvarInstance, const char* cVarName, const char* setCommand, const char* failCommand, _TYPE testInit, _TYPE initialValue, _TYPE setValue)
  71. {
  72. AZ::IConsole* console = m_console.get();
  73. _TYPE getCVarTest = testInit;
  74. ConsoleFunctorBase* foundCommand = console->FindCommand(cVarName);
  75. ASSERT_NE(nullptr, foundCommand); // Find command works and returns a non-null result
  76. EXPECT_STREQ(cVarName, foundCommand->GetName()); // Find command actually returned the correct command
  77. EXPECT_EQ(GetValueResult::Success, console->GetCvarValue(cVarName, getCVarTest)); // Console finds and retrieves cvar value
  78. EXPECT_EQ(initialValue, getCVarTest); // Retrieved cvar value
  79. console->PerformCommand(setCommand);
  80. EXPECT_EQ(setValue, _TYPE(cvarInstance)); // Set works for type
  81. EXPECT_EQ(GetValueResult::Success, console->GetCvarValue(cVarName, getCVarTest)); // Console finds and retrieves cvar value
  82. EXPECT_EQ(setValue, getCVarTest); // Retrieved cvar value
  83. if (failCommand != nullptr)
  84. {
  85. console->PerformCommand(failCommand);
  86. EXPECT_EQ(setValue, _TYPE(cvarInstance)); // Failed command did not affect cvar state
  87. }
  88. }
  89. };
  90. void TestFreeFunc(const AZ::ConsoleCommandContainer& someStrings)
  91. {
  92. ConsoleTests::s_consoleFreeFuncArgs = someStrings.size();
  93. }
  94. AZ_CONSOLEFREEFUNC(TestFreeFunc, AZ::ConsoleFunctorFlags::Null, "");
  95. TEST_F(ConsoleTests, CVar_GetSetTest_Bool)
  96. {
  97. testBool = false; // Reset testBool to false for scenarios where gtest_repeat is invoked
  98. TestCVarHelper(testBool, "testBool", "testBool true", "testBool asdf", false, false, true);
  99. }
  100. TEST_F(ConsoleTests, CVar_GetSetTest_Char)
  101. {
  102. testChar = {};
  103. TestCVarHelper(testChar, "testChar", "testChar 1", nullptr, char(100), char(0), '1'); // Char interprets the input as ascii, so if you print it, you get back a '1'
  104. }
  105. TEST_F(ConsoleTests, CVar_GetSetTest_Int8)
  106. {
  107. testInt8 = {};
  108. TestCVarHelper(testInt8, "testInt8", "testInt8 1", "testInt8 asdf", int8_t(100), int8_t(0), int8_t(1));
  109. }
  110. TEST_F(ConsoleTests, CVar_GetSetTest_Int16)
  111. {
  112. testInt16 = {};
  113. TestCVarHelper(testInt16, "testInt16", "testInt16 1", "testInt16 asdf", int16_t(100), int16_t(0), int16_t(1));
  114. }
  115. TEST_F(ConsoleTests, CVar_GetSetTest_Int32)
  116. {
  117. testInt32 = {};
  118. TestCVarHelper(testInt32, "testInt32", "testInt32 1", "testInt32 asdf", int32_t(100), int32_t(0), int32_t(1));
  119. }
  120. TEST_F(ConsoleTests, CVar_GetSetTest_Int64)
  121. {
  122. testInt64 = {};
  123. TestCVarHelper(testInt64, "testInt64", "testInt64 1", "testInt64 asdf", int64_t(100), int64_t(0), int64_t(1));
  124. }
  125. TEST_F(ConsoleTests, CVar_GetSetTest_UInt8)
  126. {
  127. testUInt8 = {};
  128. TestCVarHelper(testUInt8, "testUInt8", "testUInt8 1", "testUInt8 asdf", uint8_t(100), uint8_t(0), uint8_t(1));
  129. }
  130. TEST_F(ConsoleTests, CVar_GetSetTest_UInt16)
  131. {
  132. testUInt16 = {};
  133. TestCVarHelper(testUInt16, "testUInt16", "testUInt16 1", "testUInt16 asdf", uint16_t(100), uint16_t(0), uint16_t(1));
  134. }
  135. TEST_F(ConsoleTests, CVar_GetSetTest_UInt32)
  136. {
  137. testUInt32 = {};
  138. TestCVarHelper(testUInt32, "testUInt32", "testUInt32 1", "testUInt32 asdf", uint32_t(100), uint32_t(0), uint32_t(1));
  139. }
  140. TEST_F(ConsoleTests, CVar_GetSetTest_UInt64)
  141. {
  142. testUInt64 = {};
  143. TestCVarHelper(testUInt64, "testUInt64", "testUInt64 1", "testUInt64 asdf", uint64_t(100), uint64_t(0), uint64_t(1));
  144. }
  145. TEST_F(ConsoleTests, CVar_GetSetTest_Float)
  146. {
  147. testFloat = {};
  148. TestCVarHelper(testFloat, "testFloat", "testFloat 1", "testFloat asdf", float(100), float(0), float(1));
  149. }
  150. TEST_F(ConsoleTests, CVar_GetSetTest_Double)
  151. {
  152. testDouble = {};
  153. TestCVarHelper(testDouble, "testDouble", "testDouble 1", "testDouble asdf", double(100), double(0), double(1));
  154. }
  155. TEST_F(ConsoleTests, CVar_GetSetTest_String)
  156. {
  157. testString = "default";
  158. // There is really no failure condition for string, since even an empty string simply causes the console to echo the current cvar value
  159. TestCVarHelper(testString, "testString", "testString notdefault", nullptr, AZ::CVarFixedString("garbage"), AZ::CVarFixedString("default"), AZ::CVarFixedString("notdefault"));
  160. }
  161. TEST_F(ConsoleTests, CVar_GetSetTest_Vector2)
  162. {
  163. testVec2 = AZ::Vector2{ 0.0f, 0.0f };
  164. TestCVarHelper(testVec2, "testVec2", "testVec2 1 1", "testVec2 asdf", AZ::Vector2(100, 100), AZ::Vector2(0, 0), AZ::Vector2(1, 1));
  165. }
  166. TEST_F(ConsoleTests, CVar_GetSetTest_Vector3)
  167. {
  168. testVec3 = AZ::Vector3{ 0.0f, 0.0f, 0.0f };
  169. TestCVarHelper(testVec3, "testVec3", "testVec3 1 1 1", "testVec3 asdf", AZ::Vector3(100, 100, 100), AZ::Vector3(0, 0, 0), AZ::Vector3(1, 1, 1));
  170. }
  171. TEST_F(ConsoleTests, CVar_GetSetTest_Vector4)
  172. {
  173. testVec4 = AZ::Vector4{ 0.0f, 0.0f, 0.0f, 0.0f };
  174. TestCVarHelper(testVec4, "testVec4", "testVec4 1 1 1 1", "testVec4 asdf", AZ::Vector4(100, 100, 100, 100), AZ::Vector4(0, 0, 0, 0), AZ::Vector4(1, 1, 1, 1));
  175. }
  176. TEST_F(ConsoleTests, CVar_GetSetTest_Quaternion)
  177. {
  178. testQuat = AZ::Quaternion{ 0.0f, 0.0f, 0.0f, 0.0f };
  179. TestCVarHelper(testQuat, "testQuat", "testQuat 1 1 1 1", "testQuat asdf", AZ::Quaternion(100, 100, 100, 100), AZ::Quaternion(0, 0, 0, 0), AZ::Quaternion(1, 1, 1, 1));
  180. }
  181. TEST_F(ConsoleTests, CVar_GetSetTest_Color_Normalized)
  182. {
  183. testColorNormalized = AZ::Color{ 0.0f, 0.0f, 0.0f, 0.0f };
  184. TestCVarHelper(
  185. testColorNormalized, "testColorNormalized", "testColorNormalized 1.0 1.0 1.0 1.0", "testColorNormalized asdf",
  186. AZ::Color(0.5f, 0.5f, 0.5f, 0.5f), AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
  187. }
  188. TEST_F(ConsoleTests, CVar_GetSetTest_Color_Normalized_Mixed)
  189. {
  190. testColorNormalizedMixed = AZ::Color{ 0.0f, 0.0f, 0.0f, 0.0f };
  191. TestCVarHelper(
  192. testColorNormalizedMixed, "testColorNormalizedMixed", "testColorNormalizedMixed 1.0 0 1.0 1", "testColorNormalizedMixed asdf",
  193. AZ::Color(0.5f, 0.5f, 0.5f, 0.5f), AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), AZ::Color(1.0f, 0.0f, 1.0f, 1.0f));
  194. }
  195. TEST_F(ConsoleTests, CVar_GetSetTest_Color_Rgba)
  196. {
  197. testColorRgba = AZ::Color{ 0.0f, 0.0f, 0.0f, 0.0f };
  198. TestCVarHelper(
  199. testColorRgba, "testColorRgba", "testColorRgba 255 255 255 255", "testColorRgba asdf",
  200. AZ::Color(0.5f, 0.5f, 0.5f, 0.5f), AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
  201. }
  202. TEST_F(ConsoleTests, CVar_GetSetTest_EnumType_SupportsNumericValue)
  203. {
  204. testEnum = ConsoleTestEnum::Option1;
  205. TestCVarHelper(
  206. testEnum, "testEnum", "testEnum 0", "testEnum RandomOption",
  207. static_cast<ConsoleTestEnum>(2), ConsoleTestEnum::Option1, ConsoleTestEnum::Option1);
  208. testEnum = ConsoleTestEnum::Option1;
  209. TestCVarHelper(
  210. testEnum, "testEnum", "testEnum 3", "testEnum RandomOption",
  211. static_cast<ConsoleTestEnum>(2), ConsoleTestEnum::Option1, static_cast<ConsoleTestEnum>(3));
  212. }
  213. TEST_F(ConsoleTests, CVar_GetSetTest_EnumType_SupportsEnumOptionString)
  214. {
  215. testEnum = ConsoleTestEnum::Option1;
  216. TestCVarHelper(
  217. testEnum, "testEnum", "testEnum Option2", "testEnum RandomOption",
  218. static_cast<ConsoleTestEnum>(2), ConsoleTestEnum::Option1, ConsoleTestEnum::Option2);
  219. testEnum = ConsoleTestEnum::Option1;
  220. TestCVarHelper(
  221. testEnum, "testEnum", "testEnum Option3", "testEnum RandomOption",
  222. static_cast<ConsoleTestEnum>(47), ConsoleTestEnum{}, ConsoleTestEnum::Option3);
  223. }
  224. TEST_F(ConsoleTests, CVar_ConstructAfterDeferredInit)
  225. {
  226. // This cvar only has scope within the function body, it will be added and removed on function entry and exit
  227. AZ_CVAR_SCOPED(int32_t, testInit, 0, nullptr, ConsoleFunctorFlags::Null, "");
  228. testInit = {};
  229. TestCVarHelper(testInit, "testInit", "testInit 1", "testInit asdf", int32_t(100), int32_t(0), int32_t(1));
  230. }
  231. TEST_F(ConsoleTests, CVar_GetSetTest_FormatConversion)
  232. {
  233. AZ::IConsole* console = m_console.get();
  234. // This simply tests format conversion
  235. float testValue = 0.0f;
  236. console->PerformCommand("testString 100.5f");
  237. AZ_TEST_ASSERT(console->GetCvarValue("testString", testValue) == GetValueResult::Success); // Console finds and retrieves cvar value
  238. AZ_TEST_ASSERT(testValue == 100.5f); // Retrieved cvar value
  239. console->PerformCommand("testString asdf");
  240. AZ_TEST_ASSERT(static_cast<AZ::CVarFixedString>(testString) == "asdf"); // String changed state
  241. AZ_TEST_ASSERT(console->GetCvarValue("testString", testValue) != GetValueResult::Success); // Console can't convert an arbitrary string to a float
  242. }
  243. TEST_F(ConsoleTests, CVar_Autocomplete)
  244. {
  245. AZ::IConsole* console = m_console.get();
  246. // Empty input
  247. {
  248. AZStd::string completeCommand = console->AutoCompleteCommand("");
  249. AZ_TEST_ASSERT(completeCommand == "");
  250. }
  251. // Prefix
  252. {
  253. AZStd::string completeCommand = console->AutoCompleteCommand("te");
  254. AZ_TEST_ASSERT(completeCommand == "test");
  255. }
  256. // Prefix
  257. {
  258. AZStd::string completeCommand = console->AutoCompleteCommand("testV");
  259. AZ_TEST_ASSERT(completeCommand == "testVec");
  260. }
  261. // Unique
  262. {
  263. AZStd::string completeCommand = console->AutoCompleteCommand("testQ");
  264. AZ_TEST_ASSERT(completeCommand == "testQuat");
  265. }
  266. // Complete
  267. {
  268. AZStd::string completeCommand = console->AutoCompleteCommand("testVec3");
  269. AZ_TEST_ASSERT(completeCommand == "testVec3");
  270. }
  271. // Duplicate names
  272. {
  273. // Register two cvars with the same name
  274. auto id = AZ::TypeId();
  275. auto flag = AZ::ConsoleFunctorFlags::Null;
  276. auto signature = AZ::ConsoleFunctor<void, false>::FunctorSignature();
  277. AZ::ConsoleFunctor<void, false> cvarOne(*console, "testAutoCompleteDuplication", "", flag, id, signature);
  278. AZ::ConsoleFunctor<void, false> cvarTwo(*console, "testAutoCompleteDuplication", "", flag, id, signature);
  279. // Autocomplete given name expecting one match (not two)
  280. AZStd::vector<AZStd::string> matches;
  281. AZStd::string completeCommand = console->AutoCompleteCommand("testAutoCompleteD", &matches);
  282. AZ_TEST_ASSERT(matches.size() == 1 && completeCommand == "testAutoCompleteDuplication");
  283. }
  284. }
  285. TEST_F(ConsoleTests, ConsoleFunctor_FreeFunctorExecutionTest)
  286. {
  287. AZ::IConsole* console = m_console.get();
  288. ASSERT_TRUE(console);
  289. // Verify that we can successfully execute a free-standing console functor.
  290. // The test functor puts the number of arguments into s_consoleFreeFuncArgs.
  291. s_consoleFreeFuncArgs = 0;
  292. bool result = static_cast<bool>(console->PerformCommand("TestFreeFunc arg1 arg2"));
  293. EXPECT_TRUE(result);
  294. EXPECT_EQ(2, s_consoleFreeFuncArgs);
  295. }
  296. TEST_F(ConsoleTests, ConsoleFunctor_ClassFunctorExecutionTest)
  297. {
  298. AZ::IConsole* console = m_console.get();
  299. ASSERT_TRUE(console);
  300. // Verify that we can successfully execute a class instance console functor.
  301. // The test functor puts the number of arguments into m_classFuncArgs.
  302. m_classFuncArgs = 0;
  303. bool result = static_cast<bool>(console->PerformCommand("ConsoleTests.TestClassFunc arg1 arg2"));
  304. EXPECT_TRUE(result);
  305. EXPECT_EQ(2, m_classFuncArgs);
  306. }
  307. TEST_F(ConsoleTests, ConsoleFunctor_MultiInstanceClassFunctorExecutionTest)
  308. {
  309. // Verify that if multiple instances of a class all register the same class method,
  310. // the method will get called on every instance of the class.
  311. class Example
  312. {
  313. public:
  314. void TestClassFunc(const AZ::ConsoleCommandContainer& someStrings)
  315. {
  316. m_classFuncArgs = someStrings.size();
  317. }
  318. AZ_CONSOLEFUNC(Example, TestClassFunc, AZ::ConsoleFunctorFlags::Null, "");
  319. size_t m_classFuncArgs = 0;
  320. };
  321. constexpr int numInstances = 5;
  322. Example multiInstances[numInstances];
  323. AZ::IConsole* console = AZ::Interface<AZ::IConsole>::Get();
  324. ASSERT_TRUE(console);
  325. bool result = static_cast<bool>(console->PerformCommand("Example.TestClassFunc arg1 arg2"));
  326. EXPECT_TRUE(result);
  327. for (auto& instance : multiInstances)
  328. {
  329. EXPECT_EQ(2, instance.m_classFuncArgs);
  330. }
  331. }
  332. }
  333. namespace ConsoleSettingsRegistryTests
  334. {
  335. //! ConfigFile MergeUtils Test
  336. struct ConfigFileParams
  337. {
  338. AZStd::string_view m_testConfigFileName;
  339. AZStd::string_view m_testConfigContents;
  340. };
  341. class ConsoleSettingsRegistryFixture
  342. : public UnitTest::LeakDetectionFixture
  343. , public ::testing::WithParamInterface<ConfigFileParams>
  344. {
  345. public:
  346. void SetUp() override
  347. {
  348. m_registry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
  349. // Store off the old global settings registry to restore after each test
  350. m_oldSettingsRegistry = AZ::SettingsRegistry::Get();
  351. if (m_oldSettingsRegistry != nullptr)
  352. {
  353. AZ::SettingsRegistry::Unregister(m_oldSettingsRegistry);
  354. }
  355. AZ::SettingsRegistry::Register(m_registry.get());
  356. // Create a TestFile in the Test Directory
  357. auto configFileParams = GetParam();
  358. AZ::Test::CreateTestFile(m_tempDirectory, configFileParams.m_testConfigFileName, configFileParams.m_testConfigContents);
  359. }
  360. void TearDown() override
  361. {
  362. // Restore the old global settings registry
  363. AZ::SettingsRegistry::Unregister(m_registry.get());
  364. if (m_oldSettingsRegistry != nullptr)
  365. {
  366. AZ::SettingsRegistry::Register(m_oldSettingsRegistry);
  367. m_oldSettingsRegistry = {};
  368. }
  369. m_registry.reset();
  370. }
  371. void TestClassFunc(const AZ::ConsoleCommandContainer& someStrings)
  372. {
  373. m_stringArgCount = someStrings.size();
  374. }
  375. AZ_CONSOLEFUNC(ConsoleSettingsRegistryFixture, TestClassFunc, AZ::ConsoleFunctorFlags::Null, "");
  376. protected:
  377. size_t m_stringArgCount{};
  378. AZStd::unique_ptr<AZ::SettingsRegistryInterface> m_registry;
  379. AZ::Test::ScopedAutoTempDirectory m_tempDirectory;
  380. private:
  381. AZ::SettingsRegistryInterface* m_oldSettingsRegistry{};
  382. };
  383. static bool s_consoleFreeFunctionInvoked = false;
  384. static void TestSettingsRegistryFreeFunc(const AZ::ConsoleCommandContainer& someStrings)
  385. {
  386. EXPECT_TRUE(someStrings.empty());
  387. s_consoleFreeFunctionInvoked = true;
  388. }
  389. AZ_CONSOLEFREEFUNC(TestSettingsRegistryFreeFunc, AZ::ConsoleFunctorFlags::Null, "");
  390. TEST_P(ConsoleSettingsRegistryFixture, Console_AbleToLoadSettingsFile_Successfully)
  391. {
  392. AZ::Console testConsole(*m_registry);
  393. testConsole.LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
  394. AZ::Interface<AZ::IConsole>::Register(&testConsole);
  395. AZ_CVAR_SCOPED(int32_t, testInit, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "");
  396. s_consoleFreeFunctionInvoked = false;
  397. testInit = {};
  398. AZ::testChar = {};
  399. AZ::testBool = {};
  400. AZ::testInt8 = {};
  401. AZ::testInt16 = {};
  402. AZ::testInt32 = {};
  403. AZ::testInt64 = {};
  404. AZ::testUInt8 = {};
  405. AZ::testUInt16 = {};
  406. AZ::testUInt32 = {};
  407. AZ::testUInt64 = {};
  408. AZ::testFloat= {};
  409. AZ::testDouble = {};
  410. AZ::testString = {};
  411. auto configFileParams = GetParam();
  412. auto testFilePath = m_tempDirectory.GetDirectoryAsFixedMaxPath() / configFileParams.m_testConfigFileName;
  413. EXPECT_TRUE(AZ::IO::SystemFile::Exists(testFilePath.c_str()));
  414. testConsole.ExecuteConfigFile(testFilePath.Native());
  415. EXPECT_TRUE(s_consoleFreeFunctionInvoked);
  416. EXPECT_EQ(3, testInit);
  417. EXPECT_TRUE(static_cast<bool>(AZ::testBool));
  418. EXPECT_EQ('Q', AZ::testChar);
  419. EXPECT_EQ(24, AZ::testInt8);
  420. EXPECT_EQ(-32, AZ::testInt16);
  421. EXPECT_EQ(41, AZ::testInt32);
  422. EXPECT_EQ(-51, AZ::testInt64);
  423. EXPECT_EQ(3, AZ::testUInt8);
  424. EXPECT_EQ(5, AZ::testUInt16);
  425. EXPECT_EQ(6, AZ::testUInt32);
  426. EXPECT_EQ(0xFFFF'FFFF'FFFF'FFFF, AZ::testUInt64);
  427. EXPECT_FLOAT_EQ(1.0f, AZ::testFloat);
  428. EXPECT_DOUBLE_EQ(2, AZ::testDouble);
  429. EXPECT_STREQ("Stable", static_cast<AZ::CVarFixedString>(AZ::testString).c_str());
  430. EXPECT_EQ(3, m_stringArgCount);
  431. AZ::Interface<AZ::IConsole>::Unregister(&testConsole);
  432. }
  433. template<typename T>
  434. using ConsoleDataWrapper = AZ::ConsoleDataWrapper<T, ConsoleThreadSafety<T>>;
  435. TEST_P(ConsoleSettingsRegistryFixture, Console_RecordsUnregisteredCommands_And_IsAbleToDeferDispatchCommand_Successfully)
  436. {
  437. AZ::Console testConsole(*m_registry);
  438. AZ::Interface<AZ::IConsole>::Register(&testConsole);
  439. // GetDeferredHead is invoked for the side effect of to set the s_deferredHeadInvoked value to true
  440. // This allows scoped console variables to be attached immediately
  441. [[maybe_unused]] auto deferredHead = AZ::ConsoleFunctorBase::GetDeferredHead();
  442. ConsoleDataWrapper<int32_t> localTestInit{ {}, nullptr, "testInit", "", AZ::ConsoleFunctorFlags::Null };
  443. ConsoleDataWrapper<char> localTestChar{ {}, nullptr, "testChar", "", AZ::ConsoleFunctorFlags::Null };
  444. ConsoleDataWrapper<bool> localTestBool{ {}, nullptr, "testBool", "", AZ::ConsoleFunctorFlags::Null };
  445. s_consoleFreeFunctionInvoked = false;
  446. // Invoke the Commands for Scoped CVar variables above
  447. auto configFileParams = GetParam();
  448. auto testFilePath = m_tempDirectory.GetDirectoryAsFixedMaxPath() / configFileParams.m_testConfigFileName;
  449. EXPECT_TRUE(AZ::IO::SystemFile::Exists(testFilePath.c_str()));
  450. testConsole.ExecuteConfigFile(testFilePath.Native());
  451. EXPECT_EQ(3, localTestInit);
  452. EXPECT_TRUE(static_cast<bool>(localTestBool));
  453. EXPECT_EQ('Q', localTestChar);
  454. // The following commands from the config files should have been deferred
  455. ConsoleDataWrapper<int8_t> localTestInt8{ {}, nullptr, "testInt8", "", AZ::ConsoleFunctorFlags::Null };
  456. ConsoleDataWrapper<int16_t> localTestInt16{ {}, nullptr, "testInt16", "", AZ::ConsoleFunctorFlags::Null };
  457. ConsoleDataWrapper<int32_t> localTestInt32{ {}, nullptr, "testInt32", "", AZ::ConsoleFunctorFlags::Null };
  458. ConsoleDataWrapper<int64_t> localTestInt64{ {}, nullptr, "testInt64", "", AZ::ConsoleFunctorFlags::Null };
  459. ConsoleDataWrapper<uint8_t> localTestUInt8{ {}, nullptr, "testUInt8", "", AZ::ConsoleFunctorFlags::Null };
  460. ConsoleDataWrapper<uint16_t> localTestUInt16{ {}, nullptr, "testUInt16", "", AZ::ConsoleFunctorFlags::Null };
  461. ConsoleDataWrapper<uint32_t> localTestUInt32{ {}, nullptr, "testUInt32", "", AZ::ConsoleFunctorFlags::Null };
  462. ConsoleDataWrapper<uint64_t> localTestUInt64{ {}, nullptr, "testUInt64", "", AZ::ConsoleFunctorFlags::Null };
  463. ConsoleDataWrapper<float> localTestFloat{ {}, nullptr, "testFloat", "", AZ::ConsoleFunctorFlags::Null };
  464. ConsoleDataWrapper<double> localTestDouble{ {}, nullptr, "testDouble", "", AZ::ConsoleFunctorFlags::Null };
  465. ConsoleDataWrapper<AZ::CVarFixedString> localTestString{ {}, nullptr, "testString", "", AZ::ConsoleFunctorFlags::Null };
  466. // The scoped cvars just above should have all been deferred for execution
  467. // Each of them should have executed resulting in the expected return value
  468. EXPECT_TRUE(testConsole.ExecuteDeferredConsoleCommands());
  469. EXPECT_EQ(24, localTestInt8);
  470. EXPECT_EQ(-32, localTestInt16);
  471. EXPECT_EQ(41, localTestInt32);
  472. EXPECT_EQ(-51, localTestInt64);
  473. EXPECT_EQ(3, localTestUInt8);
  474. EXPECT_EQ(5, localTestUInt16);
  475. EXPECT_EQ(6, localTestUInt32);
  476. EXPECT_EQ(0xFFFF'FFFF'FFFF'FFFF, localTestUInt64);
  477. EXPECT_FLOAT_EQ(1.0f, localTestFloat);
  478. EXPECT_DOUBLE_EQ(2, localTestDouble);
  479. EXPECT_STREQ("Stable", static_cast<AZ::CVarFixedString>(localTestString).c_str());
  480. // All of the deferred console commands should have executed at this point
  481. // Therefore this invocation should return false
  482. EXPECT_FALSE(testConsole.ExecuteDeferredConsoleCommands());
  483. AZ::Interface<AZ::IConsole>::Unregister(&testConsole);
  484. }
  485. static constexpr AZStd::string_view UserINIStyleContent =
  486. R"(
  487. testInit = 3
  488. testBool true
  489. testChar Q
  490. testInt8 24
  491. testInt16 -32
  492. testInt32 41
  493. testInt64 -51
  494. testUInt8 3
  495. testUInt16 5
  496. testUInt32 6
  497. testUInt64 18446744073709551615
  498. testFloat 1.0
  499. testDouble 2
  500. testString Stable
  501. ConsoleSettingsRegistryFixture.testClassFunc Foo Bar Baz
  502. TestSettingsRegistryFreeFunc
  503. )";
  504. static constexpr AZStd::string_view UserJsonMergePatchContent =
  505. R"(
  506. {
  507. "Amazon": {
  508. "AzCore": {
  509. "Runtime": {
  510. "ConsoleCommands": {
  511. "testInit": 3,
  512. "testBool": true,
  513. "testChar": "Q",
  514. "testInt8": 24,
  515. "testInt16": -32,
  516. "testInt32": 41,
  517. "testInt64": -51,
  518. "testUInt8": 3,
  519. "testUInt16": 5,
  520. "testUInt32": 6,
  521. "testUInt64": 18446744073709551615,
  522. "testFloat": 1.0,
  523. "testDouble": 2,
  524. "testString": "Stable",
  525. "ConsoleSettingsRegistryFixture.testClassFunc": "Foo Bar Baz",
  526. "TestSettingsRegistryFreeFunc": ""
  527. }
  528. }
  529. }
  530. }
  531. }
  532. )";
  533. static constexpr AZStd::string_view UserJsonPatchContent =
  534. R"(
  535. [
  536. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInit", "value": 3 },
  537. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testBool", "value": true },
  538. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testChar", "value": "Q" },
  539. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt8", "value": 24 },
  540. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt16", "value": -32 },
  541. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt32", "value": 41 },
  542. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt64", "value": -51 },
  543. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt8", "value": 3 },
  544. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt16", "value": 5 },
  545. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt32", "value": 6 },
  546. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt64", "value": 18446744073709551615 },
  547. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testFloat", "value": 1.0 },
  548. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testDouble", "value": 2 },
  549. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testString", "value": "Stable" },
  550. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/ConsoleSettingsRegistryFixture.testClassFunc", "value": "Foo Bar Baz" },
  551. { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/TestSettingsRegistryFreeFunc", "value": "" }
  552. ]
  553. )";
  554. INSTANTIATE_TEST_SUITE_P(
  555. ExecuteCommandFromSettingsFile,
  556. ConsoleSettingsRegistryFixture,
  557. ::testing::Values(
  558. ConfigFileParams{"user.cfg", UserINIStyleContent},
  559. ConfigFileParams{"user.setreg", UserJsonMergePatchContent},
  560. ConfigFileParams{"user.setregpatch", UserJsonPatchContent}
  561. )
  562. );
  563. }