SceneBuilderPhasesTests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <gmock/gmock.h>
  9. #include <AzCore/Component/Component.h>
  10. #include <AzCore/Component/ComponentApplication.h>
  11. #include <AzCore/Module/Environment.h>
  12. #include <AzCore/RTTI/ReflectContext.h>
  13. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  14. #include <AzCore/UnitTest/TestTypes.h>
  15. #include <AzCore/UserSettings/UserSettingsComponent.h>
  16. #include <AzCore/std/smart_ptr/make_shared.h>
  17. #include <Application/ToolsApplication.h>
  18. #include <AssetBuilderSDK/AssetBuilderSDK.h>
  19. #include <SceneAPI/SceneCore/Components/ExportingComponent.h>
  20. #include <SceneAPI/SceneCore/Components/GenerationComponent.h>
  21. #include <SceneAPI/SceneCore/Components/LoadingComponent.h>
  22. #include <SceneAPI/SceneCore/Components/Utilities/EntityConstructor.h>
  23. #include <SceneAPI/SceneCore/Containers/Scene.h>
  24. #include <SceneAPI/SceneCore/Events/ExportEventContext.h>
  25. #include <SceneAPI/SceneCore/Events/GenerateEventContext.h>
  26. #include <SceneAPI/SceneCore/Events/ImportEventContext.h>
  27. #include <SceneAPI/SceneCore/Events/ProcessingResult.h>
  28. #include <SceneAPI/SceneCore/Events/SceneSerializationBus.h>
  29. #include <SceneAPI/SceneCore/Mocks/DataTypes/Groups/MockIGroup.h>
  30. #include <SceneBuilder/SceneBuilderWorker.h>
  31. // This component descriptor allows for a component to be created beforehand,
  32. // and is then returned when an instance of that component is requested.
  33. // This allows for a component to be pre-configured, via EXPECT calls.
  34. template<class ComponentType>
  35. class ComponentSingleton
  36. : public AZ::ComponentDescriptorDefault<ComponentType>
  37. {
  38. public:
  39. AZ_CLASS_ALLOCATOR(ComponentSingleton, AZ::SystemAllocator)
  40. AZ::Component* CreateComponent() override { return m_component; }
  41. void SetComponent(ComponentType* c) { m_component = c; }
  42. private:
  43. ComponentType* m_component = nullptr;
  44. };
  45. class TestLoadingComponent
  46. : public AZ::SceneAPI::SceneCore::LoadingComponent
  47. {
  48. public:
  49. AZ_RTTI(TestLoadingComponent, "{19B714CA-6AEF-414D-A91C-54E73DF69625}", AZ::SceneAPI::SceneCore::LoadingComponent, AZ::Component)
  50. using DescriptorType = ComponentSingleton<TestLoadingComponent>;
  51. AZ_COMPONENT_BASE(TestLoadingComponent);
  52. AZ_CLASS_ALLOCATOR(TestLoadingComponent, AZ::ComponentAllocator);
  53. static void Reflect(AZ::ReflectContext* context)
  54. {
  55. if (AZ::SerializeContext* sc = azrtti_cast<AZ::SerializeContext*>(context); sc)
  56. {
  57. sc->Class<TestLoadingComponent, AZ::SceneAPI::SceneCore::LoadingComponent>()->Version(1);
  58. }
  59. }
  60. TestLoadingComponent() { BindToCall(&TestLoadingComponent::Load); }
  61. MOCK_CONST_METHOD1(Load, AZ::SceneAPI::Events::ProcessingResult(AZ::SceneAPI::Events::ImportEventContext& context));
  62. };
  63. class TestGenerationComponent
  64. : public AZ::SceneAPI::SceneCore::GenerationComponent
  65. {
  66. public:
  67. AZ_RTTI(TestGenerationComponent, "{3350BD61-2EB1-4F77-B1BD-D108795015EE}", AZ::SceneAPI::SceneCore::GenerationComponent, AZ::Component)
  68. using DescriptorType = ComponentSingleton<TestGenerationComponent>;
  69. AZ_COMPONENT_BASE(TestGenerationComponent);
  70. AZ_CLASS_ALLOCATOR(TestGenerationComponent, AZ::ComponentAllocator);
  71. static void Reflect(AZ::ReflectContext* context)
  72. {
  73. if (AZ::SerializeContext* sc = azrtti_cast<AZ::SerializeContext*>(context); sc)
  74. {
  75. sc->Class<TestGenerationComponent, AZ::SceneAPI::SceneCore::GenerationComponent>()->Version(1);
  76. }
  77. }
  78. TestGenerationComponent() { BindToCall(&TestGenerationComponent::Generate); }
  79. MOCK_CONST_METHOD1(Generate, AZ::SceneAPI::Events::ProcessingResult(AZ::SceneAPI::Events::GenerateEventContext& context));
  80. };
  81. class TestExportingComponent
  82. : public AZ::SceneAPI::SceneCore::ExportingComponent
  83. {
  84. public:
  85. AZ_RTTI(TestExportingComponent, "{EADA08AD-2068-4607-AA3D-8B17C59696D5}", AZ::SceneAPI::SceneCore::ExportingComponent, AZ::Component)
  86. using DescriptorType = ComponentSingleton<TestExportingComponent>;
  87. AZ_COMPONENT_BASE(TestExportingComponent);
  88. AZ_CLASS_ALLOCATOR(TestExportingComponent, AZ::ComponentAllocator);
  89. static void Reflect(AZ::ReflectContext* context)
  90. {
  91. if (AZ::SerializeContext* sc = azrtti_cast<AZ::SerializeContext*>(context); sc)
  92. {
  93. sc->Class<TestExportingComponent, AZ::SceneAPI::SceneCore::ExportingComponent>()->Version(1);
  94. }
  95. }
  96. TestExportingComponent() { BindToCall(&TestExportingComponent::Export); }
  97. MOCK_CONST_METHOD1(Export, AZ::SceneAPI::Events::ProcessingResult(const AZ::SceneAPI::Events::ExportEventContext& context));
  98. };
  99. // This scene loader handler mocks the LoadScene method, so that the user can
  100. // control the Scene that is generated in the test. But the default handler
  101. // used in production is also responsible for generating the Import events.
  102. // This test is designed to test the order of the import phases, so a method is
  103. // provided to generate those events.
  104. class TestSceneSerializationHandler
  105. : public AZ::SceneAPI::Events::SceneSerializationBus::Handler
  106. {
  107. public:
  108. TestSceneSerializationHandler() { BusConnect(); }
  109. ~TestSceneSerializationHandler() override { BusDisconnect(); }
  110. MOCK_METHOD3(LoadScene, AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene>(const AZStd::string& sceneFilePath, AZ::Uuid sceneSourceGuid, const AZStd::string& watchFolder));
  111. void GenerateImportEvents(const AZStd::string& assetFilePath, [[maybe_unused]] const AZ::Uuid& sourceGuid, [[maybe_unused]] const AZStd::string& watchFolder)
  112. {
  113. auto loaders = AZ::SceneAPI::SceneCore::EntityConstructor::BuildEntity("Scene Loading", azrtti_typeid<AZ::SceneAPI::SceneCore::LoadingComponent>());
  114. auto scene = AZStd::make_shared<AZ::SceneAPI::Containers::Scene>("import scene");
  115. AZ::SceneAPI::Events::ProcessingResultCombiner contextResult;
  116. contextResult += AZ::SceneAPI::Events::Process<AZ::SceneAPI::Events::PreImportEventContext>(assetFilePath);
  117. contextResult += AZ::SceneAPI::Events::Process<AZ::SceneAPI::Events::ImportEventContext>(assetFilePath, *scene);
  118. contextResult += AZ::SceneAPI::Events::Process<AZ::SceneAPI::Events::PostImportEventContext>(*scene);
  119. }
  120. };
  121. // This fixture attaches the SceneCore and SceneData libraries, and attaches
  122. // the AZ::Environment to them
  123. class SceneBuilderPhasesFixture
  124. : public UnitTest::LeakDetectionFixture
  125. {
  126. public:
  127. void SetUp() override
  128. {
  129. AZ::SettingsRegistryInterface* registry = AZ::SettingsRegistry::Get();
  130. auto projectPathKey =
  131. AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path";
  132. AZ::IO::FixedMaxPath enginePath;
  133. registry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
  134. registry->Set(projectPathKey, (enginePath / "AutomatedTesting").Native());
  135. AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
  136. AZ::ComponentApplication::StartupParameters startupParameters;
  137. startupParameters.m_loadSettingsRegistry = false;
  138. m_app.Start(AZ::ComponentApplication::Descriptor(), startupParameters);
  139. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  140. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  141. // in the unit tests.
  142. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  143. m_app.RegisterComponentDescriptor(TestLoadingComponent::CreateDescriptor());
  144. m_app.RegisterComponentDescriptor(TestGenerationComponent::CreateDescriptor());
  145. m_app.RegisterComponentDescriptor(TestExportingComponent::CreateDescriptor());
  146. m_sceneCoreModule = LoadSceneModule("SceneCore");
  147. m_sceneDataModule = LoadSceneModule("SceneData");
  148. }
  149. void TearDown() override
  150. {
  151. m_app.Stop();
  152. UnloadModule(m_sceneCoreModule);
  153. UnloadModule(m_sceneDataModule);
  154. }
  155. private:
  156. static AZStd::unique_ptr<AZ::DynamicModuleHandle> LoadSceneModule(const char* name)
  157. {
  158. auto module = AZ::DynamicModuleHandle::Create(name);
  159. if (!module)
  160. {
  161. return {};
  162. }
  163. module->Load();
  164. if (auto init = module->GetFunction<AZ::InitializeDynamicModuleFunction>(AZ::InitializeDynamicModuleFunctionName); init)
  165. {
  166. AZStd::invoke(init);
  167. }
  168. return module;
  169. }
  170. static void UnloadModule(AZStd::unique_ptr<AZ::DynamicModuleHandle>& module)
  171. {
  172. if (!module)
  173. {
  174. return;
  175. }
  176. if (auto uninit = module->GetFunction<AZ::UninitializeDynamicModuleFunction>(AZ::UninitializeDynamicModuleFunctionName); uninit)
  177. {
  178. AZStd::invoke(uninit);
  179. }
  180. module = nullptr;
  181. }
  182. AzToolsFramework::ToolsApplication m_app;
  183. AZStd::unique_ptr<AZ::DynamicModuleHandle> m_sceneCoreModule;
  184. AZStd::unique_ptr<AZ::DynamicModuleHandle> m_sceneDataModule;
  185. };
  186. TEST_F(SceneBuilderPhasesFixture, TestProcessingPhases)
  187. {
  188. auto scene = AZStd::make_shared<AZ::SceneAPI::Containers::Scene>("testScene");
  189. scene->GetManifest().AddEntry(AZStd::make_shared<AZ::SceneAPI::DataTypes::MockIGroup>());
  190. scene->SetManifestFilename("testScene.manifest");
  191. TestSceneSerializationHandler sceneLoadingHandler;
  192. EXPECT_CALL(sceneLoadingHandler, LoadScene(testing::_, testing::_, testing::_))
  193. .WillOnce(testing::DoAll(
  194. testing::Invoke(&sceneLoadingHandler, &TestSceneSerializationHandler::GenerateImportEvents),
  195. testing::Return(scene)
  196. ));
  197. auto* loadingComponent = aznew TestLoadingComponent();
  198. auto* generationComponent = aznew TestGenerationComponent();
  199. auto* exportingComponent = aznew TestExportingComponent();
  200. static_cast<ComponentSingleton<TestLoadingComponent>*>(TestLoadingComponent::CreateDescriptor())->SetComponent(loadingComponent);
  201. static_cast<ComponentSingleton<TestGenerationComponent>*>(TestGenerationComponent::CreateDescriptor())->SetComponent(generationComponent);
  202. static_cast<ComponentSingleton<TestExportingComponent>*>(TestExportingComponent::CreateDescriptor())->SetComponent(exportingComponent);
  203. {
  204. // Set up the order in which the event handlers should be called
  205. ::testing::InSequence sequence;
  206. using ::testing::_;
  207. EXPECT_CALL(*loadingComponent, Load(_))
  208. .WillOnce(testing::Return(AZ::SceneAPI::Events::ProcessingResult::Success));
  209. EXPECT_CALL(*generationComponent, Generate(_))
  210. .WillOnce(testing::Return(AZ::SceneAPI::Events::ProcessingResult::Success));
  211. EXPECT_CALL(*exportingComponent, Export(_))
  212. .WillOnce(testing::Return(AZ::SceneAPI::Events::ProcessingResult::Success));
  213. }
  214. SceneBuilder::SceneBuilderWorker worker;
  215. AssetBuilderSDK::ProcessJobResponse response;
  216. worker.ProcessJob({}, response);
  217. // The assertions set up before with the EXPECT_CALL calls are evaluated
  218. // when the mock objects go out of scope
  219. }