You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp

703 lines
30 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <gtest/gtest.h>
#include <QPushButton>
#include <QAction>
#include <QtTest>
#include <QMessageBox>
#include <QMenu>
#include <QApplication>
#include <QGridLayout>
#include <QDir>
#include <QCheckBox>
#include <Tests/UI/MenuUIFixture.h>
#include <Tests/UI/ModalPopupHandler.h>
#include <EMotionFX/Exporters/ExporterLib/Exporter/Exporter.h>
#include <Tests/TestAssetCode/SimpleActors.h>
#include <Tests/TestAssetCode/ActorFactory.h>
#include <Editor/Plugins/SimulatedObject/SimulatedObjectWidget.h>
#include <Editor/Plugins/SkeletonOutliner/SkeletonOutlinerPlugin.h>
#include <EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.h>
#include <EMotionFX/Source/AnimGraphReferenceNode.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/CommandSystem/Source/AnimGraphNodeCommands.h>
#include <EMotionFX/CommandSystem/Source/MotionCommands.h>
#include <EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphModel.h>
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
#include <EMotionStudio/EMStudioSDK/Source/MainWindow.h>
#include <EMotionStudio/EMStudioSDK/Source/SaveChangedFilesManager.h>
#include <EMotionStudio/EMStudioSDK/Source/ResetSettingsDialog.h>
#include <EMotionStudio/EMStudioSDK/Source/FileManager.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h>
#include <EMotionStudio/Plugins/StandardPlugins/Source/MotionSetsWindow/MotionSetsWindowPlugin.h>
namespace EMotionFX
{
class CanUseFileMenuUIFixture
: public MenuUIFixture
{
public:
void SetUp() override
{
MenuUIFixture::SetUp();
GetEMotionFX().InitAssetFolderPaths();
m_animGraphPlugin = static_cast<EMStudio::AnimGraphPlugin*>(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::AnimGraphPlugin::CLASS_ID));
ASSERT_TRUE(m_animGraphPlugin);
EMStudio::GetManager()->SetSkipSourceControlCommands(true);
}
void TearDown() override
{
QDir(GetAssetSaveFolder()).removeRecursively();
MenuUIFixture::TearDown();
}
QString GetAssetSaveFolder() const
{
auto testAssetsPath = AZ::IO::Path(GetEMotionFX().GetAssetCacheFolder()) / "TmpTestAssets";
QString dataDir = QString::fromUtf8(testAssetsPath.c_str(), aznumeric_cast<int>(testAssetsPath.Native().size()));
if (!QDir(dataDir).exists())
{
QDir().mkdir(dataDir);
}
return dataDir;
}
QString GenerateTempAssetFile(const QString& filenamebase, const QString& extension) const
{
bool foundFilename = false;
int fileIndex = 0;
QString baseDir = GetAssetSaveFolder();
while (!foundFilename)
{
const QString filename = QString("%1_%2").arg(filenamebase).arg(fileIndex);
const QString filepath = QString("%1/%2.%3").arg(baseDir, filename, extension);
if (!QFile::exists(filepath))
{
return filepath;
}
fileIndex++;
}
return nullptr;
}
QString GenerateTempAnimGraphFilename() const
{
return GenerateTempAssetFile("tmpanimgraph", "animgraph");
}
QString GenerateTempWorkspaceFilename() const
{
return GenerateTempAssetFile("tmpworkspace", "emfxworkspace");
}
QString GenerateTempActorFilename() const
{
return GenerateTempAssetFile("tmpactor", "actor");
}
QString GenerateTempMotionSetFilename() const
{
return GenerateTempAssetFile("tmpmotionset", "motionset");
}
QString GenerateTempMotionFilename() const
{
return GenerateTempAssetFile("tmpmotion", "motion");
}
void CreateAnimGraph()
{
if (!AnimGraphExists())
{
m_animGraphPlugin->GetViewWidget()->OnCreateAnimGraph();
ASSERT_TRUE(m_animGraphPlugin->GetActiveAnimGraph()) << "Failed to create AnimGraph.";
}
}
void CreateActor()
{
if (EMotionFX::GetActorManager().GetNumActorInstances() == 0)
{
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance::Create(actor.get());
EXPECT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to create actor set for reset test.";
}
}
void CreateAndSaveActor(const char* filename) const
{
if (EMotionFX::GetActorManager().GetNumActorInstances() == 0)
{
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(2, "CanAddSimulatedObjectWithJointsActor");
ActorInstance::Create(actor.get());
EXPECT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to create actor set for reset test.";
actor->SetFileName(filename);
AZStd::string stringFilename = filename;
ExporterLib::SaveActor(stringFilename, actor.get(), MCore::Endian::ENDIAN_LITTLE);
}
}
void LoadActor(const char* filename, const bool replaceScene)
{
ModalPopupHandler saveDirtyPopupHandler;
saveDirtyPopupHandler.WaitForPopupPressDialogButton<EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Ok);
EMStudio::GetMainWindow()->LoadActor(filename, replaceScene);
}
void CreateMotionSet()
{
if (EMotionFX::GetMotionManager().GetNumMotionSets() == 0)
{
EMStudio::MotionSetManagementWindow* managementWindow = GetMotionSetManagementWindow();
ASSERT_TRUE(managementWindow);
managementWindow->OnCreateMotionSet();
ASSERT_EQ(EMotionFX::GetMotionManager().GetNumMotionSets(), 1) << "Failed to create motion set for reset test.";
}
}
void CreateMotion()
{
if (EMotionFX::GetMotionManager().GetNumMotions() == 0)
{
LoadTestMotion();
ASSERT_EQ(EMotionFX::GetMotionManager().GetNumMotions(), 1) << "Failed to create motion for reset test.";
}
}
void DeleteAnimGraph()
{
EMotionFX::AnimGraph* animGraph = m_animGraphPlugin->GetActiveAnimGraph();
GetEventManager().OnDeleteAnimGraph(animGraph);
}
bool AnimGraphExists() const
{
EMotionFX::AnimGraph* animGraph = m_animGraphPlugin->GetActiveAnimGraph();
return animGraph;
}
void SaveCurrentAnimGraph(const QString& filename)
{
// Set the save filename to avoid a file select dialog.
EMotionFX::AnimGraph* animGraph = m_animGraphPlugin->GetActiveAnimGraph();
animGraph->SetFileName(filename.toUtf8().constData());
m_animGraphPlugin->OnFileSave();
ASSERT_TRUE(QFile::exists(filename)) << "Failed to save AnimGraph.";
}
void TestActorMenus(QMenu* fileMenu)
{
// Open Actor
// We can't use the Open Actor menu item as it would involve interacting with a system requestor, so just do what the menu option does internally.
//Clear any existing actors before we start.
QAction* resetAction = GetResetMenuAction(fileMenu);
ASSERT_TRUE(resetAction) << "Reset menu item not found";
TestResetMenuItem(resetAction, "EMFX.ResetSettingsDialog.Actors");
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 0) << "Failed to reset Actors.";
// Create an actor and save it so we can reload it for the merge step.
const QString actorFilename = GenerateTempActorFilename();
CreateAndSaveActor(actorFilename.toUtf8().data());
// Clear out the existing actors so we can tell whether the load works.
TestResetMenuItem(resetAction, "EMFX.ResetSettingsDialog.Actors");
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 0) << "Failed to reset Actors.";
// Load the actor we just saved, with replaceScene set to true to represent a load.
LoadActor(actorFilename.toUtf8().data(), true);
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to load Actor.";
// Do it again to verify that number of actors stays the same when replaceScene is true.
LoadActor(actorFilename.toUtf8().data(), true);
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to load Actor.";
// Now load again, but with replaceScene set to false, as the merge code does.
LoadActor(actorFilename.toUtf8().data(), false);
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 2) << "Failed to merge Actor.";
// We can't test Save Selected Actor as we would it would involve mocking source scene handling.
// Add the filename to the recent actorsa anyway, so we can test that functionality.
EMStudio::GetMainWindow()->AddRecentActorFile(actorFilename);
// Check for the file saved in the Save test to be listed in the recent actors submenu.
const QList <QMenu*> recentMenus = fileMenu->findChildren<QMenu*>("EMFX.MainWindow.RecentFilesMenu");
QMenu* recentActorsMenu = nullptr;
for (QMenu* recentMenu : recentMenus)
{
if (recentMenu->title() == "Recent Actors")
{
recentActorsMenu = recentMenu;
}
}
ASSERT_TRUE(recentActorsMenu) << "Unable to find recent actors menu.";
const QList<QAction*> actions = recentActorsMenu->findChildren<QAction *>();
QAction* recentAction = nullptr;
for (QAction* action : actions)
{
if (IsActionRecentlySavedActor(action->text(), actorFilename))
{
recentAction = action;
}
}
ASSERT_TRUE(recentAction) << "Recent action for last saved actor not found.";
recentAction->trigger();
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to load recent Actor.";
QAction* resetRecentAction = recentActorsMenu->findChild<QAction *>("EMFX.RecentFiles.ResetRecentFilesAction");
ASSERT_TRUE(resetRecentAction) << "Reset recent actors action not found.";
resetRecentAction->trigger();
const QList<QAction*> actionsAfterReset = recentActorsMenu->findChildren<QAction *>();
ASSERT_EQ(actionsAfterReset.size(), 1) << "Failed to reset recent items menu.";
}
bool IsActionRecentlySavedActor(const QString& actionTitle, const QString& actorFilename) const
{
if (actionTitle.isEmpty())
{
return false;
}
QFileInfo fileInfo(actionTitle);
QString fileName = fileInfo.fileName();
// Remove the shortcut at the start.
const int shortcutLen = fileName.indexOf(" ");
fileName = fileName.mid(shortcutLen + 1);
return actorFilename.endsWith(fileName);
}
void TestSaveWorkspaceMenuOption([[maybe_unused]] QMenu* fileMenu, const QString& workspaceFilename)
{
EMStudio::Workspace* workspace = EMStudio::GetManager()->GetWorkspace();
ASSERT_TRUE(workspace) << "Current workspace not found";
// Create an anim graph so that there is unsaved data
CreateAnimGraph();
// The workspace needs to have a file to save to, as we can't interact with the SaveAs dialog.
workspace->SetFilename(workspaceFilename.toUtf8().constData());
// If we try to save now, we'll be asked to select a save file for the anim graph, we need to provide one to avoid that.
const QString animGraphFilename = GenerateTempAnimGraphFilename();
SaveCurrentAnimGraph(animGraphFilename);
// Prepare a watcher to press the ok button when the SaveDirtySettingsWindow appears.
ModalPopupHandler saveDirtyPopupHandler;
saveDirtyPopupHandler.WaitForPopupPressDialogButton<EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Ok);
EMStudio::GetMainWindow()->OnFileSaveWorkspace();
ASSERT_TRUE(saveDirtyPopupHandler.GetSeenTargetWidget()) << "Expected SaveDirtySettingsWindow not found.";
ASSERT_TRUE(QFile::exists(workspaceFilename)) << "Workspace save failed.";
}
bool IsActionRecentlySavedWorkspace(const QString& actionTitle) const
{
if (actionTitle.isEmpty())
{
return false;
}
QFileInfo fileInfo(actionTitle);
QString fileName = fileInfo.fileName();
// Remove the shortcut at the start.
const int shortcutLen = fileName.indexOf(" ");
fileName = fileName.mid(shortcutLen + 1);
return m_lastSavedWorkspaceFilename.endsWith(fileName);
}
void TestNewWorkspaceMenuOption(QMenu* fileMenu)
{
// Create an anim graph so that there is unsaved data
CreateAnimGraph();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Test 1. Select New Workspace, press cancel in the SaveDirtySettingsWindow.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Start waiting for the "do you want to save" dialog, then press Cancel.
ModalPopupHandler saveDirtyPopupHandler;
saveDirtyPopupHandler.WaitForPopupPressDialogButton< EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Cancel);
// Trigger the new workspace menu option
QAction* newWorkspaceAction = MenuUIFixture::FindMenuActionWithObjectName(fileMenu, "EMFX.MainWindow.NewWorkspaceAction", "EMFX.MainWindow.FileMenu");
ASSERT_TRUE(newWorkspaceAction);
newWorkspaceAction->trigger();
// If the dialog does not appear, we might get here before the callback is triggered, so check that it was.
ASSERT_TRUE(saveDirtyPopupHandler.GetSeenTargetWidget()) << "Expected SaveDirtySettingsWindow not found.";
// The dialog should now be gone but the anim graph we made should still exist.
ASSERT_FALSE(QApplication::activeModalWidget()) << "SaveDirtySettingsWindow failed to close.";
ASSERT_TRUE(AnimGraphExists()) << "AnimGraph not found.";
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Test 2. Select New Workspace, press Discard in the SaveDirtySettingsWindow.
// Then press No in the new workspace confirmation dialog.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Start waiting for the "do you want to save" dialog, then press Discard.
saveDirtyPopupHandler.WaitForPopupPressDialogButton< EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Discard);
// Start waiting for the "really make new workspace?" confirmation popup, then press No.
ModalPopupHandler messageBoxPopupHandler;
messageBoxPopupHandler.WaitForPopupPressDialogButton<QMessageBox*>(QDialogButtonBox::No);
newWorkspaceAction->trigger();
saveDirtyPopupHandler.WaitForCompletion();
messageBoxPopupHandler.WaitForCompletion();
// If the dialog does not appear, we might get here before the callback is triggered, so check that it was.
ASSERT_TRUE(saveDirtyPopupHandler.GetSeenTargetWidget()) << "Expected SaveDirtySettingsWindow not found.";
ASSERT_TRUE(messageBoxPopupHandler.GetSeenTargetWidget()) << "Expected QMessageBox not found.";
// The dialog should now be gone and the anim graph we made should still be there.
ASSERT_FALSE(QApplication::activeModalWidget()) << "SaveDirtySettingsWindow failed to close.";
ASSERT_TRUE(AnimGraphExists()) << "AnimGraph not found.";
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Test 3. Select New Workspace, press discard in the SaveDirtySettingsWindow.
// Then press Yes in the new workspace confirmation dialog.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Start waiting for the "do you want to save" dialog, then press Discard.
saveDirtyPopupHandler.WaitForPopupPressDialogButton< EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Discard);
// Start waiting for the "really make new workspace?" confirmation popup, then press Yes.
messageBoxPopupHandler.WaitForPopupPressDialogButton<QMessageBox*>(QDialogButtonBox::Yes);
newWorkspaceAction->trigger();
// If the dialog does not appear, we might get here before the callback is triggered, so check that it did.
ASSERT_TRUE(saveDirtyPopupHandler.GetSeenTargetWidget()) << "Expected SaveDirtySettingsWindow not found.";
ASSERT_TRUE(messageBoxPopupHandler.GetSeenTargetWidget()) << "Expected QMessageBox not found.";
// There should be no active popup.
ASSERT_FALSE(QApplication::activeModalWidget()) << "SaveDirtySettingsWindow failed to close.";
// The AnimGraph should be removed.
ASSERT_FALSE(AnimGraphExists()) << "AnimGraph not removed.";
}
void TestRecentWorkspacesMenuOption(QMenu* fileMenu)
{
// Remove the AnimGraph so that we can tell the workspace has been reloaded correctly.
DeleteAnimGraph();
ASSERT_FALSE(AnimGraphExists()) << "AnimGraph not removed.";
// Check for the file saved in the Save test to be listed.
const QList <QMenu*> recentMenus = fileMenu->findChildren<QMenu*>("EMFX.MainWindow.RecentFilesMenu");
QMenu* recentWorkspacesMenu = nullptr;
for (QMenu* recentMenu : recentMenus)
{
if (recentMenu->title() == "Recent Workspaces")
{
recentWorkspacesMenu = recentMenu;
}
}
ASSERT_TRUE(recentWorkspacesMenu) << "Unable to find recent workspaces menu.";
const QList<QAction*> actions = recentWorkspacesMenu->findChildren<QAction *>();
QAction* recentAction = nullptr;
for (QAction* action : actions)
{
if (IsActionRecentlySavedWorkspace(action->text()))
{
recentAction = action;
}
}
ASSERT_TRUE(recentAction) << "Recent action for last saved workspace not found.";
// Now try to use the action to reload the workspace.
// As we've deleted the AnimGraph, we'll be asked about saving changes, discard them.
ModalPopupHandler saveDirtyPopupHandler;
saveDirtyPopupHandler.WaitForPopupPressDialogButton< EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Discard);
recentAction->trigger();
ASSERT_TRUE(AnimGraphExists()) << "AnimGraph not found after reloading recent workspace.";
// Test the clear recent items action.
QAction* resetRecentAction = recentWorkspacesMenu->findChild<QAction *>("EMFX.RecentFiles.ResetRecentFilesAction");
ASSERT_TRUE(resetRecentAction) << "Reset recent workspaces action not found.";
resetRecentAction->trigger();
const QList<QAction*> actionsAfterReset = recentWorkspacesMenu->findChildren<QAction *>();
ASSERT_EQ(actionsAfterReset.size(), 1) << "Failed to reset workspaces items menu.";
}
void CreateDataForResetTest()
{
CreateActor();
CreateMotionSet();
CreateMotion();
CreateAnimGraph();
}
void TestResetMenuItem(QAction* resetMenuAction, const QString& resetItemName)
{
// Set up a callback to set the correct checkbox states when the ResetSettings dialog appears.
WidgetActiveCallback resetSettingsCallback = [resetItemName](QWidget* widget)
{
ASSERT_TRUE(widget) << "Failed to find Reset widget.";
if (resetItemName == "*")
{
// Set all checkboxes
QList<QCheckBox*>checkBoxes = widget->findChildren<QCheckBox*>();
for (QCheckBox *checkBox : checkBoxes)
{
checkBox->setChecked(true);
}
}
else
{
// Reset all checkboxes
QList<QCheckBox*>checkBoxes = widget->findChildren<QCheckBox*>();
for (QCheckBox *checkBox : checkBoxes)
{
QString on = checkBox->objectName();
checkBox->setChecked(false);
}
// Just tick the one we want
QCheckBox* checkBox = widget->findChild<QCheckBox*>(resetItemName);
ASSERT_TRUE(checkBox) << "Failed to find reset item checkbox ";
checkBox->setChecked(true);
}
// Press the Ok button
QDialogButtonBox* buttonBox = widget->findChild< QDialogButtonBox*>();
ASSERT_TRUE(buttonBox) << "Unable to find button box in ResetSettingsDialog";
QAbstractButton* button = buttonBox->button(QDialogButtonBox::Ok);
ASSERT_TRUE(button) << "Unable to find Ok button in ResetSettingsDialog";
QTest::mouseClick(button, Qt::LeftButton);
};
// Setup a watcher to handle the save dirty settings dialog by pressing Discard.
ModalPopupHandler saveDirtyPopupHandler;
saveDirtyPopupHandler.WaitForPopupPressDialogButton< EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Discard);
// Setup a handler to select the type to reset and press ok.
ModalPopupHandler resetSettingsHandler;
resetSettingsHandler.WaitForPopup<EMStudio::ResetSettingsDialog*>(resetSettingsCallback);
resetMenuAction->trigger();
saveDirtyPopupHandler.WaitForCompletion();
resetSettingsHandler.WaitForCompletion();
}
QString GetTestMotionFileName() const
{
AZStd::string resolvedAssetPath = this->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
return QString::fromUtf8(resolvedAssetPath.data(), aznumeric_cast<int>(resolvedAssetPath.size()));
}
void LoadTestMotion()
{
const QString testFile = GetTestMotionFileName();
ASSERT_TRUE(QFile::exists(testFile)) << "Failed to find motion file asset.";
AZStd::vector<AZStd::string> motionFilenames;
motionFilenames.push_back(testFile.toUtf8().data());
CommandSystem::LoadMotionsCommand(motionFilenames);
}
QAction* GetResetMenuAction(const QMenu* fileMenu) const
{
return MenuUIFixture::FindMenuActionWithObjectName(fileMenu, "EMFX.MainWindow.ResetAction", fileMenu->objectName());
}
void TestResetMenuItem(QMenu* fileMenu)
{
QAction* resetAction = GetResetMenuAction(fileMenu);
ASSERT_TRUE(resetAction) << "Reset menu item not found";
ASSERT_TRUE(resetAction->isEnabled()) << "Reset menu action is disabled.";
// Make one of everything to reset
CreateDataForResetTest();
// Reset them one at a time:
{
// Actors
TestResetMenuItem(resetAction, "EMFX.ResetSettingsDialog.Actors");
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 0) << "Failed to reset Actors.";
// Motions
TestResetMenuItem(resetAction, "EMFX.ResetSettingsDialog.Motions");
ASSERT_EQ(EMotionFX::GetMotionManager().GetNumMotions(), 0) << "Failed to reset Motions.";
// Motion Sets
TestResetMenuItem(resetAction, "EMFX.ResetSettingsDialog.MotionSets");
ASSERT_EQ(EMotionFX::GetMotionManager().GetNumMotionSets(), 0) << "Failed to reset MotionSets.";
// AnimGraphs
TestResetMenuItem(resetAction, "EMFX.ResetSettingsDialog.AnimGraphs");
ASSERT_FALSE(m_animGraphPlugin->GetActiveAnimGraph()) << "Failed to reset AnimGraphs.";
}
// The reset menu item should be disabled as there is nothing to reset.
ASSERT_FALSE(resetAction->isEnabled()) << "Reset menu action is enabled after resetting all items.";
// Recreate test data
CreateDataForResetTest();
// Reset them all at once
{
TestResetMenuItem(resetAction, "*");
ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 0) << "Failed to reset Actors.";
ASSERT_EQ(EMotionFX::GetMotionManager().GetNumMotions(), 0) << "Failed to reset Motions.";
ASSERT_EQ(EMotionFX::GetMotionManager().GetNumMotionSets(), 0) << "Failed to reset MotionSets.";
ASSERT_FALSE(m_animGraphPlugin->GetActiveAnimGraph()) << "Failed to reset AnimGraphs.";
}
}
void TestSaveAllMenuItem(QMenu* fileMenu)
{
// Use the test reset menu item to ensure everything is cleared out.
QAction* resetAction = GetResetMenuAction(fileMenu);
ASSERT_TRUE(resetAction) << "Reset menu item not found";
TestResetMenuItem(resetAction, "*");
// Make new sets of all data types, give them a unique filename and set them as dirty.
CreateAnimGraph();
const QString animGraphFilename = GenerateTempAnimGraphFilename();
EMotionFX::AnimGraph* animGraph = m_animGraphPlugin->GetActiveAnimGraph();
animGraph->SetFileName(animGraphFilename.toUtf8().constData());
animGraph->SetDirtyFlag(true);
CreateMotionSet();
const QString motionsetFilename = GenerateTempMotionSetFilename();
EMotionFX::MotionSet *motionSet = EMotionFX::GetMotionManager().GetMotionSet(0);
motionSet->SetFilename(motionsetFilename.toUtf8().constData());
motionSet->SetDirtyFlag(true);
// Don't create an actor or motion as we can't save that due to source scene requirements.
EMStudio::Workspace* workspace = EMStudio::GetManager()->GetWorkspace();
const QString workspaceFilename = GenerateTempWorkspaceFilename();
workspace->SetFilename(workspaceFilename.toUtf8().data());
workspace->SetDirtyFlag(true);
ModalPopupHandler saveDirtyPopupHandler;
saveDirtyPopupHandler.WaitForPopupPressDialogButton< EMStudio::SaveDirtySettingsWindow*>(QDialogButtonBox::Ok);
QAction* saveAllAction = MenuUIFixture::FindMenuActionWithObjectName(fileMenu, "EMFX.MainWindow.SaveAllAction", fileMenu->objectName());
ASSERT_TRUE(saveAllAction) << "Save All menu item not found";
ASSERT_TRUE(saveAllAction->isEnabled());
saveAllAction->trigger();
ASSERT_TRUE(QFile::exists(animGraphFilename)) << "Failed to save AnimGraph in SaveAll action.";
ASSERT_TRUE(QFile::exists(motionsetFilename)) << "Failed to save MotionSet in SaveAll action.";
ASSERT_TRUE(QFile::exists(workspaceFilename)) << "Failed to save Workspace in SaveAll action.";
}
void TestWorkspaceMenuItems(QMenu* fileMenu)
{
m_lastSavedWorkspaceFilename = GenerateTempWorkspaceFilename();
TestNewWorkspaceMenuOption(fileMenu);
// We can't test Open Workspace as it requires interacting with a system file dialog.
TestSaveWorkspaceMenuOption(fileMenu, m_lastSavedWorkspaceFilename);
// We can't test Save As as it requires interacting with a system file dialog.
TestRecentWorkspacesMenuOption(fileMenu);
}
private:
EMStudio::AnimGraphPlugin* m_animGraphPlugin = nullptr;
QString m_lastSavedWorkspaceFilename;
};
#if AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS
TEST_F(CanUseFileMenuUIFixture, DISABLED_CanUseFileMenu)
#else
TEST_F(CanUseFileMenuUIFixture, CanUseFileMenu)
#endif // AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS
{
RecordProperty("test_case_id", "C1698601");
RecordProperty("test_case_id", "C16302183");
RecordProperty("test_case_id", "C1698617");
// Find the File menu.
QMenu* fileMenu = MenuUIFixture::FindMainMenuWithName("EMFX.MainWindow.FileMenu");
ASSERT_TRUE(fileMenu) << "Unable to find file menu.";
TestWorkspaceMenuItems(fileMenu);
TestResetMenuItem(fileMenu);
TestActorMenus(fileMenu);
TestSaveAllMenuItem(fileMenu);
}
} // namespace EMotionFX