Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include "CoreMinimal.h" // Core Unreal Engine types and utilities
- #include "Misc/AutomationTest.h" // Automation test framework for Unreal Engine
- #include "Plugin.h" // Custom plugin-related classes (FPlugin, UPluginHelper, EGameID)
- #include "HAL/FileManager.h" // File management utilities (IFileManager)
- #include "Misc/Paths.h" // Path manipulation utilities (FPaths)
- #include "Misc/Parse.h" // Parsing utilities (used for FString::FromInt)
- // Enable automation tests only if WITH_DEV_AUTOMATION_TESTS is defined
- #if WITH_DEV_AUTOMATION_TESTS
- /*
- Macro to declare an automation test for a specific game, generating a test class with Unreal Engine's testing framework.
- Parameters:
- - GameIDEnum: Enum value from EGameID (e.g., Skyrim, Oblivion) to identify the game.
- - GameName: Name of the game as a string (e.g., Skyrim) used in test naming and paths.
- */
- #define DECLARE_PLUGIN_TEST(GameIDEnum, GameName) \
- IMPLEMENT_SIMPLE_AUTOMATION_TEST(FPluginTest_##GameName, "PluginTest." #GameName, EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter) \
- bool FPluginTest_##GameName::RunTest(const FString& Parameters) \
- { \
- /* Set the game identifier based on the provided enum (e.g., EGameID::Skyrim). */ \
- EGameID GameID = EGameID::GameIDEnum; \
- /* Convert the game name to a string for use in file paths and test messages. */ \
- FString GameNameStr = TEXT(#GameName); \
- /* Define a temporary directory for test files in Saved/Temp/PluginTest/[GameName]. */ \
- FString TempDir = FPaths::ProjectSavedDir() / TEXT("Temp") / TEXT("PluginTest") / GameNameStr; \
- /* Get the singleton file manager instance for file operations. */ \
- IFileManager& FileManager = IFileManager::Get(); \
- /* Create the temporary directory, including parent directories if needed. */ \
- FileManager.MakeDirectory(*TempDir, true); \
- \
- /* Source File Paths - Define the source directory for test files, located in Content/TestFiles/[GameName]. */ \
- FString SourceDir = FPaths::ProjectContentDir() / TEXT("TestFiles") / GameNameStr; \
- /* Path to the source Blank.esm file, a master plugin file. */ \
- FString BlankEsmSource = FPaths::Combine(SourceDir, TEXT("Blank.esm")); \
- /* Path to the source Blank - Master Dependent.esm, a master file dependent on Blank.esm. */ \
- FString BlankMasterDependentEsmSource = FPaths::Combine(SourceDir, TEXT("Blank - Master Dependent.esm")); \
- /* Path to the source Blank.esp file, a non-master plugin file. */ \
- FString BlankEspSource = FPaths::Combine(SourceDir, TEXT("Blank.esp")); \
- /* Path to the source Blank.bsa file, a Skyrim-specific archive file. */ \
- FString BlankBsaSource = FPaths::Combine(SourceDir, TEXT("Blank.bsa")); /* Skyrim only */ \
- \
- /* Temporary Test File Paths - Path to a missing plugin file for testing load failures. */ \
- FString MissingPluginPath = FPaths::Combine(TempDir, TEXT("Blank.missing.esm")); \
- /* Path to an empty file for testing invalid plugin loading. */ \
- FString EmptyFilePath = FPaths::Combine(TempDir, TEXT("EmptyFile.esm")); \
- /* Path to an invalid plugin file with non-plugin content. */ \
- FString InvalidPluginPath = FPaths::Combine(TempDir, TEXT("NotAPlugin.esm")); \
- /* Path to a plugin file with a non-ASCII name for testing Unicode support. */ \
- FString NonAsciiPluginPath = FPaths::Combine(TempDir, TEXT("Русский.esm")); \
- /* Path to the temporary copy of Blank.esm. */ \
- FString BlankEsmPath = FPaths::Combine(TempDir, TEXT("Blank.esm")); \
- /* Path to the temporary copy of Blank - Master Dependent.esm. */ \
- FString BlankMasterDependentEsmPath = FPaths::Combine(TempDir, TEXT("Blank - Master Dependent.esm")); \
- /* Path to the temporary copy of Blank.esp. */ \
- FString BlankEspPath = FPaths::Combine(TempDir, TEXT("Blank.esp")); \
- /* Path to the temporary copy of Blank.bsa (Skyrim only). */ \
- FString BlankBsaPath = FPaths::Combine(TempDir, TEXT("Blank.bsa")); /* Skyrim only */ \
- /* Path to a ghosted version of Blank.esm for testing ghost file handling. */ \
- FString GhostedBlankEsmPath = FPaths::Combine(TempDir, TEXT("Blank.esm.ghost")); \
- \
- /* Setup: Verify Source Files and Prepare Temporary Files - Verify that the source Blank.esm exists in the source directory. */ \
- TestTrue(FString::Printf(TEXT("Source Blank.esm exists for %s"), *GameNameStr), FileManager.FileExists(*BlankEsmSource)); \
- /* Verify that the source Blank - Master Dependent.esm exists. */ \
- TestTrue(FString::Printf(TEXT("Source Blank - Master Dependent.esm exists for %s"), *GameNameStr), FileManager.FileExists(*BlankMasterDependentEsmSource)); \
- /* Verify that the source Blank.esp exists. */ \
- TestTrue(FString::Printf(TEXT("Source Blank.esp exists for %s"), *GameNameStr), FileManager.FileExists(*BlankEspSource)); \
- /* For Skyrim, verify that the source Blank.bsa exists. */ \
- if (GameID == EGameID::Skyrim) \
- { \
- TestTrue(FString::Printf(TEXT("Source Blank.bsa exists for Skyrim")), FileManager.FileExists(*BlankBsaSource)); \
- } \
- /* Ensure the missing plugin file does not exist initially. */ \
- TestFalse(FString::Printf(TEXT("Missing plugin does not exist for %s"), *GameNameStr), FileManager.FileExists(*MissingPluginPath)); \
- \
- /* Copy source plugin files to the temporary directory for testing. */ \
- FileManager.Copy(*BlankEsmPath, *BlankEsmSource); \
- FileManager.Copy(*BlankMasterDependentEsmPath, *BlankMasterDependentEsmSource); \
- FileManager.Copy(*BlankEspPath, *BlankEspSource); \
- if (GameID == EGameID::Skyrim) \
- { \
- FileManager.Copy(*BlankBsaPath, *BlankBsaSource); \
- } \
- \
- /* Create an empty file to simulate an invalid plugin. */ \
- TUniquePtr<FArchive> EmptyFileArchive(FileManager.CreateFileWriter(*EmptyFilePath)); \
- EmptyFileArchive->Close(); \
- TestTrue(FString::Printf(TEXT("EmptyFile.esm created for %s"), *GameNameStr), FileManager.FileExists(*EmptyFilePath)); \
- \
- /* Create an invalid plugin file with dummy content for testing. */ \
- TUniquePtr<FArchive> InvalidPluginArchive(FileManager.CreateFileWriter(*InvalidPluginPath)); \
- FString InvalidContent = TEXT("This isn't a valid plugin file."); \
- InvalidPluginArchive->Serialize(TCHAR_TO_ANSI(*InvalidContent), InvalidContent.Len()); \
- InvalidPluginArchive->Close(); \
- TestTrue(FString::Printf(TEXT("NotAPlugin.esm created for %s"), *GameNameStr), FileManager.FileExists(*InvalidPluginPath)); \
- \
- /* Copy Blank.esm to a non-ASCII named file to test Unicode handling. */ \
- FileManager.Copy(*NonAsciiPluginPath, *BlankEsmPath); \
- TestTrue(FString::Printf(TEXT("Русский.esm created for %s"), *GameNameStr), FileManager.FileExists(*NonAsciiPluginPath)); \
- \
- /* Test Function Definitions - Test loading a missing plugin, expecting it to fail. */ \
- auto TestLoadMissingPlugin = [&](FPlugin& Plugin) { \
- bool bLoadFailed = !UPluginHelper::LoadPlugin(Plugin, MissingPluginPath, GameID, false); \
- TestTrue(FString::Printf(TEXT("Load missing plugin fails for %s"), *GameNameStr), bLoadFailed); \
- }; \
- \
- /* Test loading a valid plugin, expecting it to succeed. */ \
- auto TestLoadValidPlugin = [&](FPlugin& Plugin, const FString& FilePath) { \
- bool bLoaded = UPluginHelper::LoadPlugin(Plugin, FilePath, GameID, false); \
- TestTrue(FString::Printf(TEXT("Load valid plugin %s succeeds for %s"), *FPaths::GetBaseFilename(FilePath), *GameNameStr), bLoaded); \
- }; \
- \
- /* Test loading an invalid plugin, expecting it to fail, with a custom description. */ \
- auto TestLoadInvalidPlugin = [&](FPlugin& Plugin, const FString& FilePath, const FString& TestDesc) { \
- bool bLoadFailed = !UPluginHelper::LoadPlugin(Plugin, FilePath, GameID, false); \
- TestTrue(FString::Printf(TEXT("Load %s fails for %s"), *TestDesc, *GameNameStr), bLoadFailed); \
- }; \
- \
- /* Test if a plugin file is valid, comparing the result to an expected value. */ \
- auto TestIsValid = [&](const FString& FilePath, bool bExpectedValid, bool bHeaderOnly = false) { \
- bool bIsValid = UPluginHelper::IsValidPlugin(FilePath, GameID, bHeaderOnly); \
- TestEqual(FString::Printf(TEXT("IsValid %s returns %s for %s (HeaderOnly=%d)"), *FPaths::GetBaseFilename(FilePath), bExpectedValid ? TEXT("true") : TEXT("false"), *GameNameStr, bHeaderOnly), bIsValid, bExpectedValid); \
- }; \
- \
- /* Test if the plugin's name matches the expected name after loading. */ \
- auto TestPluginName = [&](FPlugin& Plugin, const FString& FilePath, const FString& ExpectedName) { \
- TestLoadValidPlugin(Plugin, FilePath); \
- TestEqual(FString::Printf(TEXT("Plugin name matches %s for %s"), *ExpectedName, *GameNameStr), UPluginHelper::GetName(Plugin), ExpectedName); \
- }; \
- \
- /* Test if the plugin is a master file, comparing to an expected value. */ \
- auto TestIsMasterFile = [&](FPlugin& Plugin, const FString& FilePath, bool bExpectedMaster) { \
- TestLoadValidPlugin(Plugin, FilePath); \
- TestEqual(FString::Printf(TEXT("%s isMasterFile returns %s for %s"), *FPaths::GetBaseFilename(FilePath), bExpectedMaster ? TEXT("true") : TEXT("false"), *GameNameStr), UPluginHelper::IsMasterFile(Plugin), bExpectedMaster); \
- }; \
- \
- /* Test the plugin's master dependencies, checking count and specific masters. */ \
- auto TestMasters = [&](FPlugin& Plugin, const FString& FilePath, const TArray<FString>& ExpectedMasters) { \
- TestLoadValidPlugin(Plugin, FilePath); \
- TArray<FString> Masters = UPluginHelper::GetMasters(Plugin); \
- TestEqual(FString::Printf(TEXT("Masters count for %s in %s"), *FPaths::GetBaseFilename(FilePath), *GameNameStr), Masters.Num(), ExpectedMasters.Num()); \
- for (const FString& Master : ExpectedMasters) \
- { \
- TestTrue(FString::Printf(TEXT("Master %s found for %s in %s"), *Master, *FPaths::GetBaseFilename(FilePath), *GameNameStr), Masters.Contains(Master)); \
- } \
- }; \
- \
- /* Test the plugin's description, comparing to an expected value. */ \
- auto TestDescription = [&](FPlugin& Plugin, const FString& FilePath, const FString& ExpectedDesc) { \
- TestLoadValidPlugin(Plugin, FilePath); \
- TestEqual(FString::Printf(TEXT("Description for %s in %s"), *FPaths::GetBaseFilename(FilePath), *GameNameStr), UPluginHelper::GetDescription(Plugin), ExpectedDesc); \
- }; \
- \
- /* Test the plugin's FormIDs, checking count and specific IDs against expected values. */ \
- auto TestFormIds = [&](FPlugin& Plugin, const FString& FilePath, const TArray<FFormID>& ExpectedFormIds, bool bHeaderOnly = false) { \
- FString FileName = FPaths::GetBaseFilename(FilePath); \
- bool bLoaded = UPluginHelper::LoadPlugin(Plugin, FilePath, GameID, bHeaderOnly); \
- FString LoadTestDesc = FString::Format(TEXT("Load {0} for FormIDs succeeds for {1}"), {FStringFormatArg(FileName), FStringFormatArg(GameNameStr)}); \
- TestTrue(*LoadTestDesc, bLoaded); \
- TArray<FFormID> FormIds = UPluginHelper::GetFormIds(Plugin); \
- FString CountTestDesc = FString::Format(TEXT("FormIDs count for {0} in {1}"), {FStringFormatArg(FileName), FStringFormatArg(GameNameStr)}); \
- TestEqual(*CountTestDesc, FormIds.Num(), ExpectedFormIds.Num()); \
- for (const FFormID& ExpectedId : ExpectedFormIds) \
- { \
- FString ValueStr = FString::FromInt(ExpectedId.Value); \
- FString FormIdTestDesc = FString::Format(TEXT("FormID {0} found for {1} in {2}"), {FStringFormatArg(ValueStr), FStringFormatArg(FileName), FStringFormatArg(GameNameStr)}); \
- TestTrue(*FormIdTestDesc, FormIds.Contains(ExpectedId)); \
- } \
- }; \
- \
- /* Test the plugin's record and group count, comparing to an expected value. */ \
- auto TestRecordAndGroupCount = [&](FPlugin& Plugin, const FString& FilePath, int32 ExpectedCount, bool bHeaderOnly = false) { \
- bool bLoaded = UPluginHelper::LoadPlugin(Plugin, FilePath, GameID, bHeaderOnly); \
- TestTrue(FString::Printf(TEXT("Load %s for record count succeeds for %s"), *FPaths::GetBaseFilename(FilePath), *GameNameStr), bLoaded); \
- TestEqual(FString::Printf(TEXT("Record and group count for %s in %s"), *FPaths::GetBaseFilename(FilePath), *GameNameStr), UPluginHelper::GetRecordAndGroupCount(Plugin), ExpectedCount); \
- }; \
- \
- /* Execute Tests - Create a plugin instance for running tests. */ \
- FPlugin Plugin; \
- \
- /* Test loading a missing plugin file. */ \
- TestLoadMissingPlugin(Plugin); \
- /* Test loading valid plugins (Blank.esm and non-ASCII named plugin). */ \
- TestLoadValidPlugin(Plugin, BlankEsmPath); \
- TestLoadValidPlugin(Plugin, NonAsciiPluginPath); \
- /* Test loading invalid plugins (empty and invalid content files). */ \
- TestLoadInvalidPlugin(Plugin, EmptyFilePath, TEXT("empty file")); \
- TestLoadInvalidPlugin(Plugin, InvalidPluginPath, TEXT("invalid plugin")); \
- /* For Skyrim, test loading the BSA file as an invalid plugin. */ \
- if (GameID == EGameID::Skyrim) \
- { \
- TestLoadInvalidPlugin(Plugin, BlankBsaPath, TEXT("Skyrim BSA")); \
- } \
- \
- /* Test plugin validity for Blank.esm (valid) and NotAPlugin.esm (invalid). */ \
- TestIsValid(BlankEsmPath, true); \
- TestIsValid(InvalidPluginPath, false); \
- /* For Skyrim, test Blank.bsa as an invalid plugin. */ \
- if (GameID == EGameID::Skyrim) \
- { \
- TestIsValid(BlankBsaPath, false); \
- } \
- /* Test validity with header-only check. */ \
- TestIsValid(BlankEsmPath, true, true); \
- TestIsValid(InvalidPluginPath, false, true); \
- if (GameID == EGameID::Skyrim) \
- { \
- TestIsValid(BlankBsaPath, false, true); \
- } \
- \
- /* Test plugin names for Blank.esm and Blank.esp. */ \
- TestPluginName(Plugin, BlankEsmPath, TEXT("Blank")); \
- TestPluginName(Plugin, BlankEspPath, TEXT("Blank")); \
- \
- /* Test master file status for Blank.esm (true) and Blank.esp (false). */ \
- TestIsMasterFile(Plugin, BlankEsmPath, true); \
- TestIsMasterFile(Plugin, BlankEspPath, false); \
- \
- /* Test master dependencies: Blank.esm (none), Blank - Master Dependent.esm (Blank.esm). */ \
- TestMasters(Plugin, BlankEsmPath, TArray<FString>()); \
- TestMasters(Plugin, BlankMasterDependentEsmPath, { TEXT("Blank.esm") }); \
- \
- /* Test plugin descriptions for various files. */ \
- TestDescription(Plugin, BlankEsmPath, TEXT("v5.0")); \
- TestDescription(Plugin, BlankEspPath, TEXT("€ƒŠ")); \
- TestDescription(Plugin, BlankMasterDependentEsmPath, TEXT("")); \
- \
- /* Morrowind-specific test: FormIDs should be empty. */ \
- if (GameID == EGameID::Morrowind) \
- { \
- TestLoadValidPlugin(Plugin, BlankEsmPath); \
- TestTrue(FString::Printf(TEXT("GetFormIds returns empty for Morrowind")), UPluginHelper::GetFormIds(Plugin).Num() == 0); \
- } \
- else \
- { \
- /* Define expected FormIDs for Blank.esm (0xCF0 to 0xCF9). */ \
- TArray<FFormID> BlankEsmFormIds; \
- for (int32 i = 0xCF0; i <= 0xCF9; i++) BlankEsmFormIds.Add(FFormID{i}); \
- TestFormIds(Plugin, BlankEsmPath, BlankEsmFormIds); \
- \
- /* Create and test a ghosted version of Blank.esm. */ \
- FileManager.Copy(*GhostedBlankEsmPath, *BlankEsmPath); \
- TestPluginName(Plugin, GhostedBlankEsmPath, TEXT("Blank")); \
- TestFormIds(Plugin, GhostedBlankEsmPath, BlankEsmFormIds); \
- \
- /* Define expected FormIDs for Blank - Master Dependent.esm. */ \
- TArray<FFormID> MasterDependentFormIds = { FFormID{static_cast<int32>(0xCF0)}, FFormID{static_cast<int32>(0xCF1)}, FFormID{static_cast<int32>(0xCF2)}, FFormID{static_cast<int32>(0xCF3)}, \
- FFormID{static_cast<int32>(0x01000CEA)}, FFormID{static_cast<int32>(0x01000CEB)}, FFormID{static_cast<int32>(0x01000CEC)}, FFormID{static_cast<int32>(0x01000CED)} }; \
- TestFormIds(Plugin, BlankMasterDependentEsmPath, MasterDependentFormIds); \
- \
- /* Test FormIDs with header-only load (expecting none). */ \
- TestFormIds(Plugin, BlankEsmPath, TArray<FFormID>(), true); \
- } \
- \
- /* Set expected record and group count based on the game. */ \
- int32 ExpectedCount = (GameID == EGameID::Morrowind) ? 10 : (GameID == EGameID::Oblivion) ? 14 : 15; \
- TestRecordAndGroupCount(Plugin, BlankEsmPath, ExpectedCount); \
- TestRecordAndGroupCount(Plugin, BlankEsmPath, ExpectedCount, true); \
- \
- /* Cleanup - Delete the temporary directory and all its contents to clean up after testing. */ \
- FileManager.DeleteDirectory(*TempDir, true, true); \
- return true; /* Indicate successful test completion */ \
- }
- /* Declare automation tests for each supported Bethesda game. */
- DECLARE_PLUGIN_TEST(Skyrim, Skyrim)
- DECLARE_PLUGIN_TEST(Oblivion, Oblivion)
- DECLARE_PLUGIN_TEST(Fallout3, Fallout3)
- DECLARE_PLUGIN_TEST(FalloutNV, FalloutNV)
- DECLARE_PLUGIN_TEST(Morrowind, Morrowind)
- DECLARE_PLUGIN_TEST(Fallout4, Fallout4)
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement