diff --git a/CMakeLists.txt b/CMakeLists.txt index b9bec963..10fb2d9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,7 @@ set (LOOT_GUI_SRC ${LOOT_SRC} "${CMAKE_SOURCE_DIR}/src/gui/handler.cpp" "${CMAKE_SOURCE_DIR}/src/gui/loot_handler.cpp" "${CMAKE_SOURCE_DIR}/src/gui/loot_app.cpp" + "${CMAKE_SOURCE_DIR}/src/gui/loot_settings.cpp" "${CMAKE_SOURCE_DIR}/src/gui/loot_state.cpp" "${CMAKE_SOURCE_DIR}/src/gui/scheme.cpp" "${CMAKE_SOURCE_DIR}/src/resource.rc") @@ -143,6 +144,7 @@ set (LOOT_GUI_HEADERS ${LOOT_HEADERS} "${CMAKE_SOURCE_DIR}/src/gui/handler.h" "${CMAKE_SOURCE_DIR}/src/gui/loot_handler.h" "${CMAKE_SOURCE_DIR}/src/gui/loot_app.h" + "${CMAKE_SOURCE_DIR}/src/gui/loot_settings.h" "${CMAKE_SOURCE_DIR}/src/gui/loot_state.h" "${CMAKE_SOURCE_DIR}/src/gui/scheme.h" "${CMAKE_SOURCE_DIR}/src/gui/resource.h") @@ -160,7 +162,9 @@ set (LOOT_VALIDATOR_SRC ${LOOT_SRC} set (LOOT_VALIDATOR_HEADERS ${LOOT_HEADERS}) -set (LOOT_TESTS_SRC "${CMAKE_SOURCE_DIR}/src/api/loot_db.cpp" +set (LOOT_TESTS_SRC ${LOOT_SRC} + "${CMAKE_SOURCE_DIR}/src/api/loot_db.cpp" + "${CMAKE_SOURCE_DIR}/src/gui/loot_settings.cpp" "${CMAKE_SOURCE_DIR}/src/tests/main.cpp") set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/fixtures.h" @@ -188,7 +192,8 @@ set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/fixtures.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/plugin/test_plugin.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/test_metadata_list.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/test_masterlist.h" - "${CMAKE_SOURCE_DIR}/src/tests/backend/test_plugin_sorter.h") + "${CMAKE_SOURCE_DIR}/src/tests/backend/test_plugin_sorter.h" + "${CMAKE_SOURCE_DIR}/src/tests/gui/test_loot_settings.h") source_group("Header Files" FILES ${LOOT_HEADERS} ${LOOT_GUI_HEADERS} ${LOOT_API_HEADERS} ${LOOT_TESTS_HEADERS}) @@ -309,7 +314,7 @@ target_link_libraries (loot${PROJECT_ARCH} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARI IF (${GTEST_FOUND}) # Build tests. - add_executable(tests ${LOOT_TESTS_SRC} ${LOOT_SRC} ${LOOT_TESTS_HEADERS}) + add_executable(tests ${LOOT_TESTS_SRC} ${LOOT_TESTS_HEADERS}) target_link_libraries(tests loot${PROJECT_ARCH} ${Boost_LIBRARIES} ${YAML_CPP_LIBRARIES} ${LOOT_LIBS} ${GTEST_BOTH_LIBRARIES}) ENDIF () diff --git a/src/backend/game/game_settings.cpp b/src/backend/game/game_settings.cpp index 3682e9c8..6cc25d27 100644 --- a/src/backend/game/game_settings.cpp +++ b/src/backend/game/game_settings.cpp @@ -226,33 +226,6 @@ namespace loot { _gamePath = path; return *this; } - - std::list GetGameSettings(YAML::Node& settings) { - list games; - - if (settings["games"]) - games = settings["games"].as< list >(); - - if (find(games.begin(), games.end(), GameSettings(GameSettings::tes4)) == games.end()) - games.push_back(GameSettings(GameSettings::tes4)); - - if (find(games.begin(), games.end(), GameSettings(GameSettings::tes5)) == games.end()) - games.push_back(GameSettings(GameSettings::tes5)); - - if (find(games.begin(), games.end(), GameSettings(GameSettings::fo3)) == games.end()) - games.push_back(GameSettings(GameSettings::fo3)); - - if (find(games.begin(), games.end(), GameSettings(GameSettings::fonv)) == games.end()) - games.push_back(GameSettings(GameSettings::fonv)); - - if (find(games.begin(), games.end(), GameSettings(GameSettings::fo4)) == games.end()) - games.push_back(GameSettings(GameSettings::fo4)); - - // If there were any missing defaults, make sure they're in settings now. - settings["games"] = games; - - return games; - } } namespace YAML { diff --git a/src/backend/game/game_settings.h b/src/backend/game/game_settings.h index a85e8d80..f5b94879 100644 --- a/src/backend/game/game_settings.h +++ b/src/backend/game/game_settings.h @@ -85,8 +85,6 @@ namespace loot { boost::filesystem::path _gamePath; //Path to the game's folder. }; - - std::list GetGameSettings(YAML::Node& settings); } namespace YAML { diff --git a/src/gui/loot_settings.cpp b/src/gui/loot_settings.cpp new file mode 100644 index 00000000..b4a33016 --- /dev/null +++ b/src/gui/loot_settings.cpp @@ -0,0 +1,295 @@ +/* LOOT + + A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and + Fallout: New Vegas. + + Copyright (C) 2014-2015 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 + . + */ + +#include "loot_settings.h" +#include "backend/globals.h" + +#include + +#include + +using namespace std; + +namespace loot { + LootSettings::WindowPosition::WindowPosition() : top(0), bottom(0), left(0), right(0) {} + + LootSettings::LootSettings() : + gameSettings({ + GameSettings(GameSettings::tes4), + GameSettings(GameSettings::tes5), + GameSettings(GameSettings::fo3), + GameSettings(GameSettings::fonv), + GameSettings(GameSettings::fo4), + GameSettings(GameSettings::tes4, "Nehrim") + .SetName("Nehrim - At Fate's Edge") + .SetMaster("Nehrim.esm") + .SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"), + }), + enableDebugLogging(false), + updateMasterlist(true), + game("auto"), + language(Language(Language::english)), + lastGame("auto"), + lastVersion(std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch)) {} + + void LootSettings::load(YAML::Node& settings) { + std::lock_guard guard(mutex); + + upgradeYaml(settings); + + if (settings["enableDebugLogging"]) + enableDebugLogging = settings["enableDebugLogging"].as(); + if (settings["updateMasterlist"]) + updateMasterlist = settings["updateMasterlist"].as(); + if (settings["game"]) + game = settings["game"].as(); + if (settings["language"]) + language = Language(settings["language"].as()); + if (settings["lastGame"]) + lastGame = settings["lastGame"].as(); + if (settings["lastVersion"]) + lastVersion = settings["lastVersion"].as(); + + if (settings["window"] + && settings["window"]["top"] && settings["window"]["bottom"] + && settings["window"]["left"] && settings["window"]["right"]) { + windowPosition.top = settings["window"]["top"].as(); + windowPosition.bottom = settings["window"]["bottom"].as(); + windowPosition.left = settings["window"]["left"].as(); + windowPosition.right = settings["window"]["right"].as(); + } + + if (settings["games"]) { + gameSettings = settings["games"].as>(); + + // If a base game isn't in the settings, add it. + if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::tes4)) == end(gameSettings)) + gameSettings.push_back(GameSettings(GameSettings::tes4)); + + if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::tes5)) == end(gameSettings)) + gameSettings.push_back(GameSettings(GameSettings::tes5)); + + if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::fo3)) == end(gameSettings)) + gameSettings.push_back(GameSettings(GameSettings::fo3)); + + if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::fonv)) == end(gameSettings)) + gameSettings.push_back(GameSettings(GameSettings::fonv)); + + if (find(begin(gameSettings), end(gameSettings), GameSettings(GameSettings::fo4)) == end(gameSettings)) + gameSettings.push_back(GameSettings(GameSettings::fo4)); + } + + if (settings["filters"]) + filters = settings["filters"].as>(); + } + + void LootSettings::load(const boost::filesystem::path& file) { + boost::filesystem::ifstream in(file); + YAML::Node content = YAML::Load(in); + load(content); + } + + void LootSettings::save(const boost::filesystem::path& file) { + std::lock_guard guard(mutex); + + YAML::Emitter yout; + yout.SetIndent(2); + yout << toYaml(); + + boost::filesystem::ofstream out(file); + out << yout.c_str(); + } + + bool LootSettings::isDebugLoggingEnabled() const { + std::lock_guard guard(mutex); + + return enableDebugLogging; + } + + bool LootSettings::isWindowPositionStored() const { + std::lock_guard guard(mutex); + + return windowPosition.top != 0 || windowPosition.bottom != 0 || windowPosition.left != 0 || windowPosition.right != 0; + } + + std::string LootSettings::getGame() const { + std::lock_guard guard(mutex); + + return game; + } + + std::string LootSettings::getLastGame() const { + std::lock_guard guard(mutex); + + return lastGame; + } + + std::string LootSettings::getLastVersion() const { + std::lock_guard guard(mutex); + + return lastVersion; + } + + const Language& LootSettings::getLanguage() const { + std::lock_guard guard(mutex); + + return language; + } + + const LootSettings::WindowPosition& LootSettings::getWindowPosition() const { + std::lock_guard guard(mutex); + + return windowPosition; + } + + std::vector LootSettings::getGameSettings() const { + std::lock_guard guard(mutex); + + return gameSettings; + } + + void LootSettings::storeLastGame(const std::string& lastGame) { + std::lock_guard guard(mutex); + + this->lastGame = lastGame; + } + + void LootSettings::storeWindowPosition(const WindowPosition& position) { + std::lock_guard guard(mutex); + + windowPosition = position; + } + + void LootSettings::storeGameSettings(const std::vector& gameSettings) { + std::lock_guard guard(mutex); + + this->gameSettings = gameSettings; + } + + void LootSettings::storeFilterState(const std::string& filterId, bool enabled) { + std::lock_guard guard(mutex); + + filters[filterId] = enabled; + } + + void LootSettings::updateLastVersion() { + std::lock_guard guard(mutex); + + lastVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch); + } + + YAML::Node LootSettings::toYaml() const { + std::lock_guard guard(mutex); + + YAML::Node node; + + node["enableDebugLogging"] = enableDebugLogging; + node["updateMasterlist"] = updateMasterlist; + node["game"] = game; + node["language"] = language.Locale(); + node["lastGame"] = lastGame; + node["lastVersion"] = lastVersion; + + if (isWindowPositionStored()) { + node["window"]["top"] = windowPosition.top; + node["window"]["bottom"] = windowPosition.bottom; + node["window"]["left"] = windowPosition.left; + node["window"]["right"] = windowPosition.right; + } + + node["games"] = gameSettings; + + if (!filters.empty()) + node["filters"] = filters; + + return node; + } + + void LootSettings::upgradeYaml(YAML::Node& yaml) { + // Upgrade YAML settings' keys and values from those used in earlier + // versions of LOOT. + + if (yaml["Debug Verbosity"] && !yaml["enableDebugLogging"]) + yaml["enableDebugLogging"] = yaml["Debug Verbosity"].as() > 0; + + if (yaml["Update Masterlist"] && !yaml["updateMasterlist"]) + yaml["updateMasterlist"] = yaml["Update Masterlist"]; + + if (yaml["Game"] && !yaml["game"]) + yaml["game"] = yaml["Game"]; + + if (yaml["Language"] && !yaml["language"]) + yaml["language"] = yaml["Language"]; + + if (yaml["Last Game"] && !yaml["lastGame"]) + yaml["lastGame"] = yaml["Last Game"]; + + if (yaml["Games"] && !yaml["games"]) { + yaml["games"] = yaml["Games"]; + + for (auto node : yaml["games"]) { + if (node["url"]) { + node["repo"] = node["url"]; + node["branch"] = "v0.8"; + } + } + } + + if (yaml["games"]) { + const set oldDefaultBranches({ + "master", + "v0.7", + }); + + // Handle exception if YAML is invalid, eg. if an unrecognised + // game type is used (which can happen if downgrading from a + // later version of LOOT that supports more game types). + // However, can't remove elements from a sequence Node, so have to + // copy the valid elements into a new node then overwrite the + // original. + YAML::Node validGames; + for (auto node : yaml["games"]) { + try { + GameSettings settings(node.as()); + + if (!yaml["Games"]) { + // Update existing default branch, if the default + // repositories are used. + if (settings.RepoURL() == GameSettings(settings.Id()).RepoURL() + && oldDefaultBranches.count(settings.RepoBranch()) == 1) { + settings.SetRepoBranch("v0.8"); + } + } + + validGames.push_back(settings); + } + catch (...) {} + } + yaml["games"] = validGames; + } + + if (yaml["filters"]) + yaml["filters"].remove("contentFilter"); + } +} diff --git a/src/gui/loot_settings.h b/src/gui/loot_settings.h new file mode 100644 index 00000000..ab7a3c8d --- /dev/null +++ b/src/gui/loot_settings.h @@ -0,0 +1,90 @@ +/* LOOT + + A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and + Fallout: New Vegas. + + Copyright (C) 2014-2015 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_GUI_LOOT_SETTINGS +#define LOOT_GUI_LOOT_SETTINGS + +#include "backend/game/game_settings.h" +#include "backend/helpers/language.h" + +#include +#include +#include +#include + +#include +#include + +namespace loot { + class LootSettings { + public: + struct WindowPosition { + WindowPosition(); + + long top; + long bottom; + long left; + long right; + }; + + LootSettings(); + + void load(YAML::Node& settings); + void load(const boost::filesystem::path& file); + void save(const boost::filesystem::path& file); + + bool isDebugLoggingEnabled() const; + bool isWindowPositionStored() const; + std::string getGame() const; + std::string getLastGame() const; + std::string getLastVersion() const; + const Language& getLanguage() const; + const WindowPosition& getWindowPosition() const; + std::vector getGameSettings() const; + + void storeLastGame(const std::string& lastGame); + void storeWindowPosition(const WindowPosition& position); + void storeGameSettings(const std::vector& gameSettings); + void storeFilterState(const std::string& filterId, bool enabled); + void updateLastVersion(); + + YAML::Node toYaml() const; + private: + bool enableDebugLogging; + bool updateMasterlist; + std::string game; + std::string lastGame; + std::string lastVersion; + Language language; + WindowPosition windowPosition; + std::vector gameSettings; + std::map filters; + + mutable std::recursive_mutex mutex; + + static void upgradeYaml(YAML::Node& yaml); + }; +} + +#endif diff --git a/src/tests/backend/game/test_game_settings.h b/src/tests/backend/game/test_game_settings.h index 651cb785..bbc27f30 100644 --- a/src/tests/backend/game/test_game_settings.h +++ b/src/tests/backend/game/test_game_settings.h @@ -251,43 +251,4 @@ TEST_F(GameSettings, YamlDecode) { EXPECT_EQ("branch1", game.RepoBranch()); EXPECT_EQ("", game.GamePath()); } - -TEST(GetGameSettings, AllMissing) { - YAML::Node settings; - - std::list expected = { - loot::GameSettings(loot::GameSettings::tes4), - loot::GameSettings(loot::GameSettings::tes5), - loot::GameSettings(loot::GameSettings::fo3), - loot::GameSettings(loot::GameSettings::fonv), - loot::GameSettings(loot::GameSettings::fo4) - }; - - EXPECT_FALSE(settings["games"]); - EXPECT_EQ(expected, loot::GetGameSettings(settings)); - EXPECT_EQ(expected, settings["games"].as>()); -} - -TEST(GetGameSettings, MissingFallout3) { - std::list initial({ - loot::GameSettings(loot::GameSettings::tes4, "folder1"), - loot::GameSettings(loot::GameSettings::tes5, "folder2"), - loot::GameSettings(loot::GameSettings::fonv, "folder3"), - loot::GameSettings(loot::GameSettings::fo4, "folder4") - }); - - YAML::Node settings; - settings["games"] = initial; - - std::list expected = { - loot::GameSettings(loot::GameSettings::tes4, "folder1"), - loot::GameSettings(loot::GameSettings::tes5, "folder2"), - loot::GameSettings(loot::GameSettings::fonv, "folder3"), - loot::GameSettings(loot::GameSettings::fo4, "folder4"), - loot::GameSettings(loot::GameSettings::fo3) - }; - - EXPECT_EQ(expected, loot::GetGameSettings(settings)); - EXPECT_EQ(expected, settings["games"].as>()); -} #endif diff --git a/src/tests/gui/test_loot_settings.h b/src/tests/gui/test_loot_settings.h new file mode 100644 index 00000000..f96722ba --- /dev/null +++ b/src/tests/gui/test_loot_settings.h @@ -0,0 +1,479 @@ +/* LOOT + +A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and +Fallout: New Vegas. + +Copyright (C) 2014-2015 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_GUI_LOOT_SETTINGS +#define LOOT_TEST_GUI_LOOT_SETTINGS + +#include "gui/loot_settings.h" +#include "backend/globals.h" + +#include "tests/fixtures.h" + +namespace loot { + namespace test { + class LootSettings : public ::testing::Test { + protected: + LootSettings() : settingsFile("./settings.yaml") {} + + ~LootSettings() { + boost::filesystem::remove(settingsFile); + } + + boost::filesystem::path settingsFile; + loot::LootSettings settings; + }; + + TEST_F(LootSettings, defaultConstructorShouldSetDefaultValues) { + const std::string currentVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch); + const std::vector expectedGameSettings({ + GameSettings(GameSettings::tes4), + GameSettings(GameSettings::tes5), + GameSettings(GameSettings::fo3), + GameSettings(GameSettings::fonv), + GameSettings(GameSettings::fo4), + GameSettings(GameSettings::tes4, "Nehrim") + .SetName("Nehrim - At Fate's Edge") + .SetMaster("Nehrim.esm") + .SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"), + }); + + EXPECT_FALSE(settings.isDebugLoggingEnabled()); + EXPECT_EQ("auto", settings.getGame()); + EXPECT_EQ("en", settings.getLanguage().Locale()); + EXPECT_EQ("auto", settings.getLastGame()); + EXPECT_FALSE(settings.isWindowPositionStored()); + + const YAML::Node node = settings.toYaml(); + EXPECT_TRUE(node["updateMasterlist"].as()); + EXPECT_EQ(currentVersion, node["lastVersion"].as()); + EXPECT_FALSE(node["filters"]); + + // GameSettings equality only checks name and folder, so check + // other settings individually. + const std::vector actualGameSettings = settings.getGameSettings(); + EXPECT_EQ(expectedGameSettings, actualGameSettings); + + EXPECT_EQ(expectedGameSettings[0].Id(), actualGameSettings[0].Id()); + EXPECT_EQ(expectedGameSettings[0].Master(), actualGameSettings[0].Master()); + EXPECT_EQ(expectedGameSettings[0].RegistryKey(), actualGameSettings[0].RegistryKey()); + EXPECT_EQ(expectedGameSettings[0].RepoURL(), actualGameSettings[0].RepoURL()); + EXPECT_EQ(expectedGameSettings[0].RepoBranch(), actualGameSettings[0].RepoBranch()); + + EXPECT_EQ(expectedGameSettings[1].Id(), actualGameSettings[1].Id()); + EXPECT_EQ(expectedGameSettings[1].Master(), actualGameSettings[1].Master()); + EXPECT_EQ(expectedGameSettings[1].RegistryKey(), actualGameSettings[1].RegistryKey()); + EXPECT_EQ(expectedGameSettings[1].RepoURL(), actualGameSettings[1].RepoURL()); + EXPECT_EQ(expectedGameSettings[1].RepoBranch(), actualGameSettings[1].RepoBranch()); + + EXPECT_EQ(expectedGameSettings[2].Id(), actualGameSettings[2].Id()); + EXPECT_EQ(expectedGameSettings[2].Master(), actualGameSettings[2].Master()); + EXPECT_EQ(expectedGameSettings[2].RegistryKey(), actualGameSettings[2].RegistryKey()); + EXPECT_EQ(expectedGameSettings[2].RepoURL(), actualGameSettings[2].RepoURL()); + EXPECT_EQ(expectedGameSettings[2].RepoBranch(), actualGameSettings[2].RepoBranch()); + + EXPECT_EQ(expectedGameSettings[3].Id(), actualGameSettings[3].Id()); + EXPECT_EQ(expectedGameSettings[3].Master(), actualGameSettings[3].Master()); + EXPECT_EQ(expectedGameSettings[3].RegistryKey(), actualGameSettings[3].RegistryKey()); + EXPECT_EQ(expectedGameSettings[3].RepoURL(), actualGameSettings[3].RepoURL()); + EXPECT_EQ(expectedGameSettings[3].RepoBranch(), actualGameSettings[3].RepoBranch()); + + EXPECT_EQ(expectedGameSettings[4].Id(), actualGameSettings[4].Id()); + EXPECT_EQ(expectedGameSettings[4].Master(), actualGameSettings[4].Master()); + EXPECT_EQ(expectedGameSettings[4].RegistryKey(), actualGameSettings[4].RegistryKey()); + EXPECT_EQ(expectedGameSettings[4].RepoURL(), actualGameSettings[4].RepoURL()); + EXPECT_EQ(expectedGameSettings[4].RepoBranch(), actualGameSettings[4].RepoBranch()); + + EXPECT_EQ(expectedGameSettings[5].Id(), actualGameSettings[5].Id()); + EXPECT_EQ(expectedGameSettings[5].Master(), actualGameSettings[5].Master()); + EXPECT_EQ(expectedGameSettings[5].RegistryKey(), actualGameSettings[5].RegistryKey()); + EXPECT_EQ(expectedGameSettings[5].RepoURL(), actualGameSettings[5].RepoURL()); + EXPECT_EQ(expectedGameSettings[5].RepoBranch(), actualGameSettings[5].RepoBranch()); + } + + TEST_F(LootSettings, loadingFromFileShouldLoadContentAsYaml) { + boost::filesystem::ofstream out(settingsFile); + out << "enableDebugLogging: true" << std::endl; + out.close(); + + settings.load(settingsFile); + + EXPECT_TRUE(settings.isDebugLoggingEnabled()); + } + + TEST_F(LootSettings, loadingFromYamlShouldStoreLoadedValues) { + const bool enableDebugLogging = true; + const bool updateMasterlist = true; + const std::string game = "Oblivion"; + const std::string language = "fr"; + const std::string lastGame = "Skyrim"; + const std::string lastVersion = "0.7.1"; + const std::map window({ + {"top", 1}, + {"bottom", 2}, + {"left", 3}, + {"right", 4}, + }); + const std::vector games({ + GameSettings(GameSettings::tes4).SetName("Game Name"), + }); + const std::map filters({ + {"hideBashTags", false}, + {"hideCRCs", true}, + }); + + YAML::Node inputYaml; + inputYaml["enableDebugLogging"] = enableDebugLogging; + inputYaml["updateMasterlist"] = updateMasterlist; + inputYaml["game"] = game; + inputYaml["language"] = language; + inputYaml["lastGame"] = lastGame; + inputYaml["lastVersion"] = lastVersion; + inputYaml["window"] = window; + inputYaml["games"] = games; + inputYaml["filters"] = filters; + + settings.load(inputYaml); + + EXPECT_EQ(enableDebugLogging, settings.isDebugLoggingEnabled()); + EXPECT_EQ(game, settings.getGame()); + EXPECT_EQ(language, settings.getLanguage().Locale()); + EXPECT_EQ(lastGame, settings.getLastGame()); + + EXPECT_EQ(1, settings.getWindowPosition().top); + EXPECT_EQ(2, settings.getWindowPosition().bottom); + EXPECT_EQ(3, settings.getWindowPosition().left); + EXPECT_EQ(4, settings.getWindowPosition().right); + + const YAML::Node outputYaml = settings.toYaml(); + EXPECT_EQ(updateMasterlist, outputYaml["updateMasterlist"].as()); + EXPECT_EQ(lastVersion, outputYaml["lastVersion"].as()); + + for (const auto& filter : filters) { + EXPECT_EQ(filter.second, outputYaml["filters"][filter.first].as()); + } + + EXPECT_EQ(games[0].Name(), settings.getGameSettings()[0].Name()); + } + + TEST_F(LootSettings, loadingFromEmptyYamlShouldNotThrow) { + YAML::Node yaml; + EXPECT_NO_THROW(settings.load(yaml)); + } + + TEST_F(LootSettings, loadingFromYamlShouldUpgradeFromVersion0Point6Format) { + const unsigned int DebugVerbosity = 3; + const bool UpdateMasterlist = true; + const std::string Game = "Oblivion"; + const std::string Language = "fr"; + const std::string LastGame = "Skyrim"; + const std::vector Games({ + GameSettings(GameSettings::tes4).SetName("Game Name"), + }); + + YAML::Node inputYaml; + inputYaml["Debug Verbosity"] = DebugVerbosity; + inputYaml["Update Masterlist"] = UpdateMasterlist; + inputYaml["Game"] = Game; + inputYaml["Language"] = Language; + inputYaml["Last Game"] = LastGame; + + inputYaml["Games"] = Games; + inputYaml["Games"][0]["url"] = inputYaml["Games"][0]["repo"]; + inputYaml["Games"][0].remove("repo"); + inputYaml["Games"][0].remove("branch"); + + settings.load(inputYaml); + + const YAML::Node outputYaml = settings.toYaml(); + EXPECT_TRUE(settings.isDebugLoggingEnabled()); + EXPECT_EQ(UpdateMasterlist, outputYaml["updateMasterlist"].as()); + EXPECT_EQ(Game, settings.getGame()); + EXPECT_EQ(Language, settings.getLanguage().Locale()); + EXPECT_EQ(LastGame, settings.getLastGame()); + + EXPECT_EQ(Games[0].Name(), settings.getGameSettings()[0].Name()); + EXPECT_EQ(Games[0].RepoURL(), settings.getGameSettings()[0].RepoURL()); + EXPECT_EQ(Games[0].RepoBranch(), settings.getGameSettings()[0].RepoBranch()); + } + + TEST_F(LootSettings, loadingFromYamlShouldNotUpgradeVersion0Point6SettingsIfEquivalentsAlreadyExist) { + const unsigned int DebugVerbosity = 3; + const bool enableDebugLogging = false; + const bool UpdateMasterlist = true; + const bool updateMasterlist = false; + const std::string Game = "Oblivion"; + const std::string game = "auto"; + const std::string Language = "fr"; + const std::string language = "en"; + const std::string LastGame = "Skyrim"; + const std::string lastGame = "auto"; + const std::vector Games({ + GameSettings(GameSettings::tes4).SetName("Old Game Name"), + }); + const std::vector games({ + GameSettings(GameSettings::fo3).SetName("Game Name"), + }); + + YAML::Node inputYaml; + inputYaml["Debug Verbosity"] = DebugVerbosity; + inputYaml["enableDebugLogging"] = enableDebugLogging; + inputYaml["Update Masterlist"] = UpdateMasterlist; + inputYaml["updateMasterlist"] = updateMasterlist; + inputYaml["Game"] = Game; + inputYaml["game"] = game; + inputYaml["Language"] = Language; + inputYaml["language"] = language; + inputYaml["Last Game"] = LastGame; + inputYaml["lastGame"] = lastGame; + + inputYaml["Games"] = Games; + inputYaml["Games"][0]["url"] = inputYaml["Games"][0]["repo"]; + inputYaml["Games"][0].remove("repo"); + inputYaml["Games"][0].remove("branch"); + inputYaml["games"] = games; + + settings.load(inputYaml); + + const YAML::Node outputYaml = settings.toYaml(); + + EXPECT_EQ(enableDebugLogging, settings.isDebugLoggingEnabled()); + EXPECT_EQ(updateMasterlist, outputYaml["updateMasterlist"].as()); + EXPECT_EQ(game, settings.getGame()); + EXPECT_EQ(language, settings.getLanguage().Locale()); + EXPECT_EQ(lastGame, settings.getLastGame()); + + EXPECT_EQ(games[0].Name(), settings.getGameSettings()[0].Name()); + } + + TEST_F(LootSettings, loadingFromYamlShouldUpgradeOldDefaultGameRepositoryBranches) { + const std::vector games({GameSettings(GameSettings::tes4)}); + + YAML::Node inputYaml; + inputYaml["games"] = games; + inputYaml["games"][0]["branch"] = "v0.7"; + + settings.load(inputYaml); + + EXPECT_EQ(games[0].RepoBranch(), settings.getGameSettings()[0].RepoBranch()); + } + + TEST_F(LootSettings, loadingFromYamlShouldNotUpgradeNonDefaultGameRepositoryBranches) { + const std::vector games({GameSettings(GameSettings::tes4)}); + + YAML::Node inputYaml; + inputYaml["games"] = games; + inputYaml["games"][0]["branch"] = "foo"; + + settings.load(inputYaml); + + EXPECT_EQ("foo", settings.getGameSettings()[0].RepoBranch()); + } + + TEST_F(LootSettings, loadingFromYamlShouldAddMissingBaseGames) { + const std::vector games({GameSettings(GameSettings::tes4)}); + YAML::Node inputYaml; + inputYaml["games"] = games; + + settings.load(inputYaml); + + const std::vector expectedGameSettings({ + GameSettings(GameSettings::tes4), + GameSettings(GameSettings::tes5), + GameSettings(GameSettings::fo3), + GameSettings(GameSettings::fonv), + GameSettings(GameSettings::fo4), + }); + EXPECT_EQ(expectedGameSettings, settings.getGameSettings()); + } + + TEST_F(LootSettings, loadingFromYamlShouldSkipUnrecognisedGames) { + YAML::Node inputYaml; + inputYaml["games"][0] = GameSettings(GameSettings::tes4); + inputYaml["games"][0]["type"] = "Foobar"; + inputYaml["games"][0]["name"] = "Foobar"; + inputYaml["games"][1] = GameSettings(GameSettings::tes5).SetName("Game Name"); + + settings.load(inputYaml); + + EXPECT_EQ("Game Name", settings.getGameSettings()[0].Name()); + } + + TEST_F(LootSettings, loadingFromYamlShouldRemoveTheContentFilterSetting) { + YAML::Node inputYaml; + inputYaml["filters"]["contentFilter"] = "foo"; + + settings.load(inputYaml); + } + + TEST_F(LootSettings, saveShouldWriteSettingsAsYamlToPassedFile) { + settings.storeLastGame("Skyrim"); + settings.save(settingsFile); + + settings.storeLastGame("auto"); + settings.load(settingsFile); + + EXPECT_EQ("Skyrim", settings.getLastGame()); + } + + TEST_F(LootSettings, getLanguageShouldReturnTheCurrentValue) { + YAML::Node inputYaml; + inputYaml["language"] = "fr"; + + settings.load(inputYaml); + + EXPECT_EQ("fr", settings.getLanguage().Locale()); + } + + TEST_F(LootSettings, isWindowPositionStoredShouldReturnFalseIfAllPositionValuesAreZero) { + loot::LootSettings::WindowPosition position; + settings.storeWindowPosition(position); + + EXPECT_FALSE(settings.isWindowPositionStored()); + } + + TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfTopPositionValueIsNonZero) { + loot::LootSettings::WindowPosition position; + position.top = 1; + settings.storeWindowPosition(position); + + EXPECT_TRUE(settings.isWindowPositionStored()); + } + + TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfBottomPositionValueIsNonZero) { + loot::LootSettings::WindowPosition position; + position.bottom = 1; + settings.storeWindowPosition(position); + + EXPECT_TRUE(settings.isWindowPositionStored()); + } + + TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfLeftPositionValueIsNonZero) { + loot::LootSettings::WindowPosition position; + position.left = 1; + settings.storeWindowPosition(position); + + EXPECT_TRUE(settings.isWindowPositionStored()); + } + + TEST_F(LootSettings, isWindowPositionStoredShouldReturnTrueIfRightPositionValueIsNonZero) { + loot::LootSettings::WindowPosition position; + position.right = 1; + settings.storeWindowPosition(position); + + EXPECT_TRUE(settings.isWindowPositionStored()); + } + + TEST_F(LootSettings, storeGameSettingsShouldReplaceExistingGameSettings) { + const std::vector gameSettings({GameSettings(GameSettings::tes5)}); + settings.storeGameSettings(gameSettings); + + EXPECT_EQ(gameSettings, settings.getGameSettings()); + } + + TEST_F(LootSettings, storeLastGameShouldReplaceExistingValue) { + settings.storeLastGame("Fallout3"); + + EXPECT_EQ("Fallout3", settings.getLastGame()); + } + + TEST_F(LootSettings, storeWindowPositionShouldReplaceExistingValue) { + loot::LootSettings::WindowPosition expectedPosition; + expectedPosition.top = 1; + settings.storeWindowPosition(expectedPosition); + + loot::LootSettings::WindowPosition actualPosition = settings.getWindowPosition(); + EXPECT_EQ(expectedPosition.top, actualPosition.top); + EXPECT_EQ(expectedPosition.bottom, actualPosition.bottom); + EXPECT_EQ(expectedPosition.left, actualPosition.left); + EXPECT_EQ(expectedPosition.right, actualPosition.right); + } + + TEST_F(LootSettings, updateLastVersionShouldSetValueToCurrentLootVersion) { + const std::string currentVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch); + YAML::Node inputYaml; + inputYaml["lastVersion"] = "v0.7.1"; + + settings.load(inputYaml); + settings.updateLastVersion(); + + EXPECT_EQ(currentVersion, settings.getLastVersion()); + } + + TEST_F(LootSettings, toYamlShouldOutputStoredSettings) { + const bool enableDebugLogging = true; + const bool updateMasterlist = true; + const std::string game = "Oblivion"; + const std::string language = "fr"; + const std::string lastGame = "Skyrim"; + const std::string lastVersion = "0.7.1"; + const std::map window({ + {"top", 1}, + {"bottom", 2}, + {"left", 3}, + {"right", 4}, + }); + const std::vector games({ + GameSettings(GameSettings::tes4).SetName("Game Name"), + }); + const std::map filters({ + {"hideBashTags", false}, + {"hideCRCs", true}, + }); + + YAML::Node inputYaml; + inputYaml["enableDebugLogging"] = enableDebugLogging; + inputYaml["updateMasterlist"] = updateMasterlist; + inputYaml["game"] = game; + inputYaml["language"] = language; + inputYaml["lastGame"] = lastGame; + inputYaml["lastVersion"] = lastVersion; + inputYaml["window"] = window; + inputYaml["games"] = games; + inputYaml["filters"] = filters; + + settings.load(inputYaml); + + const YAML::Node outputYaml = settings.toYaml(); + + EXPECT_EQ(enableDebugLogging, outputYaml["enableDebugLogging"].as()); + EXPECT_EQ(updateMasterlist, outputYaml["updateMasterlist"].as()); + EXPECT_EQ(game, outputYaml["game"].as()); + EXPECT_EQ(language, outputYaml["language"].as()); + EXPECT_EQ(lastGame, outputYaml["lastGame"].as()); + EXPECT_EQ(lastVersion, outputYaml["lastVersion"].as()); + + for (const auto& position : window) { + EXPECT_EQ(position.second, outputYaml["window"][position.first].as()); + } + + for (const auto& filter : filters) { + EXPECT_EQ(filter.second, outputYaml["filters"][filter.first].as()); + } + + EXPECT_EQ(games[0].Name(), outputYaml["games"][0]["name"].as()); + } + } +} + +#endif diff --git a/src/tests/main.cpp b/src/tests/main.cpp index ea814bea..78023cc1 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -51,6 +51,7 @@ #include "backend/test_metadata_list.h" #include "backend/test_masterlist.h" #include "backend/test_plugin_sorter.h" +#include "gui/test_loot_settings.h" #include