2
0

MetadataManagerTests.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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/RTTI/ReflectContext.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. #include <AzToolsFramework/Metadata/MetadataManager.h>
  11. #include <AzCore/Serialization/Json/JsonSystemComponent.h>
  12. #include <AzCore/Serialization/Json/RegistrationContext.h>
  13. #include <AzCore/UnitTest/Mocks/MockFileIOBase.h>
  14. #include <AzCore/Component/ComponentApplication.h>
  15. #include <AzCore/Utils/Utils.h>
  16. namespace UnitTest
  17. {
  18. struct MyTestType
  19. {
  20. AZ_TYPE_INFO(MyTestType, "{48ABC814-9E03-4738-BB5A-7BE07F28BBD8}");
  21. static void Reflect(AZ::ReflectContext* context)
  22. {
  23. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  24. {
  25. if (s_version == 1)
  26. {
  27. serializeContext->Class<MyTestType>()
  28. ->Version(s_version)
  29. ->Field("int", &MyTestType::m_int)
  30. ->Field("string", &MyTestType::m_string);
  31. }
  32. else
  33. {
  34. serializeContext->Class<MyTestType>()
  35. ->Version(s_version)
  36. ->Field("float", &MyTestType::m_float)
  37. ->Field("string", &MyTestType::m_string);
  38. }
  39. }
  40. }
  41. // Used to switch reflected version
  42. static inline int s_version = 1;
  43. int m_int;
  44. AZStd::string m_string;
  45. float m_float;
  46. };
  47. struct MetadataManagerTests
  48. : LeakDetectionFixture
  49. , AZ::ComponentApplicationBus::Handler
  50. {
  51. //////////////////////////////////////////////////////////////////////////
  52. // ComponentApplicationMessages
  53. AZ::ComponentApplication* GetApplication() override { return nullptr; }
  54. void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override { }
  55. void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override { }
  56. void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override { }
  57. void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override { }
  58. void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override { }
  59. void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override { }
  60. void SignalEntityActivated(AZ::Entity*) override { }
  61. void SignalEntityDeactivated(AZ::Entity*) override { }
  62. bool AddEntity(AZ::Entity*) override { return false; }
  63. bool RemoveEntity(AZ::Entity*) override { return false; }
  64. bool DeleteEntity(const AZ::EntityId&) override { return false; }
  65. AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; }
  66. AZ::SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); }
  67. AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; }
  68. AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return m_jsonRegistrationContext.get(); }
  69. const char* GetEngineRoot() const override { return nullptr; }
  70. const char* GetExecutableFolder() const override { return nullptr; }
  71. void EnumerateEntities(const EntityCallback& /*callback*/) override {}
  72. void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
  73. //////////////////////////////////////////////////////////////////////////
  74. void SetUp() override
  75. {
  76. UnitTest::TestRunner::Instance().m_suppressPrintf = false;
  77. UnitTest::TestRunner::Instance().m_suppressAsserts = false;
  78. UnitTest::TestRunner::Instance().m_suppressErrors = false;
  79. UnitTest::TestRunner::Instance().m_suppressOutput = false;
  80. UnitTest::TestRunner::Instance().m_suppressWarnings = false;
  81. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  82. m_jsonRegistrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
  83. AZ::ComponentApplicationBus::Handler::BusConnect();
  84. AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
  85. MyTestType::Reflect(m_serializeContext.get());
  86. // Cache the existing file io instance and build our mock file io
  87. m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
  88. m_fileIOMock = AZStd::make_unique<testing::NiceMock<AZ::IO::MockFileIOBase>>();
  89. // Swap out current file io instance for our mock
  90. AZ::IO::FileIOBase::SetInstance(nullptr);
  91. AZ::IO::FileIOBase::SetInstance(m_fileIOMock.get());
  92. // Setup the default returns for our mock file io calls
  93. AZ::IO::MockFileIOBase::InstallDefaultReturns(*m_fileIOMock.get());
  94. using namespace ::testing;
  95. using namespace AZ;
  96. ON_CALL(*m_fileIOMock, Open(_, _, _))
  97. .WillByDefault(Invoke(
  98. [](auto filePath, auto, IO::HandleType& handle)
  99. {
  100. handle = AZ::u32(AZStd::hash<AZStd::string>{}( filePath ));
  101. return AZ::IO::Result(AZ::IO::ResultCode::Success);
  102. }));
  103. ON_CALL(*m_fileIOMock, Size(An<AZ::IO::HandleType>(), _))
  104. .WillByDefault(Invoke(
  105. [this](auto handle, AZ::u64& size)
  106. {
  107. size = m_mockFiles[handle].size();
  108. return AZ::IO::ResultCode::Success;
  109. }));
  110. ON_CALL(*m_fileIOMock, Size(An<const char*>(), _))
  111. .WillByDefault(Invoke(
  112. [this](const char* filePath, AZ::u64& size)
  113. {
  114. auto handle = AZ::u32(AZStd::hash<AZStd::string>{}(filePath));
  115. size = m_mockFiles[handle].size();
  116. return AZ::IO::ResultCode::Success;
  117. }));
  118. ON_CALL(*m_fileIOMock, Exists(_))
  119. .WillByDefault(Invoke(
  120. [this](const char* filePath)
  121. {
  122. auto handle = AZ::u32(AZStd::hash<AZStd::string>{}(filePath));
  123. auto itr = m_mockFiles.find(handle);
  124. return itr != m_mockFiles.end() && itr->second.size() > 0;
  125. }));
  126. ON_CALL(*m_fileIOMock, Read(_, _, _, _, _))
  127. .WillByDefault(Invoke(
  128. [this](auto handle, void* buffer, auto, auto, AZ::u64* bytesRead)
  129. {
  130. auto itr = m_mockFiles.find(handle);
  131. if (itr == m_mockFiles.end())
  132. {
  133. return AZ::IO::ResultCode::Error;
  134. }
  135. memcpy(buffer, itr->second.c_str(), itr->second.size());
  136. *bytesRead = itr->second.size();
  137. return AZ::IO::ResultCode::Success;
  138. }));
  139. ON_CALL(*m_fileIOMock, Write(_, _, _, _))
  140. .WillByDefault(Invoke(
  141. [this](IO::HandleType fileHandle, const void* buffer, AZ::u64 size, AZ::u64* bytesWritten)
  142. {
  143. AZStd::string& file = m_mockFiles[fileHandle];
  144. file.resize(size);
  145. memcpy((void*)file.c_str(), buffer, size);
  146. *bytesWritten = size;
  147. return AZ::IO::ResultCode::Success;
  148. }));
  149. m_metadata = AZ::Interface<AzToolsFramework::IMetadataRequests>::Get();
  150. ASSERT_TRUE(m_metadata);
  151. }
  152. void TearDown() override
  153. {
  154. AZ::ComponentApplicationBus::Handler::BusDisconnect();
  155. m_jsonRegistrationContext->EnableRemoveReflection();
  156. AZ::JsonSystemComponent::Reflect(m_jsonRegistrationContext.get());
  157. m_jsonRegistrationContext->DisableRemoveReflection();
  158. m_jsonRegistrationContext.reset();
  159. m_serializeContext.reset();
  160. AZ::IO::FileIOBase::SetInstance(nullptr);
  161. AZ::IO::FileIOBase::SetInstance(m_priorFileIO);
  162. UnitTest::TestRunner::Instance().ResetSuppressionSettingsToDefault();
  163. }
  164. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  165. AZStd::unique_ptr<AZ::JsonRegistrationContext> m_jsonRegistrationContext;
  166. AZStd::unique_ptr<testing::NiceMock<AZ::IO::MockFileIOBase>> m_fileIOMock;
  167. AZ::IO::FileIOBase* m_priorFileIO = nullptr;
  168. AZStd::unordered_map<AZ::IO::HandleType, AZStd::string> m_mockFiles;
  169. AzToolsFramework::MetadataManager m_manager;
  170. AzToolsFramework::IMetadataRequests* m_metadata = nullptr;
  171. };
  172. TEST_F(MetadataManagerTests, Get_FileDoesNotExist_ReturnsFalse)
  173. {
  174. MyTestType test;
  175. auto result = m_metadata->GetValue("mockfile", "/Test", &test, azrtti_typeid<MyTestType>());
  176. ASSERT_TRUE(result);
  177. EXPECT_FALSE(result.GetValue());
  178. }
  179. TEST_F(MetadataManagerTests, Get_EmptyFile_ReturnsFalse)
  180. {
  181. AZ::Utils::WriteFile(
  182. "", AZStd::string("mockfile") + AzToolsFramework::MetadataManager::MetadataFileExtension);
  183. MyTestType test;
  184. auto result = m_metadata->GetValue("mockfile", "/Test", &test, azrtti_typeid<MyTestType>());
  185. ASSERT_TRUE(result);
  186. EXPECT_FALSE(result.GetValue());
  187. }
  188. TEST_F(MetadataManagerTests, Get_InvalidFile_ReturnsFalse)
  189. {
  190. AZ::Utils::WriteFile("This is not a metadata file", AZStd::string("mockfile") + AzToolsFramework::MetadataManager::MetadataFileExtension);
  191. MyTestType test;
  192. EXPECT_FALSE(m_metadata->GetValue("mockfile", "/Test", &test, azrtti_typeid<MyTestType>()));
  193. }
  194. TEST_F(MetadataManagerTests, Get_InvalidKey_ReturnsFalse)
  195. {
  196. MyTestType test;
  197. EXPECT_FALSE(m_metadata->GetValue("mockfile", "Test", &test, azrtti_typeid<MyTestType>()));
  198. }
  199. TEST_F(MetadataManagerTests, Set_ReturnsTrue)
  200. {
  201. MyTestType test;
  202. EXPECT_TRUE(m_metadata->SetValue("mockfile", "/Test", &test, azrtti_typeid<MyTestType>()));
  203. }
  204. TEST_F(MetadataManagerTests, Set_InvalidKey_ReturnsFalse)
  205. {
  206. MyTestType test;
  207. EXPECT_FALSE(m_metadata->SetValue("mockfile", "Test", &test, azrtti_typeid<MyTestType>()));
  208. }
  209. TEST_F(MetadataManagerTests, SetGet_ReadsValueCorrectly)
  210. {
  211. MyTestType outValue;
  212. MyTestType inValue;
  213. outValue.m_int = 23;
  214. outValue.m_string = "Hello World";
  215. EXPECT_TRUE(m_metadata->SetValue("mockfile", "/Test", &outValue, azrtti_typeid<MyTestType>()));
  216. EXPECT_TRUE(m_metadata->GetValue("mockfile", "/Test", &inValue, azrtti_typeid<MyTestType>()));
  217. EXPECT_EQ(outValue.m_int, inValue.m_int);
  218. EXPECT_EQ(outValue.m_string, inValue.m_string);
  219. }
  220. TEST_F(MetadataManagerTests, Get_FileExists_KeyDoesNotExist_ReturnsFalse)
  221. {
  222. MyTestType test;
  223. EXPECT_TRUE(m_metadata->SetValue("mockfile", "/Test", test));
  224. EXPECT_FALSE(m_metadata->GetValue("mockfile", "/DoesNotExist", test));
  225. }
  226. TEST_F(MetadataManagerTests, Get_FileVersion_ReturnsTrue)
  227. {
  228. MyTestType test;
  229. EXPECT_TRUE(m_metadata->SetValue("mockfile", "/Test", &test, azrtti_typeid<MyTestType>()));
  230. int version = 0;
  231. EXPECT_TRUE(m_metadata->GetValue("mockfile", AzToolsFramework::MetadataManager::MetadataVersionKey, &version, azrtti_typeid<int>()));
  232. EXPECT_EQ(version, AzToolsFramework::MetadataManager::MetadataVersion);
  233. }
  234. TEST_F(MetadataManagerTests, Set_InvalidMetadataFile_ReturnsFalse)
  235. {
  236. AZ::Utils::WriteFile("This is not a metadata file", AZStd::string("mockfile") + AzToolsFramework::MetadataManager::MetadataFileExtension);
  237. MyTestType test;
  238. EXPECT_FALSE(m_metadata->SetValue("mockfile", "/Test", &test, azrtti_typeid<MyTestType>()));
  239. }
  240. TEST_F(MetadataManagerTests, Get_OldVersion)
  241. {
  242. MyTestType test;
  243. test.m_int = 23;
  244. test.m_string = "Hello World";
  245. EXPECT_TRUE(m_metadata->SetValue("mockfile", "/Test", test));
  246. // Unregister the existing type
  247. m_serializeContext->EnableRemoveReflection();
  248. MyTestType::Reflect(m_serializeContext.get());
  249. m_serializeContext->DisableRemoveReflection();
  250. // "Upgrade" the type
  251. MyTestType::s_version = 2;
  252. MyTestType::Reflect(m_serializeContext.get());
  253. // Now try to read the old value
  254. int version;
  255. EXPECT_TRUE(m_metadata->GetValueVersion("mockfile", "/Test", version));
  256. EXPECT_EQ(version, 1);
  257. rapidjson::Document inValue;
  258. EXPECT_TRUE(m_metadata->GetJson("mockfile", "/Test", inValue));
  259. auto intItr = inValue.FindMember("int");
  260. auto stringItr = inValue.FindMember("string");
  261. EXPECT_NE(intItr, inValue.MemberEnd());
  262. EXPECT_NE(stringItr, inValue.MemberEnd());
  263. EXPECT_EQ(intItr->value.GetInt(), test.m_int);
  264. EXPECT_EQ(stringItr->value.GetString(), test.m_string);
  265. }
  266. }