diff --git a/CMakeLists.txt b/CMakeLists.txt index 1aae04e7..767fd2cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,7 +238,7 @@ set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/base_game_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_cache_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_settings_test.h" - "${CMAKE_SOURCE_DIR}/src/tests/backend/game/test_load_order_handler.h" + "${CMAKE_SOURCE_DIR}/src/tests/backend/game/load_order_handler_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_git_helper.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_helpers.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/test_language.h" diff --git a/src/tests/backend/game/game_test.h b/src/tests/backend/game/game_test.h index bef5ab03..077af4b6 100644 --- a/src/tests/backend/game/game_test.h +++ b/src/tests/backend/game/game_test.h @@ -29,19 +29,12 @@ along with LOOT. If not, see #include "backend/globals.h" #include "backend/game/game.h" -#include "tests/base_game_test.h" +#include "load_order_handler_test.h" namespace loot { namespace test { class GameTest : public BaseGameTest { protected: - - void SetUp() { - BaseGameTest::SetUp(); - - setLoadOrder(); - setActivePlugins(); - } #ifndef _WIN32 void TearDown() { BaseGameTest::TearDown(); @@ -49,54 +42,6 @@ namespace loot { ASSERT_NO_THROW(boost::filesystem::remove_all(g_path_local)); } #endif - - inline std::vector getExpectedLoadOrder() const { - return std::vector({ - masterFile, - blankEsm, - blankDifferentEsm, - blankMasterDependentEsm, - blankDifferentMasterDependentEsm, - blankEsp, - blankDifferentEsp, - blankMasterDependentEsp, - blankDifferentMasterDependentEsp, - blankPluginDependentEsp, - blankDifferentPluginDependentEsp, - }); - } - - inline void setLoadOrder() { - if (isTimestampLoadOrderMethod()) { - time_t modificationTime = time(NULL); // Current time. - for (const auto &plugin : getExpectedLoadOrder()) { - if (boost::filesystem::exists(dataPath / boost::filesystem::path(plugin + ".ghost"))) { - boost::filesystem::last_write_time(dataPath / boost::filesystem::path(plugin + ".ghost"), modificationTime); - } - else { - boost::filesystem::last_write_time(dataPath / plugin, modificationTime); - } - modificationTime += 60; - } - } - else { - boost::filesystem::ofstream loadOrder(localPath / "loadorder.txt"); - for (const auto &plugin : getExpectedLoadOrder()) - loadOrder << plugin << std::endl; - loadOrder.close(); - } - } - - inline void setActivePlugins() { - boost::filesystem::ofstream activePlugins(localPath / "plugins.txt"); - activePlugins - << blankEsm << std::endl; - activePlugins.close(); - } - - inline bool isTimestampLoadOrderMethod() { - return GetParam() == Game::tes4 || GetParam() == Game::fo3 || GetParam() == Game::fonv; - } }; // Pass an empty first argument, as it's a prefix for the test instantation, @@ -220,7 +165,7 @@ namespace loot { game.SetGamePath(dataPath.parent_path()); game.Init(false, localPath); - std::vector loadOrder = getExpectedLoadOrder(); + std::vector loadOrder = getInitialLoadOrder(); // First set reverse timestamps to be sure. time_t time = boost::filesystem::last_write_time(dataPath / masterFile); @@ -373,7 +318,7 @@ namespace loot { EXPECT_FALSE(game.IsPluginActive(blankEsp)); } -} + } } #endif diff --git a/src/tests/backend/game/load_order_handler_test.h b/src/tests/backend/game/load_order_handler_test.h new file mode 100644 index 00000000..5832e168 --- /dev/null +++ b/src/tests/backend/game/load_order_handler_test.h @@ -0,0 +1,155 @@ +/* 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_TEST_BACKEND_LOAD_ORDER_HANDLER +#define LOOT_TEST_BACKEND_LOAD_ORDER_HANDLER + +#include "backend/error.h" +#include "backend/game/load_order_handler.h" + +#include "tests/base_game_test.h" + +namespace loot { + namespace test { + class LoadOrderHandlerTest : public BaseGameTest { + protected: + LoadOrderHandler loh; + }; + + // 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_CASE_P(, + LoadOrderHandlerTest, + ::testing::Values( + GameSettings::tes4, + GameSettings::tes5, + GameSettings::fo3, + GameSettings::fonv, + GameSettings::fo4)); + + TEST_P(LoadOrderHandlerTest, initShouldThrowForAnInvalidGameId) { + GameSettings game(GameSettings::autodetect); + game.SetGamePath(dataPath.parent_path()); + + EXPECT_THROW(loh.Init(game), error); + EXPECT_THROW(loh.Init(game), error); + EXPECT_THROW(loh.Init(game, localPath), error); + EXPECT_THROW(loh.Init(game, localPath), error); + } + + TEST_P(LoadOrderHandlerTest, initShouldThrowIfNoGamePathIsSet) { + GameSettings game(GetParam()); + + EXPECT_THROW(loh.Init(game), error); + EXPECT_THROW(loh.Init(game), error); + EXPECT_THROW(loh.Init(game, localPath), error); + EXPECT_THROW(loh.Init(game, localPath), error); + } + +#ifndef _WIN32 + TEST_P(LoadOrderHandlerTest, initShouldThrowOnLinuxIfNoLocalPathIsSet) { + GameSettings game(GetParam()); + game.SetGamePath(dataPath.parent_path()); + + EXPECT_THROW(loh.Init(game), error); + } +#endif + + TEST_P(LoadOrderHandlerTest, initShouldNotThrowIfAValidGameIdAndGamePathAndLocalPathAreSet) { + GameSettings game(GetParam()); + game.SetGamePath(dataPath.parent_path()); + + EXPECT_NO_THROW(loh.Init(game, localPath)); + } + + TEST_P(LoadOrderHandlerTest, isPluginActiveShouldThrowIfTheHandlerHasNotBeenInitialised) { + EXPECT_THROW(loh.IsPluginActive(masterFile), error); + } + + TEST_P(LoadOrderHandlerTest, isPluginActiveShouldReturnCorrectPluginStatesAfterInitialisation) { + GameSettings game(GetParam()); + game.SetGamePath(dataPath.parent_path()); + ASSERT_NO_THROW(loh.Init(game, localPath)); + + EXPECT_TRUE(loh.IsPluginActive(masterFile)); + EXPECT_TRUE(loh.IsPluginActive(blankEsm)); + EXPECT_FALSE(loh.IsPluginActive(blankEsp)); + } + + TEST_P(LoadOrderHandlerTest, getLoadOrderShouldThrowIfTheHandlerHasNotBeenInitialised) { + EXPECT_THROW(loh.GetLoadOrder(), error); + } + + TEST_P(LoadOrderHandlerTest, getLoadOrderShouldReturnTheCurrentLoadOrder) { + GameSettings game(GetParam()); + game.SetGamePath(dataPath.parent_path()); + ASSERT_NO_THROW(loh.Init(game, localPath)); + + ASSERT_EQ(getLoadOrder(), loh.GetLoadOrder()); + } + + TEST_P(LoadOrderHandlerTest, setLoadOrderShouldThrowIfTheHandlerHasNotBeenInitialised) { + std::list loadOrder({ + masterFile, + blankEsm, + blankMasterDependentEsm, + blankDifferentEsm, + blankDifferentMasterDependentEsm, + blankDifferentEsp, + blankDifferentPluginDependentEsp, + blankEsp, + blankMasterDependentEsp, + blankDifferentMasterDependentEsp, + blankPluginDependentEsp, + }); + + EXPECT_THROW(loh.SetLoadOrder(std::list()), error); + } + + TEST_P(LoadOrderHandlerTest, setLoadOrderShouldSetTheLoadOrder) { + GameSettings game(GetParam()); + game.SetGamePath(dataPath.parent_path()); + ASSERT_NO_THROW(loh.Init(game, localPath)); + + std::list loadOrder({ + masterFile, + blankEsm, + blankMasterDependentEsm, + blankDifferentEsm, + blankDifferentMasterDependentEsm, + blankDifferentEsp, + blankDifferentPluginDependentEsp, + blankEsp, + blankMasterDependentEsp, + blankDifferentMasterDependentEsp, + blankPluginDependentEsp, + }); + + EXPECT_NO_THROW(loh.SetLoadOrder(loadOrder)); + EXPECT_EQ(loadOrder, getLoadOrder()); + } + } +} + +#endif diff --git a/src/tests/backend/game/test_load_order_handler.h b/src/tests/backend/game/test_load_order_handler.h deleted file mode 100644 index 41f07aaf..00000000 --- a/src/tests/backend/game/test_load_order_handler.h +++ /dev/null @@ -1,146 +0,0 @@ -/* 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_TEST_BACKEND_LOAD_ORDER_HANDLER -#define LOOT_TEST_BACKEND_LOAD_ORDER_HANDLER - -#include "backend/error.h" -#include "backend/game/load_order_handler.h" - -#include "tests/fixtures.h" - -namespace loot { - namespace test { - class LoadOrderHandlerTest : public SkyrimTest {}; - - TEST_F(LoadOrderHandlerTest, Constructors) { - LoadOrderHandler * loh = nullptr; - EXPECT_NO_THROW(loh = new LoadOrderHandler); - EXPECT_NO_THROW(delete loh); - } - - TEST_F(LoadOrderHandlerTest, Init) { - // Should throw for invalid game settings ID. - LoadOrderHandler loh; - GameSettings game(GameSettings::autodetect); - EXPECT_THROW(loh.Init(game), error); - EXPECT_THROW(loh.Init(game), error); - EXPECT_THROW(loh.Init(game, localPath), error); - EXPECT_THROW(loh.Init(game, localPath), error); - - // Should throw an exception if no game path has been set. - game = GameSettings(GameSettings::tes5); - EXPECT_THROW(loh.Init(game), error); - EXPECT_THROW(loh.Init(game), error); - EXPECT_THROW(loh.Init(game, localPath), error); - EXPECT_THROW(loh.Init(game, localPath), error); - -#ifndef _WIN32 - // Should throw on Linux if no game local app data path is given. - game = GameSettings(GameSettings::tes5) - .SetGamePath(dataPath.parent_path()); - EXPECT_THROW(loh.Init(game), error); -#endif - - game = GameSettings(GameSettings::tes5) - .SetGamePath(dataPath.parent_path()); - EXPECT_NO_THROW(loh.Init(game, localPath)); - } - - TEST_F(LoadOrderHandlerTest, IsPluginActive) { - LoadOrderHandler loh; - GameSettings game(GameSettings::tes5); - game.SetGamePath(dataPath.parent_path()); - - EXPECT_THROW(loh.IsPluginActive("Skyrim.esm"), error); - - ASSERT_NO_THROW(loh.Init(game, localPath)); - - EXPECT_TRUE(loh.IsPluginActive("Skyrim.esm")); - EXPECT_TRUE(loh.IsPluginActive("Blank.esm")); - EXPECT_TRUE(loh.IsPluginActive("Blank - Different Master Dependent.esp")); - EXPECT_FALSE(loh.IsPluginActive("Blank.esp")); - } - - TEST_F(LoadOrderHandlerTest, GetLoadOrder) { - LoadOrderHandler loh; - GameSettings game(GameSettings::tes5); - game.SetGamePath(dataPath.parent_path()); - ASSERT_NO_THROW(loh.Init(game, localPath)); - - std::list expected({ - "Skyrim.esm", - "Blank.esm", - "Blank - Different.esm", - "Blank - Master Dependent.esm", - "Blank - Different Master Dependent.esm", - "Blank.esp", - "Blank - Different.esp", - "Blank - Master Dependent.esp", - "Blank - Different Master Dependent.esp", - "Blank - Plugin Dependent.esp", - "Blank - Different Plugin Dependent.esp" - }); - - EXPECT_EQ(expected, loh.GetLoadOrder()); - } - - TEST_F(LoadOrderHandlerTest, SetLoadOrder) { - LoadOrderHandler loh; - GameSettings game(GameSettings::tes5); - game.SetGamePath(dataPath.parent_path()); - ASSERT_NO_THROW(loh.Init(game, localPath)); - - std::list loadOrder({ - "Skyrim.esm", - "Blank.esm", - "Blank - Master Dependent.esm", - "Blank - Different.esm", - "Blank - Different Master Dependent.esm", - "Blank - Different.esp", - "Blank - Different Plugin Dependent.esp", - "Blank.esp", - "Blank - Master Dependent.esp", - "Blank - Different Master Dependent.esp", - "Blank - Plugin Dependent.esp", - }); - - EXPECT_NO_THROW(loh.SetLoadOrder(loadOrder)); - - std::list actual; - boost::filesystem::ifstream in(localPath / "loadorder.txt"); - while (in) { - std::string line; - std::getline(in, line); - - if (!line.empty()) - actual.push_back(line); - } - - EXPECT_EQ(loadOrder, actual); - } - } -} - -#endif diff --git a/src/tests/base_game_test.h b/src/tests/base_game_test.h index c38507ec..73bfbd68 100644 --- a/src/tests/base_game_test.h +++ b/src/tests/base_game_test.h @@ -27,6 +27,10 @@ along with LOOT. If not, see #include #include +#include +#include + +#include namespace loot { namespace test { @@ -70,12 +74,66 @@ namespace loot { ASSERT_FALSE(boost::filesystem::exists(dataPath / masterFile)); ASSERT_NO_THROW(boost::filesystem::copy_file(dataPath / blankEsm, dataPath / masterFile)); ASSERT_TRUE(boost::filesystem::exists(dataPath / masterFile)); + + // Set initial load order and active plugins. + setLoadOrder(getInitialLoadOrder()); + setActivePlugins(getInitialActivePlugins()); } inline virtual void TearDown() { ASSERT_NO_THROW(boost::filesystem::remove(dataPath / masterFile)); } + inline std::list getLoadOrder() { + std::list actual; + if (isLoadOrderTimestampBased(GetParam())) { + std::map loadOrder; + for (boost::filesystem::directory_iterator it(dataPath); it != boost::filesystem::directory_iterator(); ++it) { + if (boost::filesystem::is_regular_file(it->status()) && + (boost::ends_with(it->path().filename().string(), ".esp") || boost::ends_with(it->path().filename().string(), ".esm"))) { + loadOrder.emplace(boost::filesystem::last_write_time(it->path()), it->path().filename().string()); + } + } + for (const auto& plugin : loadOrder) + actual.push_back(plugin.second); + } + else { + boost::filesystem::ifstream in(localPath / "loadorder.txt"); + while (in) { + std::string line; + std::getline(in, line); + + if (!line.empty()) + actual.push_back(line); + } + } + + return actual; + } + + inline std::vector getInitialLoadOrder() const { + return std::vector({ + masterFile, + blankEsm, + blankDifferentEsm, + blankMasterDependentEsm, + blankDifferentMasterDependentEsm, + blankEsp, + blankDifferentEsp, + blankMasterDependentEsp, + blankDifferentMasterDependentEsp, + blankPluginDependentEsp, + blankDifferentPluginDependentEsp, + }); + } + + inline std::unordered_set getInitialActivePlugins() const { + return std::unordered_set({ + masterFile, + blankEsm, + }); + } + const boost::filesystem::path missingPath; const boost::filesystem::path dataPath; const boost::filesystem::path localPath; @@ -128,6 +186,36 @@ namespace loot { else return 0x187BE342; } + + inline void setLoadOrder(const std::vector& loadOrder) { + if (isLoadOrderTimestampBased(GetParam())) { + time_t modificationTime = time(NULL); // Current time. + for (const auto &plugin : loadOrder) { + if (boost::filesystem::exists(dataPath / boost::filesystem::path(plugin + ".ghost"))) { + boost::filesystem::last_write_time(dataPath / boost::filesystem::path(plugin + ".ghost"), modificationTime); + } + else { + boost::filesystem::last_write_time(dataPath / plugin, modificationTime); + } + modificationTime += 60; + } + } + else { + boost::filesystem::ofstream out(localPath / "loadorder.txt"); + for (const auto &plugin : loadOrder) + out << plugin << std::endl; + } + } + + inline void setActivePlugins(const std::unordered_set& activePlugins) { + boost::filesystem::ofstream out(localPath / "plugins.txt"); + for (const auto &plugin : activePlugins) + out << plugin << std::endl; + } + + inline static bool isLoadOrderTimestampBased(unsigned int gameId) { + return gameId == GameSettings::tes4 || gameId == GameSettings::fo3 || gameId == GameSettings::fonv; + } }; } } diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 2ad2173d..63a8c294 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -44,7 +44,7 @@ #include "backend/game/game_test.h" #include "backend/game/game_cache_test.h" #include "backend/game/game_settings_test.h" -#include "backend/game/test_load_order_handler.h" +#include "backend/game/load_order_handler_test.h" #include "backend/helpers/test_git_helper.h" #include "backend/helpers/test_helpers.h" #include "backend/helpers/test_language.h"