3
0

SceneBuilderPhasesTests.cpp 11 KB

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