diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 328074c0..245047fd 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -76,7 +76,8 @@ set(LIBLOOT_SRC_TESTS_INTERFACE_H_FILES "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/message_content_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/plugin_cleaning_data_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/plugin_metadata_test.h" - "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/tag_test.h") + "${CMAKE_SOURCE_DIR}/src/tests/api/interface/metadata/tag_test.h" + "${CMAKE_SOURCE_DIR}/src/tests/api/interface/plugin_interface_test.h") source_group(TREE "${CMAKE_SOURCE_DIR}/src/tests/api/internals" PREFIX "Source Files" diff --git a/src/tests/api/interface/main.cpp b/src/tests/api/interface/main.cpp index 9e42be34..9b217666 100644 --- a/src/tests/api/interface/main.cpp +++ b/src/tests/api/interface/main.cpp @@ -38,6 +38,7 @@ #include "tests/api/interface/database_interface_test.h" #include "tests/api/interface/game_interface_test.h" #include "tests/api/interface/is_compatible_test.h" +#include "tests/api/interface/plugin_interface_test.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/src/tests/api/interface/plugin_interface_test.h b/src/tests/api/interface/plugin_interface_test.h new file mode 100644 index 00000000..ed8da8ba --- /dev/null +++ b/src/tests/api/interface/plugin_interface_test.h @@ -0,0 +1,486 @@ +/* LOOT + +A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and +Fallout: New Vegas. + +Copyright (C) 2014-2016 WrinklyNinja + +This file is part of LOOT. + +LOOT is free software: you can redistribute +it and/or modify it under the terms of the GNU General Public License +as published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +LOOT is distributed in the hope that it will +be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LOOT. If not, see +. +*/ + +#ifndef LOOT_TESTS_API_INTERFACE_PLUGIN_INTERFACE_TEST +#define LOOT_TESTS_API_INTERFACE_PLUGIN_INTERFACE_TEST + +#include "loot/api.h" +#include "tests/api/interface/api_game_operations_test.h" + +namespace loot::test { +class PluginInterfaceTest : public ApiGameOperationsTest { +protected: + PluginInterfaceTest() : + ApiGameOperationsTest(), + nonAsciiEsp(u8"non\u00C1scii.esp"), + otherNonAsciiEsp(u8"other non\u00C1scii.esp"), + blankArchive("Blank" + GetArchiveFileExtension(GetParam())), + blankSuffixArchive("Blank - Different - suffix" + + GetArchiveFileExtension(GetParam())) {} + + void SetUp() override { + ApiGameOperationsTest::SetUp(); + + handle_->LoadPlugins(GetInstalledPlugins(), false); + + if (!supportsLightPlugins(GetParam())) { + ASSERT_NO_THROW( + std::filesystem::copy(dataPath / blankEsp, dataPath / blankEsl)); + } + ASSERT_TRUE(std::filesystem::exists(dataPath / blankEsl)); + + // Make sure the plugins with non-ASCII filenames exists. + ASSERT_NO_THROW(std::filesystem::copy_file( + dataPath / blankEsp, dataPath / std::filesystem::u8path(nonAsciiEsp))); + ASSERT_NO_THROW(std::filesystem::copy_file( + dataPath / blankEsp, + dataPath / std::filesystem::u8path(otherNonAsciiEsp))); + + // Copy across archive files. + std::filesystem::path blankMasterDependentArchive; + if (GetParam() == GameType::fo4 || GetParam() == GameType::fo4vr || + GetParam() == GameType::starfield) { + copyPlugin(getSourceArchivesPath(GetParam()), "Blank - Main.ba2"); + copyPlugin(getSourceArchivesPath(GetParam()), "Blank - Textures.ba2"); + + blankMasterDependentArchive = "Blank - Master Dependent - Main.ba2"; + std::filesystem::copy_file( + getSourceArchivesPath(GetParam()) / "Blank - Main.ba2", + dataPath / blankMasterDependentArchive); + ASSERT_TRUE( + std::filesystem::exists(dataPath / blankMasterDependentArchive)); + } else if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) { + touch(dataPath / blankArchive); + + blankMasterDependentArchive = "Blank - Master Dependent.bsa"; + touch(dataPath / blankMasterDependentArchive); + } else { + copyPlugin(getSourcePluginsPath(), blankArchive); + + // Also create a copy for Blank - Master Dependent.esp to test overlap. + blankMasterDependentArchive = "Blank - Master Dependent.bsa"; + std::filesystem::copy_file(getSourcePluginsPath() / blankArchive, + dataPath / blankMasterDependentArchive); + ASSERT_TRUE( + std::filesystem::exists(dataPath / blankMasterDependentArchive)); + } + + // Create dummy archive files. + touch(dataPath / blankSuffixArchive); + + auto nonAsciiArchivePath = + dataPath / std::filesystem::u8path(u8"non\u00E1scii" + + GetArchiveFileExtension(GetParam())); + touch(dataPath / nonAsciiArchivePath); + + auto nonAsciiPrefixArchivePath = + dataPath / std::filesystem::u8path(u8"other non\u00E1scii2 - suffix" + + GetArchiveFileExtension(GetParam())); + touch(dataPath / nonAsciiPrefixArchivePath); + } + + std::shared_ptr LoadPluginHeader( + std::string_view pluginName) { + handle_->LoadPlugins({std::filesystem::u8path(pluginName)}, true); + + return handle_->GetPlugin(pluginName); + } + + std::shared_ptr LoadPlugin( + std::string_view pluginName) { + handle_->LoadPlugins({std::filesystem::u8path(pluginName)}, false); + + return handle_->GetPlugin(pluginName); + } + + std::string nonAsciiEsp; + std::string otherNonAsciiEsp; + std::string blankArchive; + std::string blankSuffixArchive; + + std::shared_ptr game_; + +private: + static std::string GetArchiveFileExtension(const GameType gameType) { + if (gameType == GameType::fo4 || gameType == GameType::fo4vr || + gameType == GameType::starfield) + return ".ba2"; + else + return ".bsa"; + } +}; + +class TestPlugin : public PluginInterface { +public: + std::string GetName() const override { return ""; } + + std::optional GetHeaderVersion() const override { + return std::optional(); + } + + std::optional GetVersion() const override { + return std::optional(); + } + + std::vector GetMasters() const override { return {}; } + + std::vector GetBashTags() const override { return {}; } + + std::optional GetCRC() const override { + return std::optional(); + } + + bool IsMaster() const override { return false; } + + bool IsLightPlugin() const override { return false; } + + bool IsMediumPlugin() const override { return false; } + + bool IsUpdatePlugin() const override { return false; } + + bool IsBlueprintPlugin() const override { return false; } + + bool IsValidAsLightPlugin() const override { return false; } + + bool IsValidAsMediumPlugin() const override { return false; } + + bool IsValidAsUpdatePlugin() const override { return false; } + + bool IsEmpty() const override { return false; } + + bool LoadsArchive() const override { return false; } + + bool DoRecordsOverlap(const PluginInterface&) const override { return false; } +}; + +// Pass an empty first argument, as it's a prefix for the test instantation, +// but we only have the one so no prefix is necessary. +INSTANTIATE_TEST_SUITE_P(, + PluginInterfaceTest, + ::testing::ValuesIn(ALL_GAME_TYPES)); + +TEST_P(PluginInterfaceTest, + shouldBeAbleToGetHeaderDataFromPluginLoadedHeaderOnly) { + const auto plugin = LoadPluginHeader(blankEsm); + + EXPECT_EQ(blankEsm, plugin->GetName()); + EXPECT_TRUE(plugin->GetMasters().empty()); + if (GetParam() == GameType::openmw || + GetParam() == GameType::oblivionRemastered) { + EXPECT_FALSE(plugin->IsMaster()); + } else { + EXPECT_TRUE(plugin->IsMaster()); + } + EXPECT_FALSE(plugin->IsEmpty()); + EXPECT_EQ("5.0", plugin->GetVersion()); + + if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) { + EXPECT_FLOAT_EQ(1.2f, plugin->GetHeaderVersion().value()); + } else if (GetParam() == GameType::tes4 || + GetParam() == GameType::oblivionRemastered) { + EXPECT_FLOAT_EQ(0.8f, plugin->GetHeaderVersion().value()); + } else if (GetParam() == GameType::starfield) { + EXPECT_FLOAT_EQ(0.96f, plugin->GetHeaderVersion().value()); + } else { + EXPECT_FLOAT_EQ(0.94f, plugin->GetHeaderVersion().value()); + } +} + +TEST_P(PluginInterfaceTest, shouldBeAbleToGetAllDataFromFullyLoadedPlugin) { + const auto plugin = LoadPlugin(blankEsm); + + EXPECT_EQ(blankEsm, plugin->GetName()); + EXPECT_TRUE(plugin->GetMasters().empty()); + if (GetParam() == GameType::openmw || + GetParam() == GameType::oblivionRemastered) { + EXPECT_FALSE(plugin->IsMaster()); + } else { + EXPECT_TRUE(plugin->IsMaster()); + } + EXPECT_FALSE(plugin->IsEmpty()); + EXPECT_EQ("5.0", plugin->GetVersion()); + + if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) { + EXPECT_FLOAT_EQ(1.2f, plugin->GetHeaderVersion().value()); + } else if (GetParam() == GameType::tes4 || + GetParam() == GameType::oblivionRemastered) { + EXPECT_FLOAT_EQ(0.8f, plugin->GetHeaderVersion().value()); + } else if (GetParam() == GameType::starfield) { + EXPECT_FLOAT_EQ(0.96f, plugin->GetHeaderVersion().value()); + } else { + EXPECT_FLOAT_EQ(0.94f, plugin->GetHeaderVersion().value()); + } + + EXPECT_EQ(blankEsmCrc, plugin->GetCRC()); +} + +TEST_P(PluginInterfaceTest, + loadingANonMasterPluginShouldReadTheMasterFlagAsFalse) { + const auto plugin = LoadPluginHeader(blankMasterDependentEsp); + + EXPECT_FALSE(plugin->IsMaster()); +} + +TEST_P( + PluginInterfaceTest, + isLightPluginShouldBeTrueForAPluginWithEslFileExtensionForFallout4AndSkyrimSe) { + const auto plugin1 = LoadPluginHeader(blankEsm); + const auto plugin2 = LoadPluginHeader(blankMasterDependentEsp); + + EXPECT_FALSE(plugin1->IsLightPlugin()); + EXPECT_FALSE(plugin2->IsLightPlugin()); + + if (GetParam() == GameType::fo4 || GetParam() == GameType::fo4vr || + GetParam() == GameType::tes5se || GetParam() == GameType::tes5vr || + GetParam() == GameType::starfield) { + const auto plugin3 = LoadPluginHeader(blankEsl); + EXPECT_TRUE(plugin3->IsLightPlugin()); + } +} + +TEST_P(PluginInterfaceTest, + isMediumPluginShouldBeTrueForAMediumFlaggedPluginForStarfield) { + if (GetParam() != GameType::starfield) { + auto bytes = ReadFile(dataPath / blankEsm); + bytes[9] = 0x4; + WriteFile(dataPath / blankEsm, bytes); + } + + const auto& pluginName = + GetParam() == GameType::starfield ? blankMediumEsm : blankEsm; + const auto plugin = LoadPluginHeader(pluginName); + + EXPECT_EQ(GetParam() == GameType::starfield, plugin->IsMediumPlugin()); +} + +TEST_P(PluginInterfaceTest, + isUpdatePluginShouldOnlyBeTrueForAStarfieldUpdatePlugin) { + auto bytes = ReadFile(dataPath / blankMasterDependentEsp); + bytes[9] = 0x2; + WriteFile(dataPath / blankMasterDependentEsp, bytes); + + const auto plugin1 = LoadPluginHeader(blankEsp); + const auto plugin2 = LoadPluginHeader(blankMasterDependentEsp); + + EXPECT_FALSE(plugin1->IsUpdatePlugin()); + EXPECT_EQ(GetParam() == GameType::starfield, plugin2->IsUpdatePlugin()); +} + +TEST_P(PluginInterfaceTest, + isBlueprintPluginShouldOnlyBeTrueForAStarfieldBlueprintPlugin) { + SetBlueprintFlag(dataPath / blankMasterDependentEsp); + + const auto plugin1 = LoadPluginHeader(blankEsp); + const auto plugin2 = LoadPluginHeader(blankMasterDependentEsp); + + EXPECT_FALSE(plugin1->IsBlueprintPlugin()); + EXPECT_EQ(GetParam() == GameType::starfield, plugin2->IsBlueprintPlugin()); +} + +TEST_P(PluginInterfaceTest, loadingAPluginWithMastersShouldReadThemCorrectly) { + const auto plugin = LoadPluginHeader(blankMasterDependentEsp); + + if (GetParam() == GameType::starfield) { + EXPECT_EQ(std::vector({blankFullEsm}), plugin->GetMasters()); + } else { + EXPECT_EQ(std::vector({blankEsm}), plugin->GetMasters()); + } +} + +TEST_P( + PluginInterfaceTest, + loadsArchiveForAnArchiveThatExactlyMatchesAnEsmFileBasenameShouldReturnTrueForAllGamesExceptMorrowindAndOblivion) { + bool loadsArchive = LoadPluginHeader(blankEsm)->LoadsArchive(); + + if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw || + GetParam() == GameType::tes4 || + GetParam() == GameType::oblivionRemastered) + EXPECT_FALSE(loadsArchive); + else + EXPECT_TRUE(loadsArchive); +} + +#ifdef _WIN32 +TEST_P( + PluginInterfaceTest, + loadsArchiveForAnArchiveThatExactlyMatchesANonAsciiEspFileBasenameShouldReturnTrueForAllGamesExceptMorrowindAndStarfield) { + bool loadsArchive = LoadPluginHeader(nonAsciiEsp)->LoadsArchive(); + + if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw || + GetParam() == GameType::starfield) + EXPECT_FALSE(loadsArchive); + else + EXPECT_TRUE(loadsArchive); +} +#endif + +TEST_P( + PluginInterfaceTest, + loadsArchiveForAnArchiveThatExactlyMatchesAnEspFileBasenameShouldReturnTrueForAllGamesExceptMorrowind) { + bool loadsArchive = LoadPluginHeader(blankEsp)->LoadsArchive(); + + if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) + EXPECT_FALSE(loadsArchive); + else + EXPECT_TRUE(loadsArchive); +} + +TEST_P( + PluginInterfaceTest, + loadsArchiveForAnArchiveWithAFilenameWhichStartsWithTheEsmFileBasenameShouldReturnTrueForOnlyTheFalloutGames) { + bool loadsArchive = LoadPluginHeader(blankDifferentEsm)->LoadsArchive(); + + if (GetParam() == GameType::fo3 || GetParam() == GameType::fonv || + GetParam() == GameType::fo4 || GetParam() == GameType::fo4vr) { + EXPECT_TRUE(loadsArchive); + } else { + EXPECT_FALSE(loadsArchive); + } +} + +TEST_P( + PluginInterfaceTest, + loadsArchiveForAnArchiveWithAFilenameWhichStartsWithTheEspFileBasenameShouldReturnTrueForOnlyOblivionAndTheFalloutGames) { + bool loadsArchive = LoadPluginHeader(blankDifferentEsp)->LoadsArchive(); + + if (GetParam() == GameType::tes4 || GetParam() == GameType::fo3 || + GetParam() == GameType::fonv || GetParam() == GameType::fo4 || + GetParam() == GameType::fo4vr || + GetParam() == GameType::oblivionRemastered) { + EXPECT_TRUE(loadsArchive); + } else { + EXPECT_FALSE(loadsArchive); + } +} + +#ifdef _WIN32 +TEST_P( + PluginInterfaceTest, + loadsArchiveForAnArchiveWithAFilenameWhichStartsWithTheNonAsciiEspFileBasenameShouldReturnTrueForOnlyOblivionAndTheFalloutGames) { + bool loadsArchive = LoadPluginHeader(otherNonAsciiEsp)->LoadsArchive(); + + if (GetParam() == GameType::tes4 || GetParam() == GameType::fo3 || + GetParam() == GameType::fonv || GetParam() == GameType::fo4 || + GetParam() == GameType::fo4vr || + GetParam() == GameType::oblivionRemastered) { + EXPECT_TRUE(loadsArchive); + } else { + EXPECT_FALSE(loadsArchive); + } +} +#endif + +TEST_P(PluginInterfaceTest, + loadsArchiveShouldReturnFalseForAPluginThatDoesNotLoadAnArchive) { + const auto pluginName = GetParam() == GameType::starfield + ? blankDifferentEsp + : blankDifferentMasterDependentEsp; + bool loadsArchive = LoadPluginHeader(pluginName)->LoadsArchive(); + + EXPECT_FALSE(loadsArchive); +} + +TEST_P( + PluginInterfaceTest, + isValidAsLightPluginShouldReturnTrueOnlyForASkyrimSEOrFallout4PluginWithNewFormIdsBetween0x800And0xFFFInclusive) { + bool valid = LoadPlugin(blankEsm)->IsValidAsLightPlugin(); + if (GetParam() == GameType::fo4 || GetParam() == GameType::fo4vr || + GetParam() == GameType::tes5se || GetParam() == GameType::tes5vr || + GetParam() == GameType::starfield) { + EXPECT_TRUE(valid); + } else { + EXPECT_FALSE(valid); + } +} + +TEST_P( + PluginInterfaceTest, + isValidAsMediumPluginShouldReturnTrueOnlyForAStarfieldPluginWithNewFormIdsBetween0And0xFFFFInclusive) { + bool valid = LoadPlugin(blankEsm)->IsValidAsMediumPlugin(); + if (GetParam() == GameType::starfield) { + EXPECT_TRUE(valid); + } else { + EXPECT_FALSE(valid); + } +} + +TEST_P( + PluginInterfaceTest, + IsValidAsUpdatePluginShouldOnlyReturnTrueForAStarfieldPluginWithNoNewRecords) { + const auto sourcePluginName = + GetParam() == GameType::starfield ? blankFullEsm : blankEsp; + const auto updatePluginName = GetParam() == GameType::starfield + ? blankMasterDependentEsp + : blankDifferentPluginDependentEsp; + + std::vector> plugins; + plugins.push_back(LoadPlugin(sourcePluginName)); + plugins.push_back(LoadPlugin(updatePluginName)); + + EXPECT_FALSE(plugins[0]->IsValidAsUpdatePlugin()); + EXPECT_EQ(GetParam() == GameType::starfield, + plugins[1]->IsValidAsUpdatePlugin()); +} + +TEST_P(PluginInterfaceTest, + doRecordsOverlapShouldReturnFalseIfTheArgumentIsNotAPluginObject) { + const auto plugin1 = LoadPlugin(blankEsm); + TestPlugin plugin2; + + EXPECT_FALSE(plugin1->DoRecordsOverlap(plugin2)); +} + +TEST_P(PluginInterfaceTest, + doRecordsOverlapShouldReturnFalseForTwoPluginsWithOnlyHeadersLoaded) { + const auto plugin1 = LoadPluginHeader(blankEsm); + const auto plugin2 = LoadPluginHeader(blankMasterDependentEsm); + + EXPECT_FALSE(plugin1->DoRecordsOverlap(*plugin2)); + EXPECT_FALSE(plugin2->DoRecordsOverlap(*plugin1)); +} + +TEST_P(PluginInterfaceTest, + doRecordsOverlapShouldReturnFalseIfThePluginsHaveUnrelatedRecords) { + const auto plugin1 = LoadPlugin(blankEsm); + const auto plugin2 = LoadPlugin(blankEsp); + + EXPECT_FALSE(plugin1->DoRecordsOverlap(*plugin2)); + EXPECT_FALSE(plugin2->DoRecordsOverlap(*plugin1)); +} + +TEST_P(PluginInterfaceTest, + doRecordsOverlapShouldReturnTrueIfOnePluginOverridesTheOthersRecords) { + const auto plugin1Name = + GetParam() == GameType::starfield ? blankFullEsm : blankEsm; + + const auto plugin1 = LoadPlugin(plugin1Name); + const auto plugin2 = LoadPlugin(blankMasterDependentEsm); + + EXPECT_TRUE(plugin1->DoRecordsOverlap(*plugin2)); + EXPECT_TRUE(plugin2->DoRecordsOverlap(*plugin1)); +} + +} + +#endif diff --git a/src/tests/api/internals/plugin_test.h b/src/tests/api/internals/plugin_test.h index 4c7e198a..b9151cba 100644 --- a/src/tests/api/internals/plugin_test.h +++ b/src/tests/api/internals/plugin_test.h @@ -278,67 +278,6 @@ TEST_P(PluginTest, loadingShouldHandleNonAsciiFilenamesCorrectly) { EXPECT_EQ(nonAsciiEsp, plugin.GetName()); } -TEST_P(PluginTest, loadingHeaderOnlyShouldReadHeaderData) { - Plugin plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, true); - - EXPECT_EQ(blankEsm, plugin.GetName()); - EXPECT_TRUE(plugin.GetMasters().empty()); - if (GetParam() == GameType::openmw || - GetParam() == GameType::oblivionRemastered) { - EXPECT_FALSE(plugin.IsMaster()); - } else { - EXPECT_TRUE(plugin.IsMaster()); - } - EXPECT_FALSE(plugin.IsEmpty()); - EXPECT_EQ("5.0", plugin.GetVersion()); - - if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) { - EXPECT_FLOAT_EQ(1.2f, plugin.GetHeaderVersion().value()); - } else if (GetParam() == GameType::tes4 || - GetParam() == GameType::oblivionRemastered) { - EXPECT_FLOAT_EQ(0.8f, plugin.GetHeaderVersion().value()); - } else if (GetParam() == GameType::starfield) { - EXPECT_FLOAT_EQ(0.96f, plugin.GetHeaderVersion().value()); - } else { - EXPECT_FLOAT_EQ(0.94f, plugin.GetHeaderVersion().value()); - } -} - -TEST_P(PluginTest, loadingHeaderOnlyShouldNotReadFieldsOrCalculateCrc) { - Plugin plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, true); - - EXPECT_FALSE(plugin.GetCRC()); -} - -TEST_P(PluginTest, loadingWholePluginShouldReadHeaderData) { - Plugin plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, true); - - EXPECT_EQ(blankEsm, plugin.GetName()); - EXPECT_TRUE(plugin.GetMasters().empty()); - if (GetParam() == GameType::openmw || - GetParam() == GameType::oblivionRemastered) { - EXPECT_FALSE(plugin.IsMaster()); - } else { - EXPECT_TRUE(plugin.IsMaster()); - } - EXPECT_FALSE(plugin.IsEmpty()); - EXPECT_EQ("5.0", plugin.GetVersion()); - - if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) { - EXPECT_FLOAT_EQ(1.2f, plugin.GetHeaderVersion().value()); - } else if (GetParam() == GameType::tes4 || - GetParam() == GameType::oblivionRemastered) { - EXPECT_FLOAT_EQ(0.8f, plugin.GetHeaderVersion().value()); - } else if (GetParam() == GameType::starfield) { - EXPECT_FLOAT_EQ(0.96f, plugin.GetHeaderVersion().value()); - } else { - EXPECT_FLOAT_EQ(0.94f, plugin.GetHeaderVersion().value()); - } -} - TEST_P(PluginTest, loadingWholePluginShouldReadFields) { const auto pluginName = GetParam() == GameType::openmw ? blankMasterDependentEsm @@ -369,22 +308,6 @@ TEST_P(PluginTest, loadingWholePluginShouldReadFields) { } } -TEST_P(PluginTest, loadingWholePluginShouldCalculateCrc) { - Plugin plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, false); - - EXPECT_EQ(blankEsmCrc, plugin.GetCRC()); -} - -TEST_P(PluginTest, loadingANonMasterPluginShouldReadTheMasterFlagAsFalse) { - Plugin plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / blankMasterDependentEsp, - true); - - EXPECT_FALSE(plugin.IsMaster()); -} - TEST_P(PluginTest, loadingWholePluginShouldSucceedForOpenMWPlugins) { const auto omwgame = "Blank.omwgame"; const auto omwaddon = "Blank.omwaddon"; @@ -430,66 +353,6 @@ TEST_P( plugin3.IsLightPlugin()); } -TEST_P(PluginTest, - isMediumPluginShouldBeTrueForAMediumFlaggedPluginForStarfield) { - if (GetParam() != GameType::starfield) { - auto bytes = ReadFile(dataPath / blankEsm); - bytes[9] = 0x4; - WriteFile(dataPath / blankEsm, bytes); - } - - const auto pluginName = - GetParam() == GameType::starfield ? blankMediumEsm : blankEsm; - Plugin plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / pluginName, true); - - EXPECT_EQ(GetParam() == GameType::starfield, plugin.IsMediumPlugin()); -} - -TEST_P(PluginTest, isUpdatePluginShouldOnlyBeTrueForAStarfieldUpdatePlugin) { - auto bytes = ReadFile(dataPath / blankMasterDependentEsp); - bytes[9] = 0x2; - WriteFile(dataPath / blankMasterDependentEsp, bytes); - - Plugin plugin1( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsp, true); - Plugin plugin2(game_.GetType(), - game_.GetCache(), - game_.DataPath() / blankMasterDependentEsp, - true); - - EXPECT_FALSE(plugin1.IsUpdatePlugin()); - EXPECT_EQ(GetParam() == GameType::starfield, plugin2.IsUpdatePlugin()); -} - -TEST_P(PluginTest, - isBlueprintPluginShouldOnlyBeTrueForAStarfieldBlueprintPlugin) { - SetBlueprintFlag(dataPath / blankMasterDependentEsp); - - Plugin plugin1( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsp, true); - Plugin plugin2(game_.GetType(), - game_.GetCache(), - game_.DataPath() / blankMasterDependentEsp, - true); - - EXPECT_FALSE(plugin1.IsBlueprintPlugin()); - EXPECT_EQ(GetParam() == GameType::starfield, plugin2.IsBlueprintPlugin()); -} - -TEST_P(PluginTest, loadingAPluginWithMastersShouldReadThemCorrectly) { - Plugin plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / blankMasterDependentEsp, - true); - - if (GetParam() == GameType::starfield) { - EXPECT_EQ(std::vector({blankFullEsm}), plugin.GetMasters()); - } else { - EXPECT_EQ(std::vector({blankEsm}), plugin.GetMasters()); - } -} - TEST_P(PluginTest, loadingAPluginThatDoesNotExistShouldThrow) { try { Plugin(game_.GetType(), @@ -503,125 +366,6 @@ TEST_P(PluginTest, loadingAPluginThatDoesNotExistShouldThrow) { } } -TEST_P( - PluginTest, - loadsArchiveForAnArchiveThatExactlyMatchesAnEsmFileBasenameShouldReturnTrueForAllGamesExceptMorrowindAndOblivion) { - bool loadsArchive = - Plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, true) - .LoadsArchive(); - - if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw || - GetParam() == GameType::tes4 || - GetParam() == GameType::oblivionRemastered) - EXPECT_FALSE(loadsArchive); - else - EXPECT_TRUE(loadsArchive); -} - -#ifdef _WIN32 -TEST_P( - PluginTest, - loadsArchiveForAnArchiveThatExactlyMatchesANonAsciiEspFileBasenameShouldReturnTrueForAllGamesExceptMorrowindAndStarfield) { - bool loadsArchive = - Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / std::filesystem::u8path(nonAsciiEsp), - true) - .LoadsArchive(); - - if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw || - GetParam() == GameType::starfield) - EXPECT_FALSE(loadsArchive); - else - EXPECT_TRUE(loadsArchive); -} -#endif - -TEST_P( - PluginTest, - loadsArchiveForAnArchiveThatExactlyMatchesAnEspFileBasenameShouldReturnTrueForAllGamesExceptMorrowind) { - bool loadsArchive = - Plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsp, true) - .LoadsArchive(); - - if (GetParam() == GameType::tes3 || GetParam() == GameType::openmw) - EXPECT_FALSE(loadsArchive); - else - EXPECT_TRUE(loadsArchive); -} - -TEST_P( - PluginTest, - loadsArchiveForAnArchiveWithAFilenameWhichStartsWithTheEsmFileBasenameShouldReturnTrueForOnlyTheFalloutGames) { - bool loadsArchive = Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / blankDifferentEsm, - true) - .LoadsArchive(); - - if (GetParam() == GameType::fo3 || GetParam() == GameType::fonv || - GetParam() == GameType::fo4 || GetParam() == GameType::fo4vr) { - EXPECT_TRUE(loadsArchive); - } else { - EXPECT_FALSE(loadsArchive); - } -} - -TEST_P( - PluginTest, - loadsArchiveForAnArchiveWithAFilenameWhichStartsWithTheEspFileBasenameShouldReturnTrueForOnlyOblivionAndTheFalloutGames) { - bool loadsArchive = Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / blankDifferentEsp, - true) - .LoadsArchive(); - - if (GetParam() == GameType::tes4 || GetParam() == GameType::fo3 || - GetParam() == GameType::fonv || GetParam() == GameType::fo4 || - GetParam() == GameType::fo4vr || - GetParam() == GameType::oblivionRemastered) { - EXPECT_TRUE(loadsArchive); - } else { - EXPECT_FALSE(loadsArchive); - } -} - -#ifdef _WIN32 -TEST_P( - PluginTest, - loadsArchiveForAnArchiveWithAFilenameWhichStartsWithTheNonAsciiEspFileBasenameShouldReturnTrueForOnlyOblivionAndTheFalloutGames) { - bool loadsArchive = - Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / std::filesystem::u8path(otherNonAsciiEsp), - true) - .LoadsArchive(); - - if (GetParam() == GameType::tes4 || GetParam() == GameType::fo3 || - GetParam() == GameType::fonv || GetParam() == GameType::fo4 || - GetParam() == GameType::fo4vr || - GetParam() == GameType::oblivionRemastered) { - EXPECT_TRUE(loadsArchive); - } else { - EXPECT_FALSE(loadsArchive); - } -} -#endif - -TEST_P(PluginTest, - loadsArchiveShouldReturnFalseForAPluginThatDoesNotLoadAnArchive) { - const auto pluginName = GetParam() == GameType::starfield - ? blankDifferentEsp - : blankDifferentMasterDependentEsp; - EXPECT_FALSE(Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / pluginName, - true) - .LoadsArchive()); -} - TEST_P(PluginTest, isValidShouldReturnTrueForAValidPlugin) { EXPECT_TRUE(Plugin::IsValid(game_.GetType(), game_.DataPath() / blankEsm)); } @@ -655,138 +399,6 @@ TEST_P(PluginTest, isValidShouldReturnTrueForAnOpenMWOmwscriptsFile) { } } -TEST_P( - PluginTest, - isValidAsLightPluginShouldReturnTrueOnlyForASkyrimSEOrFallout4PluginWithNewFormIdsBetween0x800And0xFFFInclusive) { - bool valid = - Plugin( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, true) - .IsValidAsLightPlugin(); - if (GetParam() == GameType::fo4 || GetParam() == GameType::fo4vr || - GetParam() == GameType::tes5se || GetParam() == GameType::tes5vr || - GetParam() == GameType::starfield) { - EXPECT_TRUE(valid); - } else { - EXPECT_FALSE(valid); - } -} - -TEST_P( - PluginTest, - isValidAsMediumPluginShouldReturnTrueOnlyForAStarfieldPluginWithNewFormIdsBetween0And0xFFFFInclusive) { - bool valid = - Plugin(game_.GetType(), game_.GetCache(), dataPath / blankEsm, true) - .IsValidAsMediumPlugin(); - if (GetParam() == GameType::starfield) { - EXPECT_TRUE(valid); - } else { - EXPECT_FALSE(valid); - } -} - -TEST_P( - PluginTest, - IsValidAsUpdatePluginShouldOnlyReturnTrueForAStarfieldPluginWithNoNewRecords) { - const auto sourcePluginName = - GetParam() == GameType::starfield ? blankFullEsm : blankEsp; - const auto updatePluginName = GetParam() == GameType::starfield - ? blankMasterDependentEsp - : blankDifferentPluginDependentEsp; - - std::vector plugins; - plugins.push_back(Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / sourcePluginName, - false)); - plugins.push_back(Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / updatePluginName, - false)); - - if (GetParam() == GameType::starfield) { - const auto pluginsMetadata = - Plugin::GetPluginsMetadata({&plugins[0], &plugins[1]}); - plugins[1].ResolveRecordIds(pluginsMetadata.get()); - - plugins[0].ResolveRecordIds(nullptr); - plugins[1].ResolveRecordIds(nullptr); - } - - EXPECT_FALSE(plugins[0].IsValidAsUpdatePlugin()); - EXPECT_EQ(GetParam() == GameType::starfield, - plugins[1].IsValidAsUpdatePlugin()); -} - -TEST_P(PluginTest, - doRecordsOverlapShouldReturnFalseIfTheArgumentIsNotAPluginObject) { - Plugin plugin1( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, false); - TestPlugin plugin2; - - EXPECT_FALSE(plugin1.DoRecordsOverlap(plugin2)); -} - -TEST_P(PluginTest, - doRecordsOverlapShouldReturnFalseForTwoPluginsWithOnlyHeadersLoaded) { - Plugin plugin1( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, true); - - const auto pluginName = GetParam() == GameType::openmw - ? blankMasterDependentEsm - : blankMasterDependentEsm + ".ghost"; - Plugin plugin2( - game_.GetType(), game_.GetCache(), game_.DataPath() / pluginName, true); - - EXPECT_FALSE(plugin1.DoRecordsOverlap(plugin2)); - EXPECT_FALSE(plugin2.DoRecordsOverlap(plugin1)); -} - -TEST_P(PluginTest, - doRecordsOverlapShouldReturnFalseIfThePluginsHaveUnrelatedRecords) { - Plugin plugin1( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsm, false); - Plugin plugin2( - game_.GetType(), game_.GetCache(), game_.DataPath() / blankEsp, false); - - if (GetParam() == GameType::starfield) { - plugin1.ResolveRecordIds(nullptr); - plugin2.ResolveRecordIds(nullptr); - } - - EXPECT_FALSE(plugin1.DoRecordsOverlap(plugin2)); - EXPECT_FALSE(plugin2.DoRecordsOverlap(plugin1)); -} - -TEST_P(PluginTest, - doRecordsOverlapShouldReturnTrueIfOnePluginOverridesTheOthersRecords) { - const auto plugin1Name = - GetParam() == GameType::starfield ? blankFullEsm : blankEsm; - const auto plugin2Name = GetParam() == GameType::openmw - ? blankMasterDependentEsm - : blankMasterDependentEsm + ".ghost"; - - std::vector plugins; - plugins.push_back(Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / plugin1Name, - false)); - plugins.push_back(Plugin(game_.GetType(), - game_.GetCache(), - game_.DataPath() / plugin2Name, - false)); - - if (GetParam() == GameType::starfield) { - plugins[0].ResolveRecordIds(nullptr); - - const auto pluginsMetadata = - Plugin::GetPluginsMetadata({&plugins[0], &plugins[1]}); - plugins[1].ResolveRecordIds(pluginsMetadata.get()); - } - - EXPECT_TRUE(plugins[0].DoRecordsOverlap(plugins[1])); - EXPECT_TRUE(plugins[1].DoRecordsOverlap(plugins[0])); -} - TEST_P(PluginTest, getAssetCountShouldReturnNumberOfFilesInArchivesLoadedByPlugin) { const auto assetCount =