/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
Code/UnitTests/EditorTest/TestClass/TestClass.cpp
454 строки
13 KB
C-Core
Array usage cleanup (#1864)
11 мар 2026, 23:44
Не верифицирован
11 мар 2026, 23:44
f7cb730
Код
Авторство
О чём код?
#include <EditorTest/EditorTestPCH.h> #include "TestClass.h" #include <EditorFramework/Assets/AssetCurator.h> #include <EditorFramework/DocumentWindow/EngineViewWidget.moc.h> #include <EditorFramework/DragDrop/DragDropHandler.h> #include <EditorFramework/DragDrop/DragDropInfo.h> #include <EditorPluginScene/Panels/LayerPanel/LayerAdapter.moc.h> #include <EditorPluginScene/Scene/Scene2Document.h> #include <Foundation/IO/OSFile.h> #include <Foundation/Profiling/Profiling.h> #include <Foundation/Profiling/ProfilingUtils.h> #include <GameEngine/GameApplication/GameApplication.h> #include <GuiFoundation/Action/ActionManager.h> #include <QMimeData> #include <RendererFoundation/Device/Device.h> #include <RendererFoundation/Device/DeviceFactory.h> #include <Texture/Image/ImageUtils.h> #include <ToolsFoundation/Application/ApplicationServices.h> ezEditorTestApplication::ezEditorTestApplication(ezStringView sTestName) : ezApplication("ezEditor") { EnableMemoryLeakReporting(true); m_pEditorApp = new ezQtEditorApp; m_sTestName = sTestName; } ezResult ezEditorTestApplication::BeforeCoreSystemsStartup() { if (SUPER::BeforeCoreSystemsStartup().Failed()) return EZ_FAILURE; ezStartup::AddApplicationTag("tool"); ezStartup::AddApplicationTag("editor"); ezStartup::AddApplicationTag("editorapp"); ezQtEditorApp::GetSingleton()->InitQt(GetArgumentCount(), (char**)GetArgumentsArray()); return EZ_SUCCESS; } void ezEditorTestApplication::AfterCoreSystemsShutdown() { ezQtEditorApp::GetSingleton()->DeInitQt(); delete m_pEditorApp; m_pEditorApp = nullptr; } void ezEditorTestApplication::Run() { qApp->processEvents(); } void ezEditorTestApplication::AfterCoreSystemsStartup() { EZ_PROFILE_SCOPE("AfterCoreSystemsStartup"); // We override the user data dir to not pollute the editor settings. ezStringBuilder userDataDir = ezTestFramework::GetInstance()->GetAbsOutputPath(); userDataDir.AppendPath(m_sTestName); userDataDir.MakeCleanPath(); ezQtEditorApp::GetSingleton()->StartupEditor(ezQtEditorApp::StartupFlags::SafeMode | ezQtEditorApp::StartupFlags::NoRecent | ezQtEditorApp::StartupFlags::UnitTest, userDataDir); // Disable msg boxes. ezQtUiServices::SetHeadless(true); ezFileSystem::SetSpecialDirectory("testout", ezTestFramework::GetInstance()->GetAbsOutputPath()); ezFileSystem::AddDataDirectory(">eztest/", "ImageComparisonDataDir", "imgout", ezDataDirUsage::AllowWrites).IgnoreResult(); // To read reference images ezStringBuilder sReadDir(">sdk/", ezTestFramework::GetInstance()->GetRelTestDataPath()); ezFileSystem::AddDataDirectory(sReadDir, "ImageComparisonDataDir").IgnoreResult(); } void ezEditorTestApplication::BeforeHighLevelSystemsShutdown() { EZ_PROFILE_SCOPE("BeforeHighLevelSystemsShutdown"); ezQtEditorApp::GetSingleton()->ShutdownEditor(); } ////////////////////////////////////////////////////////////////////////// ezEditorTest::ezEditorTest() { ezQtEngineViewWidget::s_FixedResolution = ezSizeU32(512, 512); } ezEditorTest::~ezEditorTest() = default; ezEditorTestApplication* ezEditorTest::CreateApplication() { ezEditorTestApplication* pTestApplication = EZ_DEFAULT_NEW(ezEditorTestApplication, GetTestName()); m_CommandLineArguments = ezCommandLineUtils::GetGlobalInstance()->GetCommandLineArray(); EZ_ASSERT_DEV(m_CommandLineArguments.GetCount() > 0, "There should always be at least 1 command line argument (the executable name)"); m_CommandLineArgumentPointers.Clear(); for (auto& s : m_CommandLineArguments) { m_CommandLineArgumentPointers.PushBack(s.GetData()); } pTestApplication->SetCommandLineArguments(m_CommandLineArgumentPointers.GetCount(), m_CommandLineArgumentPointers.GetData()); return pTestApplication; } ezResult ezEditorTest::GetImage(ezImage& ref_img, const ezSubTestEntry& subTest, ezUInt32 uiImageNumber) { if (!m_CapturedImage.IsValid()) return EZ_FAILURE; if (m_CapturedImage.GetWidth() == 512 && m_CapturedImage.GetHeight() == 512) { ref_img.ResetAndMove(std::move(m_CapturedImage)); } else { // Due to DPI scaling, we can't guarantee that the swapchain is exactly 512x512. The viewport still is though, so as long as we have something bigger the resulting image is correct if we crop off the remaining pixels. ezImageUtils::CropImage(m_CapturedImage, {0, 0}, {512, 512}, ref_img); m_CapturedImage.Clear(); } return EZ_SUCCESS; } ezResult ezEditorTest::InitializeTest() { m_pApplication = CreateApplication(); m_sProjectPath.Clear(); if (m_pApplication == nullptr) return EZ_FAILURE; EZ_SUCCEED_OR_RETURN(ezRun_Startup(m_pApplication)); static bool s_bCheckedAdapter = false; static ezString s_sAdapterName; if (!s_bCheckedAdapter) { s_bCheckedAdapter = true; #if EZ_ENABLED(EZ_PLATFORM_WINDOWS) ezUniquePtr<ezGALDevice> pDevice; ezGALDeviceCreationDescription DeviceInit; pDevice = ezGALDeviceFactory::CreateDevice(ezGameApplication::GetActiveRenderer(), ezFoundation::GetDefaultAllocator(), DeviceInit); EZ_SUCCEED_OR_RETURN(pDevice->Init()); s_sAdapterName = pDevice->GetCapabilities().m_sAdapterName; EZ_SUCCEED_OR_RETURN(pDevice->Shutdown()); pDevice.Clear(); #endif } ezTestFramework::GetInstance()->SetImageReferenceTagsFromEnvironment(EZ_PLATFORM_NAME, ezGameApplication::GetActiveRenderer(), s_sAdapterName); m_UIServicesTickEventHandlerID = ezQtUiServices::s_TickEvent.AddEventHandler(ezMakeDelegate(&ezEditorTest::UIServicesTickEventHandler, this)); return EZ_SUCCESS; } ezResult ezEditorTest::DeInitializeTest() { ezQtUiServices::s_TickEvent.RemoveEventHandler(m_UIServicesTickEventHandlerID); CloseCurrentProject(); if (m_pApplication) { ezRun_Shutdown(m_pApplication); EZ_DEFAULT_DELETE(m_pApplication); } return EZ_SUCCESS; } ezResult ezEditorTest::CreateAndLoadProject(const char* name) { EZ_PROFILE_SCOPE("CreateAndLoadProject"); ezStringBuilder relPath; relPath = ":APPDATA"; relPath.AppendPath(name); ezStringBuilder absPath; if (ezFileSystem::ResolvePath(relPath, &absPath, nullptr).Failed()) { ezLog::Error("Failed to resolve project path '{0}'.", relPath); return EZ_FAILURE; } if (ezOSFile::DeleteFolder(absPath).Failed()) { ezLog::Error("Failed to delete old project folder '{0}'.", absPath); return EZ_FAILURE; } ezStringBuilder projectFile = absPath; projectFile.AppendPath("ezProject"); if (m_pApplication->m_pEditorApp->CreateOrOpenProject(true, projectFile).Failed()) { ezLog::Error("Failed to create project '{0}'.", projectFile); return EZ_FAILURE; } m_sProjectPath = absPath; return EZ_SUCCESS; } ezResult ezEditorTest::OpenProject(const char* path) { EZ_PROFILE_SCOPE("OpenProject"); ezStringBuilder relPath; relPath = ">sdk"; relPath.AppendPath(path); ezStringBuilder absPath; if (ezFileSystem::ResolveSpecialDirectory(relPath, absPath).Failed()) { ezLog::Error("Failed to resolve project path '{0}'.", relPath); return EZ_FAILURE; } // Copy project to temp folder ezStringBuilder projectName = ezPathUtils::GetFileName(path); ezStringBuilder relTempPath; relTempPath = ":APPDATA"; relTempPath.AppendPath(projectName); ezStringBuilder absTempPath; if (ezFileSystem::ResolvePath(relTempPath, &absTempPath, nullptr).Failed()) { ezLog::Error("Failed to resolve project temp path '{0}'.", relPath); return EZ_FAILURE; } if (ezOSFile::DeleteFolder(absTempPath).Failed()) { ezLog::Error("Failed to delete old project temp folder '{0}'.", absTempPath); return EZ_FAILURE; } if (ezOSFile::CopyFolder(absPath, absTempPath).Failed()) { ezLog::Error("Failed to copy project '{0}' to temp location: '{1}'.", absPath, absTempPath); return EZ_FAILURE; } ezStringBuilder projectFile = absTempPath; projectFile.AppendPath("ezProject"); if (m_pApplication->m_pEditorApp->CreateOrOpenProject(false, projectFile).Failed()) { ezLog::Error("Failed to open project '{0}'.", projectFile); return EZ_FAILURE; } m_sProjectPath = absTempPath; return EZ_SUCCESS; } ezDocument* ezEditorTest::OpenDocument(const char* subpath) { ezStringBuilder fullpath; fullpath = m_sProjectPath; fullpath.AppendPath(subpath); ezDocument* pDoc = m_pApplication->m_pEditorApp->OpenDocument(fullpath, ezDocumentFlags::RequestWindow); if (pDoc) { ProcessEvents(); } return pDoc; } void ezEditorTest::ExecuteDocumentAction(const char* szActionName, ezDocument* pDocument, const ezVariant& argument /*= ezVariant()*/) { EZ_TEST_BOOL(ezActionManager::ExecuteAction(nullptr, szActionName, pDocument, argument).Succeeded()); } ezResult ezEditorTest::CaptureImage(ezQtDocumentWindow* pWindow, const char* szImageName) { ezStringBuilder sImgPath = ezOSFile::GetUserDataFolder("EditorTests"); sImgPath.AppendFormat("/{}.tga", szImageName); ezOSFile::DeleteFile(sImgPath).IgnoreResult(); pWindow->CreateImageCapture(sImgPath); for (int i = 0; i < 10; ++i) { ProcessEvents(); if (ezOSFile::ExistsFile(sImgPath)) break; ezThreadUtils::Sleep(ezTime::MakeFromMilliseconds(100)); } if (!ezOSFile::ExistsFile(sImgPath)) return EZ_FAILURE; EZ_SUCCEED_OR_RETURN(m_CapturedImage.LoadFrom(sImgPath)); return EZ_SUCCESS; } void ezEditorTest::CloseCurrentProject() { EZ_PROFILE_SCOPE("CloseCurrentProject"); m_sProjectPath.Clear(); m_pApplication->m_pEditorApp->CloseProject(); } void ezEditorTest::SafeProfilingData() { ezProfilingUtils::SaveProfilingCapture(":appdata/profiling.json").IgnoreResult(); } void ezEditorTest::ProcessEvents(ezUInt32 uiIterations) { EZ_PROFILE_SCOPE("ProcessEvents"); if (qApp) { for (ezUInt32 i = 0; i < uiIterations; i++) { qApp->processEvents(); } } } void ezEditorTest::WaitFrames(ezUInt32 uiFrames) { EZ_PROFILE_SCOPE("WaitFrames"); // Add one because we could have started waiting between start and end frame. uiFrames++; ezUInt32 uiCurrentFrame = m_uiRenderedFrames; if (qApp) { while ((m_uiRenderedFrames - uiCurrentFrame) < uiFrames) { qApp->processEvents(); } } } void ezEditorTest::UIServicesTickEventHandler(const ezQtUiServices::TickEvent& e) { if (e.m_Type == ezQtUiServices::TickEvent::Type::EndFrame) { m_uiRenderedFrames++; } } std::unique_ptr<QMimeData> ezEditorTest::AssetsToDragMimeData(ezArrayPtr<ezUuid> assetGuids) { std::unique_ptr<QMimeData> mimeData(new QMimeData()); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QString sGuids; QList<QUrl> urls; ezStringBuilder tmp; stream << (int)1; for (ezUInt32 i = 0; i < assetGuids.GetCount(); ++i) { QString sGuid(ezConversionUtils::ToString(assetGuids[i], tmp).GetData()); stream << sGuid; } mimeData->setData("application/ezEditor.AssetGuid", encodedData); return std::move(mimeData); } std::unique_ptr<QMimeData> ezEditorTest::ObjectsDragMimeData(const ezDeque<const ezDocumentObject*>& objects) { ezTempHybridArray<const ezDocumentObject*, 32> Dragged; for (const ezDocumentObject* pObject : objects) { Dragged.PushBack(pObject); } QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); stream << Dragged; std::unique_ptr<QMimeData> mimeData(new QMimeData()); mimeData->setData("application/ezEditor.ObjectSelection", encodedData); return std::move(mimeData); } void ezEditorTest::MoveObjectsToLayer(ezScene2Document* pDoc, const ezDeque<const ezDocumentObject*>& objects, const ezUuid& layer, ezDeque<const ezDocumentObject*>& new_objects) { pDoc->GetSelectionManager()->SetSelection(objects); ezQtLayerAdapter adapter(pDoc); auto mimeData = ObjectsDragMimeData(objects); ezDragDropInfo info; info.m_iTargetObjectInsertChildIndex = -1; info.m_pMimeData = mimeData.get(); info.m_sTargetContext = "layertree"; info.m_TargetDocument = pDoc->GetGuid(); info.m_TargetObject = pDoc->GetLayerObject(layer)->GetGuid(); info.m_bCtrlKeyDown = false; info.m_bShiftKeyDown = false; info.m_pAdapter = &adapter; if (!EZ_TEST_BOOL(ezDragDropHandler::DropOnly(&info))) return; new_objects = pDoc->GetLayerDocument(layer)->GetSelectionManager()->GetSelection(); } const ezDocumentObject* ezEditorTest::DropAsset(ezScene2Document* pDoc, const char* szAssetGuidOrPath, bool bShift /*= false*/, bool bCtrl /*= false*/) { const ezAssetCurator::ezLockedSubAsset asset = ezAssetCurator::GetSingleton()->FindSubAsset(szAssetGuidOrPath); if (EZ_TEST_BOOL(asset.isValid())) { ezUuid assetGuid = asset->m_Data.m_Guid; ezArrayPtr<ezUuid> assets(&assetGuid, 1); auto mimeData = AssetsToDragMimeData(assets); ezDragDropInfo info; info.m_pMimeData = mimeData.get(); info.m_TargetDocument = pDoc->GetGuid(); info.m_sTargetContext = "viewport"; info.m_iTargetObjectInsertChildIndex = -1; info.m_iTargetObjectSubID = 0; info.m_bShiftKeyDown = bShift; info.m_bCtrlKeyDown = bCtrl; if (EZ_TEST_BOOL(ezDragDropHandler::DropOnly(&info))) { return pDoc->GetSelectionManager()->GetCurrentObject(); } } return {}; } const ezDocumentObject* ezEditorTest::CreateGameObject(ezScene2Document* pDoc, const ezDocumentObject* pParent, ezStringView sName) { auto pAccessor = pDoc->GetObjectAccessor(); pAccessor->StartTransaction("Add Game Object"); ezUuid guid; EZ_TEST_STATUS(pAccessor->AddObjectByName(pParent != nullptr ? pParent : pDoc->GetObjectManager()->GetRootObject(), "Children", -1, ezRTTI::FindTypeByName("ezGameObject"), guid)); const ezDocumentObject* pObject = pAccessor->GetObject(guid); EZ_TEST_STATUS(pAccessor->SetValueByName(pObject, "Name", sName)); pAccessor->FinishTransaction(); return pObject; }