SettingsRegistryTests.cpp 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747
  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/Casting/numeric_cast.h>
  9. #include <AzCore/IO/SystemFile.h>
  10. #include <AzCore/Math/Uuid.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <AzCore/Serialization/Json/RegistrationContext.h>
  13. #include <AzCore/Serialization/Json/JsonSystemComponent.h>
  14. #include <AzCore/Settings/SettingsRegistryImpl.h>
  15. #include <AzCore/std/containers/vector.h>
  16. #include <AzCore/std/smart_ptr/unique_ptr.h>
  17. #include <AzCore/std/string/string.h>
  18. #include <AzCore/UnitTest/TestTypes.h>
  19. namespace SettingsRegistryTests
  20. {
  21. class TestClass
  22. {
  23. public:
  24. AZ_TYPE_INFO(TestClass, "{CDD9648A-27CA-4625-9FD9-DD3BB9CB093D}");
  25. int m_var1 = { 42 };
  26. double m_var2 = { 42.0 };
  27. static TestClass Initialize()
  28. {
  29. TestClass result;
  30. result.m_var1 = 88;
  31. result.m_var2 = 88.0;
  32. return result;
  33. }
  34. static void Reflect(AZ::SerializeContext& context)
  35. {
  36. context.Class<TestClass>()
  37. ->Field("Var1", &TestClass::m_var1)
  38. ->Field("Var2", &TestClass::m_var2);
  39. }
  40. };
  41. struct RegistryEntry
  42. {
  43. AZStd::string_view m_path;
  44. AZStd::string_view m_valueName;
  45. AZ::SettingsRegistryInterface::Type m_type;
  46. AZ::SettingsRegistryInterface::VisitAction m_action;
  47. AZ::SettingsRegistryInterface::VisitResponse m_response;
  48. RegistryEntry() = default;
  49. RegistryEntry(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type type,
  50. AZ::SettingsRegistryInterface::VisitAction action,
  51. AZ::SettingsRegistryInterface::VisitResponse response = AZ::SettingsRegistryInterface::VisitResponse::Continue)
  52. : m_path(path)
  53. , m_valueName(valueName)
  54. , m_type(type)
  55. , m_action(action)
  56. , m_response(response)
  57. {}
  58. };
  59. class SettingsRegistryTest
  60. : public UnitTest::LeakDetectionFixture
  61. {
  62. public:
  63. ~SettingsRegistryTest() override = default;
  64. static void DeleteFolderRecursive(const AZStd::string& path)
  65. {
  66. auto callback = [&path](const char* filename, bool isFile) -> bool
  67. {
  68. if (isFile)
  69. {
  70. AZStd::string filePath = path;
  71. filePath += '/';
  72. filePath += filename;
  73. AZ::IO::SystemFile::Delete(filePath.c_str());
  74. }
  75. else
  76. {
  77. if (strcmp(filename, ".") != 0 && strcmp(filename, "..") != 0)
  78. {
  79. AZStd::string folderPath = path;
  80. folderPath += '/';
  81. folderPath += filename;
  82. DeleteFolderRecursive(folderPath);
  83. }
  84. }
  85. return true;
  86. };
  87. AZStd::string searchPath = path;
  88. searchPath += "/*";
  89. AZ::IO::SystemFile::FindFiles(searchPath.c_str(), callback);
  90. AZ::IO::SystemFile::DeleteDir(path.c_str());
  91. }
  92. void SetUp() override
  93. {
  94. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  95. m_registrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
  96. m_registry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
  97. m_registry->SetContext(m_serializeContext.get());
  98. m_registry->SetContext(m_registrationContext.get());
  99. AZ::JsonSystemComponent::Reflect(m_registrationContext.get());
  100. }
  101. void TearDown() override
  102. {
  103. m_registrationContext->EnableRemoveReflection();
  104. AZ::JsonSystemComponent::Reflect(m_registrationContext.get());
  105. m_registrationContext->DisableRemoveReflection();
  106. m_registry.reset();
  107. m_registrationContext.reset();
  108. m_serializeContext.reset();
  109. }
  110. AZ::IO::FixedMaxPath CreateTestFile(AZStd::string_view name, AZStd::string_view content)
  111. {
  112. using namespace AZ::IO;
  113. auto path = m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder / name;
  114. SystemFile file;
  115. if (!file.Open(path.c_str(), SystemFile::OpenMode::SF_OPEN_CREATE | SystemFile::SF_OPEN_CREATE_PATH | SystemFile::SF_OPEN_WRITE_ONLY))
  116. {
  117. AZ_Assert(false, "Unable to open test file for writing: %s", path.c_str());
  118. return path;
  119. }
  120. if (file.Write(content.data(), content.size()) != content.size())
  121. {
  122. AZ_Assert(false, "Unable to write content to test file: %s", path.c_str());
  123. }
  124. return path;
  125. }
  126. void Visit(const AZStd::vector<RegistryEntry>& expected, AZStd::string_view path = "")
  127. {
  128. size_t counter = 0;
  129. auto callback = [&expected, &counter](const AZ::SettingsRegistryInterface::VisitArgs& visitArgs,
  130. AZ::SettingsRegistryInterface::VisitAction action)
  131. {
  132. EXPECT_LT(counter, expected.size());
  133. if (counter < expected.size())
  134. {
  135. const RegistryEntry& entry = expected[counter];
  136. EXPECT_STREQ(entry.m_path.data(), visitArgs.m_jsonKeyPath.data());
  137. EXPECT_STREQ(entry.m_valueName.data(), visitArgs.m_fieldName.data());
  138. EXPECT_EQ(entry.m_action, action);
  139. EXPECT_EQ(entry.m_type, visitArgs.m_type);
  140. counter++;
  141. return entry.m_response;
  142. }
  143. return AZ::SettingsRegistryInterface::VisitResponse::Done;
  144. };
  145. EXPECT_TRUE(m_registry->Visit(callback, path));
  146. EXPECT_EQ(counter, expected.size());
  147. }
  148. void MergeNotify(AZStd::string_view path, size_t index, size_t fileIdLength, const char* counterId, const char** fileIds)
  149. {
  150. EXPECT_TRUE(path.empty());
  151. AZ::s64 value = -1;
  152. bool result = m_registry->Get(value, counterId);
  153. EXPECT_TRUE(result);
  154. EXPECT_EQ(index, value);
  155. size_t i = 0;
  156. for (; i <= index; ++i)
  157. {
  158. bool configValue = false;
  159. result = m_registry->Get(configValue, fileIds[i]);
  160. EXPECT_TRUE(result);
  161. EXPECT_TRUE(configValue);
  162. }
  163. for (; i < fileIdLength; ++i)
  164. {
  165. AZ::SettingsRegistryInterface::Type type = m_registry->GetType(fileIds[i]);
  166. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, type);
  167. }
  168. }
  169. AZStd::unique_ptr<AZ::SettingsRegistryImpl> m_registry;
  170. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  171. AZStd::unique_ptr<AZ::JsonRegistrationContext> m_registrationContext;
  172. AZ::Test::ScopedAutoTempDirectory m_tempDirectory;
  173. };
  174. template<typename> struct SettingsType {};
  175. // Json makes a distinction between true and false as different types, so test for both
  176. // versions.
  177. struct BoolTrue {};
  178. struct BoolFalse {};
  179. template<> struct SettingsType<BoolTrue>
  180. {
  181. using DataType = bool;
  182. using ValueType = bool;
  183. constexpr static AZ::SettingsRegistryInterface::Type s_type = AZ::SettingsRegistryInterface::Type::Boolean;
  184. static AZStd::string_view GetStoredJson() { return "true"; }
  185. static DataType GetStoredValue() { return true; }
  186. static DataType GetDefaultValue() { return false; }
  187. static void ExpectEq(ValueType lhs, ValueType rhs) { EXPECT_EQ(lhs, rhs); }
  188. };
  189. template<> struct SettingsType<BoolFalse>
  190. {
  191. using DataType = bool;
  192. using ValueType = bool;
  193. constexpr static AZ::SettingsRegistryInterface::Type s_type = AZ::SettingsRegistryInterface::Type::Boolean;
  194. static AZStd::string_view GetStoredJson() { return "false"; }
  195. static DataType GetStoredValue() { return false; }
  196. static DataType GetDefaultValue() { return true; }
  197. static void ExpectEq(ValueType lhs, ValueType rhs) { EXPECT_EQ(lhs, rhs); }
  198. };
  199. template<> struct SettingsType<AZ::s64>
  200. {
  201. using DataType = AZ::s64;
  202. using ValueType = AZ::s64;
  203. constexpr static AZ::SettingsRegistryInterface::Type s_type = AZ::SettingsRegistryInterface::Type::Integer;
  204. static AZStd::string_view GetStoredJson() { return "-88"; }
  205. static DataType GetStoredValue() { return -88; }
  206. static DataType GetDefaultValue() { return 42; }
  207. static void ExpectEq(ValueType lhs, ValueType rhs) { EXPECT_EQ(lhs, rhs); }
  208. };
  209. template<> struct SettingsType<double>
  210. {
  211. using DataType = double;
  212. using ValueType = double;
  213. constexpr static AZ::SettingsRegistryInterface::Type s_type = AZ::SettingsRegistryInterface::Type::FloatingPoint;
  214. static AZStd::string_view GetStoredJson() { return "88.0"; }
  215. static DataType GetStoredValue() { return 88.0; }
  216. static DataType GetDefaultValue() { return 42.0; }
  217. static void ExpectEq(DataType lhs, DataType rhs) { EXPECT_DOUBLE_EQ(lhs, rhs); }
  218. };
  219. template<> struct SettingsType<AZStd::string>
  220. {
  221. using DataType = AZStd::string;
  222. using ValueType = AZStd::string_view;
  223. constexpr static AZ::SettingsRegistryInterface::Type s_type = AZ::SettingsRegistryInterface::Type::String;
  224. static AZStd::string_view GetStoredJson() { return R"("World")"; }
  225. static DataType GetStoredValue() { return "World"; }
  226. static DataType GetDefaultValue() { return AZStd::string{}; }
  227. static void ExpectEq(ValueType lhs, ValueType rhs) { EXPECT_STREQ(lhs.data(), rhs.data()); }
  228. };
  229. template<> struct SettingsType<AZ::SettingsRegistryInterface::FixedValueString>
  230. {
  231. using DataType = AZ::SettingsRegistryInterface::FixedValueString;
  232. using ValueType = AZStd::string_view;
  233. constexpr static AZ::SettingsRegistryInterface::Type s_type = AZ::SettingsRegistryInterface::Type::String;
  234. static AZStd::string_view GetStoredJson() { return R"("World")"; }
  235. static DataType GetStoredValue() { return "World"; }
  236. static DataType GetDefaultValue() { return DataType{}; }
  237. static void ExpectEq(ValueType lhs, ValueType rhs) { EXPECT_STREQ(lhs.data(), rhs.data()); }
  238. };
  239. template<typename SettingsType>
  240. class TypedSettingsRegistryTest
  241. : public SettingsRegistryTest
  242. {
  243. public:
  244. ~TypedSettingsRegistryTest() override = default;
  245. };
  246. using SettingsTypes = ::testing::Types<
  247. BoolTrue, BoolFalse, AZ::s64, double, AZStd::string, AZ::SettingsRegistryInterface::FixedValueString>;
  248. TYPED_TEST_CASE(TypedSettingsRegistryTest, SettingsTypes);
  249. TYPED_TEST(TypedSettingsRegistryTest, GetSet_SetAndGetValue_Success)
  250. {
  251. typename SettingsType<TypeParam>::DataType value = SettingsType<TypeParam>::GetStoredValue();
  252. typename SettingsType<TypeParam>::DataType readValue = SettingsType<TypeParam>::GetDefaultValue();
  253. AZStd::string_view testPath = "/Test/Path/Value";
  254. ASSERT_TRUE(this->m_registry->Set(testPath, value));
  255. ASSERT_TRUE(this->m_registry->Get(readValue, testPath));
  256. SettingsType<TypeParam>::ExpectEq(value, readValue);
  257. }
  258. TYPED_TEST(TypedSettingsRegistryTest, Get_InvalidPath_ReturnsFalse)
  259. {
  260. typename SettingsType<TypeParam>::DataType readValue = SettingsType<TypeParam>::GetDefaultValue();
  261. AZStd::string_view testPath = "#$%^";
  262. EXPECT_FALSE(this->m_registry->Get(readValue, testPath));
  263. }
  264. TYPED_TEST(TypedSettingsRegistryTest, Get_UnknownPath_ReturnsFalse)
  265. {
  266. typename SettingsType<TypeParam>::DataType readValue = SettingsType<TypeParam>::GetDefaultValue();
  267. AZStd::string_view testPath = "/Unknown/Path";
  268. EXPECT_FALSE(this->m_registry->Get(readValue, testPath));
  269. }
  270. TYPED_TEST(TypedSettingsRegistryTest, Get_InvalidType_ReturnsFalse)
  271. {
  272. ASSERT_TRUE(this->m_registry->MergeSettings(R"({ "Object": { "Value": 42 } })", AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  273. typename SettingsType<TypeParam>::DataType readValue = SettingsType<TypeParam>::GetDefaultValue();
  274. AZStd::string_view testPath = "/Object";
  275. EXPECT_FALSE(this->m_registry->Get(readValue, testPath));
  276. }
  277. TYPED_TEST(TypedSettingsRegistryTest, Set_InvalidPath_ReturnsFalse)
  278. {
  279. typename SettingsType<TypeParam>::DataType value = SettingsType<TypeParam>::GetStoredValue();
  280. AZStd::string_view testPath = "#$%^";
  281. EXPECT_FALSE(this->m_registry->Set(testPath, value));
  282. }
  283. TYPED_TEST(TypedSettingsRegistryTest, Set_NotifiersCalled_ReturnsFalse)
  284. {
  285. size_t counter = 0;
  286. auto callback0 = [&counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  287. {
  288. EXPECT_EQ("/Object/Value", notifyEventArgs.m_jsonKeyPath);
  289. counter++;
  290. };
  291. auto callback1 = [&counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  292. {
  293. AZ::SettingsRegistryInterface::Type type = SettingsType<TypeParam>::s_type;
  294. EXPECT_EQ(notifyEventArgs.m_type, type);
  295. counter++;
  296. };
  297. auto testNotifier1 = this->m_registry->RegisterNotifier(callback0);
  298. auto testNotifier2 = this->m_registry->RegisterNotifier(AZStd::move(callback1));
  299. typename SettingsType<TypeParam>::DataType value = SettingsType<TypeParam>::GetStoredValue();
  300. AZStd::string_view testPath = "/Object/Value";
  301. EXPECT_TRUE(this->m_registry->Set(testPath, value));
  302. EXPECT_EQ(2, counter);
  303. }
  304. TYPED_TEST(TypedSettingsRegistryTest, Set_ConnectedNotifierCalledAndDisconnectedNotifierNotCalled_Success)
  305. {
  306. size_t counter1{};
  307. auto callback0 = [&counter1](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  308. {
  309. EXPECT_EQ("/Object/Value", notifyEventArgs.m_jsonKeyPath);
  310. counter1++;
  311. };
  312. size_t counter2{};
  313. auto callback1 = [&counter2](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  314. {
  315. EXPECT_EQ("/Object/Value", notifyEventArgs.m_jsonKeyPath);
  316. counter2++;
  317. };;
  318. auto testNotifier1 = this->m_registry->RegisterNotifier(callback0);
  319. auto testNotifier2 = this->m_registry->RegisterNotifier(AZStd::move(callback1));
  320. typename SettingsType<TypeParam>::DataType value = SettingsType<TypeParam>::GetStoredValue();
  321. AZStd::string_view testPath = "/Object/Value";
  322. EXPECT_TRUE(this->m_registry->Set(testPath, value));
  323. EXPECT_EQ(1, counter1);
  324. EXPECT_EQ(1, counter2);
  325. // Disconnect the second Notifier
  326. testNotifier2.Disconnect();
  327. EXPECT_TRUE(this->m_registry->Set(testPath, SettingsType<TypeParam>::GetDefaultValue()));
  328. EXPECT_EQ(2, counter1);
  329. EXPECT_EQ(1, counter2);
  330. }
  331. TYPED_TEST(TypedSettingsRegistryTest, GetType_TypeForTheStoredValue_TypeMatchesProvidedType)
  332. {
  333. typename SettingsType<TypeParam>::DataType value = SettingsType<TypeParam>::GetStoredValue();
  334. AZ::SettingsRegistryInterface::Type type = SettingsType<TypeParam>::s_type;
  335. AZStd::string_view testPath = "/Test/Path/Value";
  336. ASSERT_TRUE(this->m_registry->Set(testPath, value));
  337. EXPECT_EQ(type, this->m_registry->GetType(testPath));
  338. }
  339. TYPED_TEST(TypedSettingsRegistryTest, VisitWithVisitor_VisitingObject_ValuesInJsonAreVisited)
  340. {
  341. AZStd::string_view storedJson = SettingsType<TypeParam>::GetStoredJson();
  342. AZStd::string json = AZStd::string::format(
  343. R"({
  344. "Test":
  345. {
  346. "Object":{ "Type": %.*s }
  347. }
  348. })", aznumeric_cast<int>(storedJson.length()), storedJson.data());
  349. ASSERT_TRUE(this->m_registry->MergeSettings(json.c_str(), AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  350. struct : public AZ::SettingsRegistryInterface::Visitor
  351. {
  352. using AZ::SettingsRegistryInterface::Visitor::Visit;
  353. using ValueType [[maybe_unused]] = typename SettingsType<TypeParam>::ValueType;
  354. void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, ValueType value) override
  355. {
  356. AZ::SettingsRegistryInterface::Type expectedType = SettingsType<TypeParam>::s_type;
  357. EXPECT_EQ(expectedType, visitArgs.m_type);
  358. SettingsType<TypeParam>::ExpectEq(SettingsType<TypeParam>::GetStoredValue(), value);
  359. m_counter++;
  360. }
  361. size_t m_counter{ 0 };
  362. } visitor;
  363. EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test"));
  364. EXPECT_EQ(1, visitor.m_counter);
  365. }
  366. TYPED_TEST(TypedSettingsRegistryTest, VisitWithVisitor_VisitingArray_ValuesInJsonAreVisited)
  367. {
  368. AZStd::string_view storedJson = SettingsType<TypeParam>::GetStoredJson();
  369. AZStd::string json = AZStd::string::format(
  370. R"({
  371. "Test":
  372. {
  373. "Array":[ %.*s ]
  374. }
  375. })", aznumeric_cast<int>(storedJson.length()), storedJson.data());
  376. ASSERT_TRUE(this->m_registry->MergeSettings(json.c_str(), AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  377. struct : public AZ::SettingsRegistryInterface::Visitor
  378. {
  379. using AZ::SettingsRegistryInterface::Visitor::Visit;
  380. using ValueType [[maybe_unused]] = typename SettingsType<TypeParam>::ValueType;
  381. void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, ValueType value) override
  382. {
  383. AZ::SettingsRegistryInterface::Type expectedType = SettingsType<TypeParam>::s_type;
  384. EXPECT_EQ(expectedType, visitArgs.m_type);
  385. SettingsType<TypeParam>::ExpectEq(SettingsType<TypeParam>::GetStoredValue(), value);
  386. m_counter++;
  387. }
  388. size_t m_counter{ 0 };
  389. } visitor;
  390. EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test"));
  391. EXPECT_EQ(1, visitor.m_counter);
  392. }
  393. TEST_F(SettingsRegistryTest, VisitWithVisitor_VisitingIntegerGreaterThanNumericLimitsOfSigned64Bit_SuppliesCorrectBitPattern)
  394. {
  395. // Create a 64-bit value that is greater than what can be represented in a signed int64_t
  396. constexpr AZ::u64 unsigned64BitValue = aznumeric_cast<AZ::u64>((std::numeric_limits<AZ::s64>::max)()) + 1;
  397. AZStd::string json = AZStd::string::format(
  398. R"({
  399. "Test":
  400. {
  401. "Object":{ "Type": %llu }
  402. }
  403. })", unsigned64BitValue);
  404. ASSERT_TRUE(this->m_registry->MergeSettings(json.c_str(), AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  405. struct : public AZ::SettingsRegistryInterface::Visitor
  406. {
  407. using AZ::SettingsRegistryInterface::Visitor::Visit;
  408. void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, AZ::s64 value) override
  409. {
  410. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Integer, visitArgs.m_type);
  411. AZ::u64 testValue = reinterpret_cast<AZ::u64&>(value);
  412. EXPECT_EQ(expectedValue, testValue);
  413. }
  414. const AZ::u64 expectedValue{ unsigned64BitValue };
  415. } visitor;
  416. EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test/Object/Type"));
  417. }
  418. TEST_F(SettingsRegistryTest, VisitWithVisitor_EndOfPathArguments_MatchesValueNameArgument_ForAllIterations)
  419. {
  420. // Validate that every invocation of the Traverse and Visit command supplies a 'path' parameter
  421. // whose end matches that of the 'valueName' parameter
  422. AZStd::string json{
  423. R"({
  424. "Test":
  425. {
  426. "Object":{ "Type": "TestString" }
  427. }
  428. })"
  429. };
  430. ASSERT_TRUE(this->m_registry->MergeSettings(json.c_str(), AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  431. struct : public AZ::SettingsRegistryInterface::Visitor
  432. {
  433. AZ::SettingsRegistryInterface::VisitResponse Traverse(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs,
  434. AZ::SettingsRegistryInterface::VisitAction) override
  435. {
  436. EXPECT_TRUE(visitArgs.m_jsonKeyPath.ends_with(visitArgs.m_fieldName));
  437. return AZ::SettingsRegistryInterface::VisitResponse::Continue;
  438. }
  439. using AZ::SettingsRegistryInterface::Visitor::Visit;
  440. void Visit(const AZ::SettingsRegistryInterface::VisitArgs& visitArgs, AZStd::string_view)override
  441. {
  442. EXPECT_TRUE(visitArgs.m_jsonKeyPath.ends_with(visitArgs.m_fieldName));
  443. }
  444. } visitor;
  445. EXPECT_TRUE(this->m_registry->Visit(visitor, ""));
  446. EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test"));
  447. }
  448. //
  449. // Object
  450. //
  451. TEST_F(SettingsRegistryTest, GetSetObject_SetAndGetValue_Success)
  452. {
  453. TestClass::Reflect(*m_serializeContext);
  454. AZStd::string_view testPath = "/Test/Path/Value";
  455. TestClass value;
  456. value.m_var1 = 88;
  457. value.m_var2 = 88.0;
  458. TestClass readValue;
  459. ASSERT_TRUE(m_registry->SetObject(testPath, &value, azrtti_typeid(value)));
  460. ASSERT_TRUE(m_registry->GetObject(&readValue, azrtti_typeid(readValue), testPath));
  461. EXPECT_EQ(value.m_var1, readValue.m_var1);
  462. EXPECT_DOUBLE_EQ(value.m_var2, readValue.m_var2);
  463. m_serializeContext->EnableRemoveReflection();
  464. TestClass::Reflect(*m_serializeContext);
  465. m_serializeContext->DisableRemoveReflection();
  466. }
  467. TEST_F(SettingsRegistryTest, GetObject_InvalidPath_ReturnsFalse)
  468. {
  469. TestClass::Reflect(*m_serializeContext);
  470. AZStd::string_view testPath = "$%^&";
  471. TestClass readValue;
  472. EXPECT_FALSE(m_registry->GetObject(&readValue, azrtti_typeid(readValue), testPath));
  473. m_serializeContext->EnableRemoveReflection();
  474. TestClass::Reflect(*m_serializeContext);
  475. m_serializeContext->DisableRemoveReflection();
  476. }
  477. TEST_F(SettingsRegistryTest, GetObject_UnknownPath_ReturnsFalse)
  478. {
  479. TestClass::Reflect(*m_serializeContext);
  480. AZStd::string_view testPath = "/Unknown/Path";
  481. TestClass readValue;
  482. EXPECT_FALSE(m_registry->GetObject(&readValue, azrtti_typeid(readValue), testPath));
  483. m_serializeContext->EnableRemoveReflection();
  484. TestClass::Reflect(*m_serializeContext);
  485. m_serializeContext->DisableRemoveReflection();
  486. }
  487. TEST_F(SettingsRegistryTest, SetObject_InvalidPath_ReturnFalse)
  488. {
  489. TestClass::Reflect(*m_serializeContext);
  490. AZStd::string_view testPath = "$%^&";
  491. TestClass value;
  492. EXPECT_FALSE(m_registry->SetObject(testPath, &value, azrtti_typeid(value)));
  493. m_serializeContext->EnableRemoveReflection();
  494. TestClass::Reflect(*m_serializeContext);
  495. m_serializeContext->DisableRemoveReflection();
  496. }
  497. TEST_F(SettingsRegistryTest, SetObject_NotifiersCalled_ReturnsFalse)
  498. {
  499. size_t counter = 0;
  500. auto callback0 = [&counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  501. {
  502. EXPECT_EQ("/Object/Value", notifyEventArgs.m_jsonKeyPath);
  503. counter++;
  504. };
  505. auto callback1 = [&counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  506. {
  507. EXPECT_EQ(notifyEventArgs.m_type, AZ::SettingsRegistryInterface::Type::Object);
  508. counter++;
  509. };
  510. auto testNotifier1 = m_registry->RegisterNotifier(callback0);
  511. auto testNotifier2 = m_registry->RegisterNotifier(AZStd::move(callback1));
  512. TestClass::Reflect(*m_serializeContext);
  513. AZStd::string_view testPath = "/Object/Value";
  514. TestClass value;
  515. EXPECT_TRUE(m_registry->SetObject(testPath, &value, azrtti_typeid(value)));
  516. EXPECT_EQ(2, counter);
  517. m_serializeContext->EnableRemoveReflection();
  518. TestClass::Reflect(*m_serializeContext);
  519. m_serializeContext->DisableRemoveReflection();
  520. }
  521. //
  522. // Remove
  523. //
  524. TYPED_TEST(TypedSettingsRegistryTest, Remove_SetAndRemoveValue_Success)
  525. {
  526. typename SettingsType<TypeParam>::DataType value = SettingsType<TypeParam>::GetStoredValue();
  527. typename SettingsType<TypeParam>::DataType newValue = SettingsType<TypeParam>::GetDefaultValue();
  528. AZStd::string_view testPath = "/Test/Path/Value";
  529. EXPECT_TRUE(this->m_registry->Set(testPath, value));
  530. EXPECT_TRUE(this->m_registry->Get(newValue, testPath));
  531. SettingsType<TypeParam>::ExpectEq(value, newValue);
  532. EXPECT_TRUE(this->m_registry->Remove(testPath));
  533. typename SettingsType<TypeParam>::DataType notFoundValue{};
  534. EXPECT_FALSE(this->m_registry->Get(notFoundValue, testPath));
  535. }
  536. TYPED_TEST(TypedSettingsRegistryTest, Remove_InvalidPath_ReturnsFalse)
  537. {
  538. AZStd::string_view testPath = "#$%^";
  539. EXPECT_FALSE(this->m_registry->Remove(testPath));
  540. typename SettingsType<TypeParam>::DataType notFoundValue{};
  541. EXPECT_FALSE(this->m_registry->Get(notFoundValue, testPath));
  542. }
  543. TYPED_TEST(TypedSettingsRegistryTest, Remove_UnknownPath_ReturnsFalse)
  544. {
  545. AZStd::string_view testPath = "/Unknown/Path";
  546. EXPECT_FALSE(this->m_registry->Remove(testPath));
  547. typename SettingsType<TypeParam>::DataType notFoundValue{};
  548. EXPECT_FALSE(this->m_registry->Get(notFoundValue, testPath));
  549. }
  550. //
  551. // Specializations::Append
  552. //
  553. TEST_F(SettingsRegistryTest, SpecializationsAppend_TooManySpecializations_ReportsErrorAndReturnsFalse)
  554. {
  555. AZ::SettingsRegistryInterface::Specializations specializations;
  556. for (size_t i = 0; i < AZ::SettingsRegistryInterface::Specializations::MaxCount; ++i)
  557. {
  558. specializations.Append("test");
  559. }
  560. AZ_TEST_START_TRACE_SUPPRESSION;
  561. bool result = specializations.Append("TooFar");
  562. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  563. EXPECT_FALSE(result);
  564. }
  565. //
  566. // GetType
  567. // Note: The typed tests already test several GetType versions.
  568. //
  569. TEST_F(SettingsRegistryTest, GetType_TypeForObject_TypeMatchesProvidedType)
  570. {
  571. ASSERT_TRUE(m_registry->MergeSettings(R"({ "Object": { "Value": 42 } })", AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  572. AZStd::string_view testPath = "/Object";
  573. EXPECT_EQ(AZ::SettingsRegistryImpl::Type::Object, m_registry->GetType(testPath));
  574. }
  575. TEST_F(SettingsRegistryTest, GetType_TypeForArray_TypeMatchesProvidedType)
  576. {
  577. ASSERT_TRUE(m_registry->MergeSettings(R"({ "Array": [ 42 ] })", AZ::SettingsRegistryInterface::Format::JsonMergePatch));
  578. AZStd::string_view testPath = "/Array";
  579. EXPECT_EQ(AZ::SettingsRegistryImpl::Type::Array, m_registry->GetType(testPath));
  580. }
  581. TEST_F(SettingsRegistryTest, GetType_TypeForNull_TypeMatchesProvidedType)
  582. {
  583. ASSERT_TRUE(m_registry->MergeSettings(
  584. R"( [
  585. { "op": "add", "path": "/Object", "value": {"Value": null} }
  586. ])",
  587. AZ::SettingsRegistryInterface::Format::JsonPatch));
  588. AZStd::string_view testPath = "/Object/Value";
  589. EXPECT_EQ(AZ::SettingsRegistryImpl::Type::Null, m_registry->GetType(testPath));
  590. }
  591. TEST_F(SettingsRegistryTest, GetType_InvalidPath_ReturnNone)
  592. {
  593. AZ::SettingsRegistryInterface::Type type = m_registry->GetType("#$%");
  594. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, type);
  595. }
  596. TEST_F(SettingsRegistryTest, GetType_UnknownPath_ReturnNone)
  597. {
  598. AZ::SettingsRegistryInterface::Type type = m_registry->GetType("/Unknown/Path");
  599. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, type);
  600. }
  601. //
  602. // Visit
  603. //
  604. TEST_F(SettingsRegistryTest, VisitWithVisitor_InvalidPath_ReturnsFalse)
  605. {
  606. struct : public AZ::SettingsRegistryInterface::Visitor
  607. {
  608. } visitor;
  609. EXPECT_FALSE(m_registry->Visit(visitor, "#$%"));
  610. }
  611. TEST_F(SettingsRegistryTest, VisitWithVisitor_UnknownPath_ReturnsFalse)
  612. {
  613. struct : public AZ::SettingsRegistryInterface::Visitor
  614. {
  615. } visitor;
  616. EXPECT_FALSE(m_registry->Visit(visitor, "/Unknown/Path"));
  617. }
  618. TEST_F(SettingsRegistryTest, VisitWithCallback_FullIteration_AllFieldsAreReported)
  619. {
  620. using SRI = AZ::SettingsRegistryInterface;
  621. ASSERT_TRUE(m_registry->MergeSettings(
  622. R"( [
  623. { "op": "add", "path": "/Test", "value": { "Object": {} } },
  624. { "op": "add", "path": "/Test/Object/NullType", "value": null },
  625. { "op": "add", "path": "/Test/Object/TrueType", "value": true },
  626. { "op": "add", "path": "/Test/Object/FalseType", "value": false },
  627. { "op": "add", "path": "/Test/Object/IntType", "value": -42 },
  628. { "op": "add", "path": "/Test/Object/UIntType", "value": 42 },
  629. { "op": "add", "path": "/Test/Object/DoubleType", "value": 42.0 },
  630. { "op": "add", "path": "/Test/Object/StringType", "value": "Hello world" },
  631. { "op": "add", "path": "/Test/Array", "value": [ null, true, false, -42, 42, 42.0, "Hello world" ] }
  632. ])", SRI::Format::JsonPatch));
  633. AZStd::vector<RegistryEntry> expected =
  634. {
  635. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  636. RegistryEntry("/Test/Object", "Object", SRI::Type::Object, SRI::VisitAction::Begin),
  637. RegistryEntry("/Test/Object/NullType", "NullType", SRI::Type::Null, SRI::VisitAction::Value),
  638. RegistryEntry("/Test/Object/TrueType", "TrueType", SRI::Type::Boolean, SRI::VisitAction::Value),
  639. RegistryEntry("/Test/Object/FalseType", "FalseType", SRI::Type::Boolean, SRI::VisitAction::Value),
  640. RegistryEntry("/Test/Object/IntType", "IntType", SRI::Type::Integer, SRI::VisitAction::Value),
  641. RegistryEntry("/Test/Object/UIntType", "UIntType", SRI::Type::Integer, SRI::VisitAction::Value),
  642. RegistryEntry("/Test/Object/DoubleType", "DoubleType", SRI::Type::FloatingPoint, SRI::VisitAction::Value),
  643. RegistryEntry("/Test/Object/StringType", "StringType", SRI::Type::String, SRI::VisitAction::Value),
  644. RegistryEntry("/Test/Object", "Object", SRI::Type::Object, SRI::VisitAction::End),
  645. RegistryEntry("/Test/Array", "Array", SRI::Type::Array, SRI::VisitAction::Begin),
  646. RegistryEntry("/Test/Array/0", "0", SRI::Type::Null, SRI::VisitAction::Value),
  647. RegistryEntry("/Test/Array/1", "1", SRI::Type::Boolean, SRI::VisitAction::Value),
  648. RegistryEntry("/Test/Array/2", "2", SRI::Type::Boolean, SRI::VisitAction::Value),
  649. RegistryEntry("/Test/Array/3", "3", SRI::Type::Integer, SRI::VisitAction::Value),
  650. RegistryEntry("/Test/Array/4", "4", SRI::Type::Integer, SRI::VisitAction::Value),
  651. RegistryEntry("/Test/Array/5", "5", SRI::Type::FloatingPoint, SRI::VisitAction::Value),
  652. RegistryEntry("/Test/Array/6", "6", SRI::Type::String, SRI::VisitAction::Value),
  653. RegistryEntry("/Test/Array", "Array", SRI::Type::Array, SRI::VisitAction::End),
  654. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End)
  655. };
  656. Visit(expected, "/Test");
  657. }
  658. TEST_F(SettingsRegistryTest, VisitWithCallback_IterateWithOffsetInObject_AllFieldsInSubSectionAreListed)
  659. {
  660. using SRI = AZ::SettingsRegistryInterface;
  661. ASSERT_TRUE(m_registry->MergeSettings(
  662. R"({
  663. "Layer1":
  664. {
  665. "Layer2":
  666. {
  667. "Layer3":
  668. {
  669. "StringType": "Hello World"
  670. }
  671. }
  672. }
  673. })", SRI::Format::JsonMergePatch));
  674. AZStd::vector<RegistryEntry> expected =
  675. {
  676. RegistryEntry("/Layer1/Layer2", "Layer2", SRI::Type::Object, SRI::VisitAction::Begin),
  677. RegistryEntry("/Layer1/Layer2/Layer3", "Layer3", SRI::Type::Object, SRI::VisitAction::Begin),
  678. RegistryEntry("/Layer1/Layer2/Layer3/StringType", "StringType", SRI::Type::String, SRI::VisitAction::Value),
  679. RegistryEntry("/Layer1/Layer2/Layer3", "Layer3", SRI::Type::Object, SRI::VisitAction::End),
  680. RegistryEntry("/Layer1/Layer2", "Layer2", SRI::Type::Object, SRI::VisitAction::End)
  681. };
  682. Visit(expected, "/Layer1/Layer2");
  683. }
  684. TEST_F(SettingsRegistryTest, VisitWithCallback_IterateWithOffsetInArray_AllFieldsInSubSectionAreListed)
  685. {
  686. using SRI = AZ::SettingsRegistryInterface;
  687. ASSERT_TRUE(m_registry->MergeSettings(
  688. R"({
  689. "Object":
  690. [
  691. [
  692. [
  693. "Hello World"
  694. ]
  695. ]
  696. ]
  697. })", SRI::Format::JsonMergePatch));
  698. AZStd::vector<RegistryEntry> expected =
  699. {
  700. RegistryEntry("/Object/0/0", "0", SRI::Type::Array, SRI::VisitAction::Begin),
  701. RegistryEntry("/Object/0/0/0", "0", SRI::Type::String, SRI::VisitAction::Value),
  702. RegistryEntry("/Object/0/0", "0", SRI::Type::Array, SRI::VisitAction::End)
  703. };
  704. Visit(expected, "/Object/0/0");
  705. }
  706. TEST_F(SettingsRegistryTest, VisitWithCallback_SkipObject_FirstAndThirdObjectOnly)
  707. {
  708. using SRI = AZ::SettingsRegistryInterface;
  709. ASSERT_TRUE(m_registry->MergeSettings(
  710. R"({
  711. "Test":
  712. {
  713. "Object0": { "Field" : 142 },
  714. "Object1": { "Field" : 242 },
  715. "Object2": { "Field" : 342 }
  716. }
  717. })", SRI::Format::JsonMergePatch));
  718. AZStd::vector<RegistryEntry> expected =
  719. {
  720. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  721. RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin),
  722. RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
  723. RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::End),
  724. RegistryEntry("/Test/Object1", "Object1", SRI::Type::Object, SRI::VisitAction::Begin, SRI::VisitResponse::Skip),
  725. RegistryEntry("/Test/Object2", "Object2", SRI::Type::Object, SRI::VisitAction::Begin),
  726. RegistryEntry("/Test/Object2/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
  727. RegistryEntry("/Test/Object2", "Object2", SRI::Type::Object, SRI::VisitAction::End),
  728. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End)
  729. };
  730. Visit(expected, "/Test");
  731. }
  732. TEST_F(SettingsRegistryTest, VisitWithCallback_SkipArray_FirstAndThirdObjectOnly)
  733. {
  734. using SRI = AZ::SettingsRegistryInterface;
  735. ASSERT_TRUE(m_registry->MergeSettings(
  736. R"({
  737. "Test":
  738. {
  739. "Array0": [ 142, 188 ],
  740. "Array1": [ 242, 288 ],
  741. "Array2": [ 342, 388 ]
  742. }
  743. })", SRI::Format::JsonMergePatch));
  744. AZStd::vector<RegistryEntry> expected =
  745. {
  746. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  747. RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin),
  748. RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
  749. RegistryEntry("/Test/Array0/1", "1", SRI::Type::Integer, SRI::VisitAction::Value),
  750. RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::End),
  751. RegistryEntry("/Test/Array1", "Array1", SRI::Type::Array, SRI::VisitAction::Begin, SRI::VisitResponse::Skip),
  752. RegistryEntry("/Test/Array2", "Array2", SRI::Type::Array, SRI::VisitAction::Begin),
  753. RegistryEntry("/Test/Array2/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
  754. RegistryEntry("/Test/Array2/1", "1", SRI::Type::Integer, SRI::VisitAction::Value),
  755. RegistryEntry("/Test/Array2", "Array2", SRI::Type::Array, SRI::VisitAction::End),
  756. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End)
  757. };
  758. Visit(expected, "/Test");
  759. }
  760. TEST_F(SettingsRegistryTest, VisitWithCallback_StopMidwayThroughObject_FirstObjectOnly)
  761. {
  762. using SRI = AZ::SettingsRegistryInterface;
  763. ASSERT_TRUE(m_registry->MergeSettings(
  764. R"({
  765. "Test":
  766. {
  767. "Object0": { "Field" : 142 },
  768. "Object1": { "Field" : 242 },
  769. "Object2": { "Field" : 342 }
  770. }
  771. })", SRI::Format::JsonMergePatch));
  772. AZStd::vector<RegistryEntry> expected =
  773. {
  774. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  775. RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin),
  776. RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
  777. RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::End),
  778. RegistryEntry("/Test/Object1", "Object1", SRI::Type::Object, SRI::VisitAction::Begin, SRI::VisitResponse::Done)
  779. };
  780. Visit(expected, "/Test");
  781. }
  782. TEST_F(SettingsRegistryTest, VisitWithCallback_StopOnObjectEnd_FirstObjectOnly)
  783. {
  784. using SRI = AZ::SettingsRegistryInterface;
  785. ASSERT_TRUE(m_registry->MergeSettings(
  786. R"({
  787. "Test":
  788. {
  789. "Object0": { "Field" : 142 },
  790. "Object1": { "Field" : 242 },
  791. "Object2": { "Field" : 342 }
  792. }
  793. })", SRI::Format::JsonMergePatch));
  794. AZStd::vector<RegistryEntry> expected =
  795. {
  796. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  797. RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin),
  798. RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
  799. RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::End, SRI::VisitResponse::Done)
  800. };
  801. Visit(expected, "/Test");
  802. }
  803. TEST_F(SettingsRegistryTest, VisitWithCallback_StopMidwayThroughArray_FirstObjectOnly)
  804. {
  805. using SRI = AZ::SettingsRegistryInterface;
  806. ASSERT_TRUE(m_registry->MergeSettings(
  807. R"({
  808. "Test":
  809. {
  810. "Array0": [ 142, 188 ],
  811. "Array1": [ 242, 288 ],
  812. "Array2": [ 342, 388 ]
  813. }
  814. })", SRI::Format::JsonMergePatch));
  815. AZStd::vector<RegistryEntry> expected =
  816. {
  817. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  818. RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin),
  819. RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
  820. RegistryEntry("/Test/Array0/1", "1", SRI::Type::Integer, SRI::VisitAction::Value),
  821. RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::End),
  822. RegistryEntry("/Test/Array1", "Array1", SRI::Type::Array, SRI::VisitAction::Begin),
  823. RegistryEntry("/Test/Array1/0", "0", SRI::Type::Integer, SRI::VisitAction::Value, SRI::VisitResponse::Done),
  824. };
  825. Visit(expected, "/Test");
  826. }
  827. TEST_F(SettingsRegistryTest, VisitWithCallback_StopOnArrayEnd_FirstObjectOnly)
  828. {
  829. using SRI = AZ::SettingsRegistryInterface;
  830. ASSERT_TRUE(m_registry->MergeSettings(
  831. R"({
  832. "Test":
  833. {
  834. "Array0": [ 142, 188 ],
  835. "Array1": [ 242, 288 ],
  836. "Array2": [ 342, 388 ]
  837. }
  838. })", SRI::Format::JsonMergePatch));
  839. AZStd::vector<RegistryEntry> expected =
  840. {
  841. RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
  842. RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin),
  843. RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
  844. RegistryEntry("/Test/Array0/1", "1", SRI::Type::Integer, SRI::VisitAction::Value),
  845. RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::End, SRI::VisitResponse::Done)
  846. };
  847. Visit(expected, "/Test");
  848. }
  849. TEST_F(SettingsRegistryTest, VisitWithCallback_InvalidPath_ReturnsFalse)
  850. {
  851. auto callback = [](const AZ::SettingsRegistryInterface::VisitArgs&,
  852. AZ::SettingsRegistryInterface::VisitAction)
  853. {
  854. return AZ::SettingsRegistryInterface::VisitResponse::Continue;
  855. };
  856. EXPECT_FALSE(m_registry->Visit(callback, "#$%"));
  857. }
  858. TEST_F(SettingsRegistryTest, VisitWithCallback_UnknownPath_ReturnsFalse)
  859. {
  860. auto callback = [](const AZ::SettingsRegistryInterface::VisitArgs&,
  861. AZ::SettingsRegistryInterface::VisitAction)
  862. {
  863. return AZ::SettingsRegistryInterface::VisitResponse::Continue;
  864. };
  865. EXPECT_FALSE(m_registry->Visit(callback, "/Unknown/Path"));
  866. }
  867. TEST_F(SettingsRegistryTest, VisitWithCallback_WithEmptyStringViewPath_DoesNotCrash)
  868. {
  869. auto callback = [](const AZ::SettingsRegistryInterface::VisitArgs&,
  870. AZ::SettingsRegistryInterface::VisitAction)
  871. {
  872. return AZ::SettingsRegistryInterface::VisitResponse::Continue;
  873. };
  874. EXPECT_TRUE(m_registry->Visit(callback, {}));
  875. }
  876. //
  877. // MergeCommandLineArgument
  878. //
  879. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SetStringArgument_ValueAddedToRegistry)
  880. {
  881. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=Value", {}, {}));
  882. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  883. AZStd::string value;
  884. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  885. EXPECT_STREQ("Value", value.c_str());
  886. }
  887. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SetStringWithSpaceArgument_ValueAddedToRegistry)
  888. {
  889. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=Value of test", {}, {}));
  890. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  891. AZStd::string value;
  892. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  893. EXPECT_STREQ("Value of test", value.c_str());
  894. }
  895. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SetIntegerArgument_ValueAddedToRegistry)
  896. {
  897. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=42", {}, {}));
  898. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Integer, m_registry->GetType("/Test"));
  899. AZ::s64 value;
  900. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  901. EXPECT_EQ(42, value);
  902. }
  903. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SetFloatingPointArgument_ValueAddedToRegistry)
  904. {
  905. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=42.0", {}, {}));
  906. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::FloatingPoint, m_registry->GetType("/Test"));
  907. double value;
  908. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  909. EXPECT_EQ(42.0, value);
  910. }
  911. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SetTrueArgument_ValueAddedToRegistry)
  912. {
  913. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=true", {}, {}));
  914. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Boolean, m_registry->GetType("/Test"));
  915. bool value;
  916. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  917. EXPECT_TRUE(value);
  918. }
  919. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SetFalseArgument_ValueAddedToRegistry)
  920. {
  921. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=false", {}, {}));
  922. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Boolean, m_registry->GetType("/Test"));
  923. bool value;
  924. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  925. EXPECT_FALSE(value);
  926. }
  927. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyWithPath_ValueAddedToRegistry)
  928. {
  929. ASSERT_TRUE(m_registry->MergeCommandLineArgument("/Parent/Test=Value", {}, {}));
  930. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Parent/Test"));
  931. AZStd::string value;
  932. ASSERT_TRUE(m_registry->Get(value, "/Parent/Test"));
  933. EXPECT_STREQ("Value", value.c_str());
  934. }
  935. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyAndPath_ValueAddedToRegistry)
  936. {
  937. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=Value", "/Parent", {}));
  938. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Parent/Test"));
  939. AZStd::string value;
  940. ASSERT_TRUE(m_registry->Get(value, "/Parent/Test"));
  941. EXPECT_STREQ("Value", value.c_str());
  942. }
  943. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyWithDividerAndPath_ValueAddedToRegistry)
  944. {
  945. ASSERT_TRUE(m_registry->MergeCommandLineArgument("/Test=Value", "/Parent", {}));
  946. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Parent/Test"));
  947. AZStd::string value;
  948. ASSERT_TRUE(m_registry->Get(value, "/Parent/Test"));
  949. EXPECT_STREQ("Value", value.c_str());
  950. }
  951. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyAndPathWithDivider_ValueAddedToRegistry)
  952. {
  953. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=Value", "/Parent/", {}));
  954. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Parent/Test"));
  955. AZStd::string value;
  956. ASSERT_TRUE(m_registry->Get(value, "/Parent/Test"));
  957. EXPECT_STREQ("Value", value.c_str());
  958. }
  959. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyWithDividerAndPathWithDivider_ValueAddedToRegistry)
  960. {
  961. ASSERT_TRUE(m_registry->MergeCommandLineArgument("/Test=Value", "/Parent/", {}));
  962. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Parent/Test"));
  963. AZStd::string value;
  964. ASSERT_TRUE(m_registry->Get(value, "/Parent/Test"));
  965. EXPECT_STREQ("Value", value.c_str());
  966. }
  967. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesBeforeKey_SpacesAreRemoved)
  968. {
  969. ASSERT_TRUE(m_registry->MergeCommandLineArgument(" Test=Value", {}, {}));
  970. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  971. AZStd::string value;
  972. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  973. EXPECT_STREQ("Value", value.c_str());
  974. }
  975. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesAfterKey_SpacesAreRemoved)
  976. {
  977. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test =Value", {}, {}));
  978. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  979. AZStd::string value;
  980. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  981. EXPECT_STREQ("Value", value.c_str());
  982. }
  983. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesBeforeAndAfterKey_SpacesAreRemoved)
  984. {
  985. ASSERT_TRUE(m_registry->MergeCommandLineArgument(" Test =Value", {}, {}));
  986. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  987. AZStd::string value;
  988. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  989. EXPECT_STREQ("Value", value.c_str());
  990. }
  991. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesInKey_SpacesAreNotRemoved)
  992. {
  993. ASSERT_TRUE(m_registry->MergeCommandLineArgument(" Test Key =Value", {}, {}));
  994. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test Key"));
  995. AZStd::string value;
  996. ASSERT_TRUE(m_registry->Get(value, "/Test Key"));
  997. EXPECT_STREQ("Value", value.c_str());
  998. }
  999. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesBeforeValue_SpacesAreRemoved)
  1000. {
  1001. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test= Value", {}, {}));
  1002. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  1003. AZStd::string value;
  1004. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  1005. EXPECT_STREQ("Value", value.c_str());
  1006. }
  1007. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesAfterValue_SpacesAreRemoved)
  1008. {
  1009. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test=Value ", {}, {}));
  1010. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  1011. AZStd::string value;
  1012. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  1013. EXPECT_STREQ("Value", value.c_str());
  1014. }
  1015. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_SpacesBeforeAndAfterValue_SpacesAreRemoved)
  1016. {
  1017. ASSERT_TRUE(m_registry->MergeCommandLineArgument("Test= Value ", {}, {}));
  1018. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  1019. AZStd::string value;
  1020. ASSERT_TRUE(m_registry->Get(value, "/Test"));
  1021. EXPECT_STREQ("Value", value.c_str());
  1022. }
  1023. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyIsTooLong_ReturnsFalse)
  1024. {
  1025. constexpr int LongKeySize = 1024;
  1026. AZStd::string argument = AZStd::string::format("Te%*cst=Value", LongKeySize, ' ');
  1027. EXPECT_FALSE(m_registry->MergeCommandLineArgument(argument, {}, {}));
  1028. }
  1029. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyIsTooLongWithDivider_ReturnsFalse)
  1030. {
  1031. constexpr int LongKeySize = 1024;
  1032. AZStd::string argument = AZStd::string::format("/Te%*cst=Value", LongKeySize, ' ');
  1033. EXPECT_FALSE(m_registry->MergeCommandLineArgument(argument, "/Path", {}));
  1034. }
  1035. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_ValueIsTooLong_ReturnsFalse)
  1036. {
  1037. constexpr int LongValueSize = 1024;
  1038. AZStd::string argument = AZStd::string::format("Test=Val%*cue", LongValueSize, ' ');
  1039. EXPECT_FALSE(m_registry->MergeCommandLineArgument(argument, {}, {}));
  1040. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType("/Test"));
  1041. }
  1042. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_MissingValue_ReturnsEmptyString)
  1043. {
  1044. EXPECT_TRUE(m_registry->MergeCommandLineArgument("Test=", {}, {}));
  1045. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test"));
  1046. AZ::SettingsRegistryInterface::FixedValueString value;
  1047. EXPECT_TRUE(m_registry->Get(value, "/Test"));
  1048. EXPECT_TRUE(value.empty());
  1049. }
  1050. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_MissingKey_ReturnsFalse)
  1051. {
  1052. EXPECT_FALSE(m_registry->MergeCommandLineArgument("=Value", {}, {}));
  1053. }
  1054. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_MissingKeyAndValue_ReturnsFalse)
  1055. {
  1056. EXPECT_FALSE(m_registry->MergeCommandLineArgument("=", {}, {}));
  1057. }
  1058. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_EmptyString_ReturnsFalse)
  1059. {
  1060. EXPECT_FALSE(m_registry->MergeCommandLineArgument("", {}, {}));
  1061. }
  1062. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyIsSpaces_ReturnsFalse)
  1063. {
  1064. EXPECT_FALSE(m_registry->MergeCommandLineArgument(" =Value", {}, {}));
  1065. }
  1066. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_ValueIsSpaces_ReturnsEmptyString)
  1067. {
  1068. EXPECT_TRUE(m_registry->MergeCommandLineArgument("Key= ", {}, {}));
  1069. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Key"));
  1070. AZ::SettingsRegistryInterface::FixedValueString value;
  1071. EXPECT_TRUE(m_registry->Get(value, "/Key"));
  1072. EXPECT_TRUE(value.empty());
  1073. }
  1074. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyAndValueAreSpaces_ReturnsFalse)
  1075. {
  1076. EXPECT_FALSE(m_registry->MergeCommandLineArgument(" = ", {}, {}));
  1077. }
  1078. TEST_F(SettingsRegistryTest, MergeCommandLineArgument_OnlySpaces_ReturnsFalse)
  1079. {
  1080. EXPECT_FALSE(m_registry->MergeCommandLineArgument(" ", {}, {}));
  1081. }
  1082. //
  1083. // MergeSettings
  1084. //
  1085. TEST_F(SettingsRegistryTest, MergeSettings_MergeJsonWithAnchorKey_StoresSettingsUnderneathKey)
  1086. {
  1087. constexpr AZStd::string_view anchorKey = "/Anchor/Root/0";
  1088. constexpr auto mergeFormat = AZ::SettingsRegistryInterface::Format::JsonMergePatch;
  1089. EXPECT_TRUE(m_registry->MergeSettings(R"({ "Test": "1" })", mergeFormat, anchorKey));
  1090. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Array, m_registry->GetType("/Anchor/Root"));
  1091. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType("/Anchor/Root/0"));
  1092. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Anchor/Root/0/Test"));
  1093. }
  1094. TEST_F(SettingsRegistryTest, MergeSettings_NotifierSignals_AtAnchorKeyAndStoresMergeType)
  1095. {
  1096. AZStd::string_view anchorKey = "/Anchor/Root";
  1097. bool callbackInvoked{};
  1098. auto callback = [anchorKey, &callbackInvoked](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1099. {
  1100. EXPECT_EQ(anchorKey, notifyEventArgs.m_jsonKeyPath);
  1101. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Array, notifyEventArgs.m_type);
  1102. callbackInvoked = true;
  1103. };
  1104. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1105. constexpr auto mergeFormat = AZ::SettingsRegistryInterface::Format::JsonMergePatch;
  1106. EXPECT_TRUE(m_registry->MergeSettings(R"([ "Test" ])", mergeFormat, anchorKey));
  1107. EXPECT_TRUE(callbackInvoked);
  1108. }
  1109. //
  1110. // MergeSettingsFile
  1111. //
  1112. TEST_F(SettingsRegistryTest, MergeSettingsFile_MergeTestFile_PatchAppliedAndReported)
  1113. {
  1114. auto path = CreateTestFile("test.setreg", R"({ "Test": 1 })");
  1115. auto callback = [this](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1116. {
  1117. EXPECT_TRUE(notifyEventArgs.m_jsonKeyPath.empty());
  1118. AZ::s64 value = -1;
  1119. bool result = m_registry->Get(value, "/Test");
  1120. EXPECT_TRUE(result);
  1121. EXPECT_EQ(1, value);
  1122. };
  1123. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1124. auto outcome = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr);
  1125. ASSERT_TRUE(outcome);
  1126. AZStd::string history;
  1127. bool result = m_registry->Get(history, AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0");
  1128. ASSERT_TRUE(result);
  1129. EXPECT_STREQ(path.c_str(), history.c_str());
  1130. }
  1131. TEST_F(SettingsRegistryTest, MergeSettingsFile_MergeTestFileWithRootKey_PatchAppliedAndReported)
  1132. {
  1133. auto path = CreateTestFile("test.setreg", R"({ "Test": 1 })");
  1134. auto callback = [this](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1135. {
  1136. EXPECT_EQ("/Path", notifyEventArgs.m_jsonKeyPath);
  1137. AZ::s64 value = -1;
  1138. bool result = m_registry->Get(value, "/Path/Test");
  1139. EXPECT_TRUE(result);
  1140. EXPECT_EQ(1, value);
  1141. };
  1142. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1143. auto outcome = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "/Path", nullptr);
  1144. ASSERT_TRUE(outcome);
  1145. AZStd::string history;
  1146. bool result = m_registry->Get(history, AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0");
  1147. ASSERT_TRUE(result);
  1148. EXPECT_STREQ(path.c_str(), history.c_str());
  1149. }
  1150. TEST_F(SettingsRegistryTest, MergeSettingsFile_MergeTestFileWithBuffer_PatchAppliedAndReported)
  1151. {
  1152. auto path = CreateTestFile("test.setreg", R"({ "Test": 1 })");
  1153. AZStd::vector<char> buffer;
  1154. buffer.push_back(32);
  1155. buffer.push_back(64);
  1156. auto result = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, &buffer);
  1157. EXPECT_TRUE(result);
  1158. EXPECT_TRUE(buffer.empty());
  1159. }
  1160. TEST_F(SettingsRegistryTest, MergeSettingsFile_EmptyPath_ReturnsFalse)
  1161. {
  1162. auto result = m_registry->MergeSettingsFile("", AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr);
  1163. EXPECT_FALSE(result);
  1164. }
  1165. TEST_F(SettingsRegistryTest, MergeSettingsFile_PathAsSubString_ReturnsTrue)
  1166. {
  1167. auto path = m_tempDirectory.GetDirectoryAsFixedMaxPath()
  1168. / AZ::SettingsRegistryInterface::RegistryFolder / "test.setreg1234";
  1169. CreateTestFile("test.setreg", R"({ "Test": 1 })");
  1170. AZStd::string_view subPath(path.c_str(), path.Native().size() - 4);
  1171. auto result = m_registry->MergeSettingsFile(subPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr);
  1172. EXPECT_TRUE(result);
  1173. }
  1174. TEST_F(SettingsRegistryTest, MergeSettingsFile_PathAsSubStringThatsTooLong_ReturnsFalse)
  1175. {
  1176. constexpr AZStd::fixed_string<AZ::IO::MaxPathLength + 1> path(AZ::IO::MaxPathLength + 1, '1');
  1177. const AZStd::string_view subPath(path);
  1178. auto result = m_registry->MergeSettingsFile(subPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr);
  1179. EXPECT_FALSE(result);
  1180. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1181. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1182. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1183. }
  1184. TEST_F(SettingsRegistryTest, MergeSettingsFile_InvalidPath_ReturnsFalse)
  1185. {
  1186. auto result = m_registry->MergeSettingsFile("InvalidPath", AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr);
  1187. EXPECT_FALSE(result);
  1188. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1189. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1190. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1191. }
  1192. TEST_F(SettingsRegistryTest, MergeSettingsFile_InvalidRootKey_ReturnsFalse)
  1193. {
  1194. auto path = CreateTestFile("test.setreg", R"({ "Test": 1 })");
  1195. auto result = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "$", nullptr);
  1196. EXPECT_FALSE(result);
  1197. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1198. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1199. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1200. }
  1201. TEST_F(SettingsRegistryTest, MergeSettingsFile_ParseError_ReturnsFalse)
  1202. {
  1203. auto path = CreateTestFile("test.setreg", "{ Test: 1 }");
  1204. auto result = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr);
  1205. EXPECT_FALSE(result);
  1206. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1207. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1208. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1209. }
  1210. TEST_F(SettingsRegistryTest, MergeSettingsFile_NonObjectRoot_EmptyRootKey_JsonMergePatch_ReturnsFalse)
  1211. {
  1212. auto path = CreateTestFile("test.setreg", R"("BooleanValue": false)");
  1213. auto result = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, {});
  1214. EXPECT_FALSE(result);
  1215. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1216. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1217. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1218. }
  1219. TEST_F(SettingsRegistryTest, MergeSettingsFile_NonObjectRoot_NonEmptyRootKey_JsonMergePatch_ReturnsFalse)
  1220. {
  1221. // Because the root key isn't empty the setting registry will not be be completely overridden and therefore
  1222. // it is safe to merge the .setreg file with a boolean element at the root
  1223. auto path = CreateTestFile("test.setreg", R"("BooleanValue": false)");
  1224. EXPECT_FALSE(m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "/Test"));
  1225. // There should be an error message about attempting to serialize a root json value that is not a Json Object
  1226. // to the settings registry
  1227. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1228. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1229. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1230. }
  1231. TEST_F(SettingsRegistryTest, MergeSettingsFile_EmptyObjectRoot_EmptyRootKey_JsonMergePatch_PatchAppliedAndReported)
  1232. {
  1233. // In this scenario the object root is empty. The Merge should complete successfully
  1234. // but leave the settings registry unchanged.
  1235. auto path = CreateTestFile("test.setreg", R"({})");
  1236. // Initialize the Settings Registry with an Object at /TestObject/IntValue
  1237. m_registry->MergeSettings(R"({ "TestObject": { "IntValue": 7 } })", AZ::SettingsRegistryInterface::Format::JsonMergePatch);
  1238. // Merging a file with a empty JSON Object should be effectively a no-op.
  1239. // There are some changes in the settings registry to record the merge history for introspection purposes.
  1240. auto outcome = m_registry->MergeSettingsFile(path.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, {});
  1241. EXPECT_TRUE(outcome);
  1242. AZStd::string history;
  1243. bool result = m_registry->Get(history, AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0");
  1244. EXPECT_TRUE(result);
  1245. EXPECT_STREQ(path.c_str(), history.c_str());
  1246. AZ::s64 intValue{};
  1247. EXPECT_TRUE(m_registry->Get(intValue, "/TestObject/IntValue"));
  1248. EXPECT_EQ(7, intValue);
  1249. }
  1250. //
  1251. // MergeSettingsFolder
  1252. //
  1253. TEST_F(SettingsRegistryTest, MergeSettingsFolder_MergeTestFiles_FilesAppliedInSpecializationOrder)
  1254. {
  1255. CreateTestFile("Memory.setreg", R"({ "Memory": 0, "MemoryRoot": true })");
  1256. CreateTestFile("Memory.editor.test.setreg", R"({ "Memory": 3, "MemoryEditorTest": true })");
  1257. CreateTestFile("Memory.editor.setreg", R"({ "Memory": 1, "MemoryEditor": true })");
  1258. CreateTestFile("Memory.test.setreg", R"({ "Memory": 2, "MemoryTest": true })");
  1259. size_t counter = 0;
  1260. auto callback = [this, &counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1261. {
  1262. const char* fileIds[] =
  1263. {
  1264. "/MemoryRoot",
  1265. "/MemoryEditor",
  1266. "/MemoryTest",
  1267. "/MemoryEditorTest"
  1268. };
  1269. MergeNotify(notifyEventArgs.m_jsonKeyPath, counter, AZ_ARRAY_SIZE(fileIds), "/Memory", fileIds);
  1270. counter++;
  1271. };
  1272. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1273. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), {"editor", "test"}, {});
  1274. EXPECT_TRUE(result);
  1275. EXPECT_EQ(4, counter);
  1276. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1277. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1278. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2"));
  1279. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/3"));
  1280. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/4"));
  1281. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/5"));
  1282. }
  1283. TEST_F(SettingsRegistryTest, MergeSettingsFolder_WithPlatformFiles_FilesAppliedInSpecializationOrder)
  1284. {
  1285. CreateTestFile("Memory.setreg", R"({ "Memory": 0, "MemoryRoot": true })");
  1286. CreateTestFile("Memory.editor.test.setreg", R"({ "Memory": 5, "MemoryEditorTest": true })");
  1287. CreateTestFile("Memory.editor.setreg", R"({ "Memory": 2, "MemoryEditor": true })");
  1288. CreateTestFile("Memory.test.setreg", R"({ "Memory": 4, "MemoryTest": true })");
  1289. CreateTestFile("Platform/Special/Memory.setreg", R"({ "Memory": 1, "MemorySpecial": true })");
  1290. CreateTestFile("Platform/Special/Memory.editor.setreg", R"({ "Memory": 3, "MemoryEditorSpecial": true })");
  1291. size_t counter = 0;
  1292. auto callback = [this, &counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1293. {
  1294. const char* fileIds[] =
  1295. {
  1296. "/MemoryRoot",
  1297. "/MemorySpecial",
  1298. "/MemoryEditor",
  1299. "/MemoryEditorSpecial",
  1300. "/MemoryTest",
  1301. "/MemoryEditorTest"
  1302. };
  1303. MergeNotify(notifyEventArgs.m_jsonKeyPath, counter, AZ_ARRAY_SIZE(fileIds), "/Memory", fileIds);
  1304. counter++;
  1305. };
  1306. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1307. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), { "editor", "test" }, "Special");
  1308. EXPECT_TRUE(result);
  1309. EXPECT_EQ(6, counter);
  1310. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1311. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1312. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2"));
  1313. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/3"));
  1314. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/4"));
  1315. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/5"));
  1316. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/6"));
  1317. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/7"));
  1318. }
  1319. TEST_F(SettingsRegistryTest, MergeSettingsFolder_DifferentlyNamedFiles_FilesAppliedInAlphabeticAndSpecializationOrder)
  1320. {
  1321. CreateTestFile("c.setreg", R"({ "Id": 2, "c": true })");
  1322. CreateTestFile("a.editor.test.setreg", R"({ "Id": 0, "a": true })");
  1323. CreateTestFile("b.editor.setreg", R"({ "Id": 1, "b": true })");
  1324. CreateTestFile("c.test.setreg", R"({ "Id": 3, "cTest": true })");
  1325. size_t counter = 0;
  1326. auto callback = [this, &counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1327. {
  1328. const char* fileIds[] =
  1329. {
  1330. "/a",
  1331. "/b",
  1332. "/c",
  1333. "/cTest"
  1334. };
  1335. MergeNotify(notifyEventArgs.m_jsonKeyPath, counter, AZ_ARRAY_SIZE(fileIds), "/Id", fileIds);
  1336. counter++;
  1337. };
  1338. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1339. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), { "editor", "test" }, {});
  1340. EXPECT_TRUE(result);
  1341. EXPECT_EQ(4, counter);
  1342. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1343. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1344. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2"));
  1345. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/3"));
  1346. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/4"));
  1347. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/5"));
  1348. }
  1349. TEST_F(SettingsRegistryTest, MergeSettingsFolder_JsonPatchFiles_FilesAppliedInAlphabeticAndSpecializationOrder)
  1350. {
  1351. CreateTestFile("Memory.setreg", R"({ "Memory": 0, "MemoryRoot": true })");
  1352. CreateTestFile("Memory.editor.test.setreg", R"({ "Memory": 3, "MemoryEditorTest": true })");
  1353. CreateTestFile("Memory.editor.setreg", R"({ "Memory": 1, "MemoryEditor": true })");
  1354. CreateTestFile("Memory.test.setregpatch", R"(
  1355. [
  1356. { "op": "replace", "path": "/Memory", "value": 2 },
  1357. { "op": "add", "path": "/MemoryTest", "value": true }
  1358. ])");
  1359. size_t counter = 0;
  1360. auto callback = [this, &counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1361. {
  1362. const char* fileIds[] =
  1363. {
  1364. "/MemoryRoot",
  1365. "/MemoryEditor",
  1366. "/MemoryTest",
  1367. "/MemoryEditorTest"
  1368. };
  1369. MergeNotify(notifyEventArgs.m_jsonKeyPath, counter, AZ_ARRAY_SIZE(fileIds), "/Memory", fileIds);
  1370. counter++;
  1371. };
  1372. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1373. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), { "editor", "test" }, {});
  1374. EXPECT_TRUE(result);
  1375. EXPECT_EQ(4, counter);
  1376. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1377. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1378. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2"));
  1379. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/3"));
  1380. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/4"));
  1381. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/5"));
  1382. }
  1383. TEST_F(SettingsRegistryTest, MergeSettingsFolder_UnsupportedFilesAreIgnored_OneFileAppliedAndSuccessReturned)
  1384. {
  1385. CreateTestFile("Memory.setreg", R"({ "Memory": 0, "MemoryRoot": true })");
  1386. CreateTestFile("Memory.wrong", R"({ "Memory": 1, "Wrong": true })");
  1387. CreateTestFile("Platform/Special/Memory.wrong", R"({ "Memory": 2, "SpecialWrong": true })");
  1388. size_t counter = 0;
  1389. auto callback = [this, &counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1390. {
  1391. const char* fileIds[] =
  1392. {
  1393. "/MemoryRoot"
  1394. };
  1395. MergeNotify(notifyEventArgs.m_jsonKeyPath, counter, AZ_ARRAY_SIZE(fileIds), "/Memory", fileIds);
  1396. counter++;
  1397. };
  1398. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1399. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), { "editor", "test" }, "Special");
  1400. EXPECT_TRUE(result);
  1401. EXPECT_EQ(1, counter);
  1402. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1403. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1404. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2"));
  1405. }
  1406. TEST_F(SettingsRegistryTest, MergeSettingsFolder_WithScratchBuffer_FilesAppliedInSpecializationOrder)
  1407. {
  1408. CreateTestFile("Memory.setreg", R"({ "Memory": 0, "MemoryRoot": true })");
  1409. CreateTestFile("Memory.editor.test.setreg", R"({ "Memory": 3, "MemoryEditorTest": true })");
  1410. CreateTestFile("Memory.editor.setreg", R"({ "Memory": 1, "MemoryEditor": true })");
  1411. CreateTestFile("Memory.test.setreg", R"({ "Memory": 2, "MemoryTest": true })");
  1412. size_t counter = 0;
  1413. auto callback = [this, &counter](const AZ::SettingsRegistryInterface::NotifyEventArgs& notifyEventArgs)
  1414. {
  1415. const char* fileIds[] =
  1416. {
  1417. "/MemoryRoot",
  1418. "/MemoryEditor",
  1419. "/MemoryTest",
  1420. "/MemoryEditorTest"
  1421. };
  1422. MergeNotify(notifyEventArgs.m_jsonKeyPath, counter, AZ_ARRAY_SIZE(fileIds), "/Memory", fileIds);
  1423. counter++;
  1424. };
  1425. auto testNotifier1 = m_registry->RegisterNotifier(callback);
  1426. AZStd::vector<char> buffer;
  1427. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), { "editor", "test" }, {}, "", &buffer);
  1428. EXPECT_TRUE(result);
  1429. EXPECT_EQ(4, counter);
  1430. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1431. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1432. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2"));
  1433. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/3"));
  1434. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/4"));
  1435. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/5"));
  1436. }
  1437. TEST_F(SettingsRegistryTest, MergeSettingsFolder_EmptyFolder_ReportsSuccessButNothingAdded)
  1438. {
  1439. auto result = m_registry->MergeSettingsFolder(m_tempDirectory.GetDirectoryAsFixedMaxPath().Native(), { "editor", "test" }, {});
  1440. EXPECT_TRUE(result);
  1441. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1442. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1443. }
  1444. TEST_F(SettingsRegistryTest, MergeSettingsFolder_PathTooLong_ReportsErrorAndReturnsFalse)
  1445. {
  1446. constexpr AZStd::fixed_string<AZ::IO::MaxPathLength + 1> path(AZ::IO::MaxPathLength + 1, 'a');
  1447. AZ_TEST_START_TRACE_SUPPRESSION;
  1448. auto result = m_registry->MergeSettingsFolder(path, { "editor", "test" }, {});
  1449. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  1450. EXPECT_FALSE(result);
  1451. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0"));
  1452. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Error"));
  1453. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
  1454. }
  1455. TEST_F(SettingsRegistryTest, MergeSettingsFolder_ConflictingSpecializations_ReportsErrorAndReturnsFalse)
  1456. {
  1457. CreateTestFile("Memory.test.editor.setreg", "{}");
  1458. CreateTestFile("Memory.editor.test.setreg", "{}");
  1459. AZ_TEST_START_TRACE_SUPPRESSION;
  1460. auto result = m_registry->MergeSettingsFolder((m_tempDirectory.GetDirectoryAsFixedMaxPath() / AZ::SettingsRegistryInterface::RegistryFolder).Native(), { "editor", "test" }, {});
  1461. EXPECT_GT(::UnitTest::TestRunner::Instance().StopAssertTests(), 0);
  1462. EXPECT_FALSE(result);
  1463. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings.
  1464. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1"));
  1465. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/Error"));
  1466. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/Path"));
  1467. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/File1"));
  1468. EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/File2"));
  1469. }
  1470. } // namespace SettingsRegistryTests