From eeb6ed40c7a52d8a0d909d5610fa44442cf39d61 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 24 Mar 2018 07:20:47 +0000 Subject: [PATCH] Add UndefinedGroupError for better sorting exception handling --- CMakeLists.txt | 1 + docs/api/reference.rst | 3 + include/loot/api.h | 1 + .../loot/exception/undefined_group_error.h | 58 +++++++++++++++++++ src/api/sorting/group_sort.cpp | 3 +- src/api/sorting/plugin_sorter.cpp | 4 +- .../api/internals/sorting/group_sort_test.h | 3 +- .../internals/sorting/plugin_sorter_test.h | 3 +- 8 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 include/loot/exception/undefined_group_error.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ca81fad1..f6850e84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,6 +198,7 @@ set (LOOT_API_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h" "${CMAKE_SOURCE_DIR}/include/loot/exception/cyclic_interaction_error.h" "${CMAKE_SOURCE_DIR}/include/loot/exception/file_access_error.h" "${CMAKE_SOURCE_DIR}/include/loot/exception/git_state_error.h" + "${CMAKE_SOURCE_DIR}/include/loot/exception/undefined_group_error.h" "${CMAKE_SOURCE_DIR}/include/loot/enum/game_type.h" "${CMAKE_SOURCE_DIR}/include/loot/enum/log_level.h" "${CMAKE_SOURCE_DIR}/include/loot/enum/message_type.h" diff --git a/docs/api/reference.rst b/docs/api/reference.rst index 8f4cdff6..3a5ccb4d 100644 --- a/docs/api/reference.rst +++ b/docs/api/reference.rst @@ -96,6 +96,9 @@ Exceptions .. doxygenclass:: loot::FileAccessError :members: +.. doxygenclass:: loot::UndefinedGroupError + :members: + Error Categories ================ diff --git a/include/loot/api.h b/include/loot/api.h index b8990c27..f017be27 100644 --- a/include/loot/api.h +++ b/include/loot/api.h @@ -37,6 +37,7 @@ #include "loot/exception/error_categories.h" #include "loot/exception/file_access_error.h" #include "loot/exception/git_state_error.h" +#include "loot/exception/undefined_group_error.h" #include "loot/game_interface.h" #include "loot/loot_version.h" diff --git a/include/loot/exception/undefined_group_error.h b/include/loot/exception/undefined_group_error.h new file mode 100644 index 00000000..30e8208f --- /dev/null +++ b/include/loot/exception/undefined_group_error.h @@ -0,0 +1,58 @@ +/* LOOT + + A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and + Fallout: New Vegas. + + Copyright (C) 2012-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_EXCEPTION_UNDEFINED_GROUP_ERROR +#define LOOT_EXCEPTION_UNDEFINED_GROUP_ERROR + +#include + +namespace loot { +/** + * @brief An exception class thrown if group is referenced but is undefined. + */ +class UndefinedGroupError : public std::runtime_error { +public: + /** + * @brief Construct an exception detailing a plugin graph cycle. + * @param firstPlugin A plugin in the cycle. + * @param lastPlugin Another plugin in the cycle. + * @param backCycle A string describing the path from lastPlugin to + * firstPlugin. + */ + UndefinedGroupError(const std::string& groupName) : + std::runtime_error("The group \"" + groupName + "\" does not exist"), + groupName_(groupName) {} + + /** + * Get the name of the undefined group. + * @return A group name. + */ + std::string getGroupName() { return groupName_; } + +private: + const std::string groupName_; +}; +} + +#endif diff --git a/src/api/sorting/group_sort.cpp b/src/api/sorting/group_sort.cpp index bb674249..d317f783 100644 --- a/src/api/sorting/group_sort.cpp +++ b/src/api/sorting/group_sort.cpp @@ -29,6 +29,7 @@ #include #include "loot/exception/cyclic_interaction_error.h" +#include "loot/exception/undefined_group_error.h" namespace loot { typedef boost::adjacency_list> GetTransitiveAf for (const auto& otherGroupName : group.GetAfterGroups()) { auto otherVertex = groupVertices.find(otherGroupName); if (otherVertex == groupVertices.end()) { - throw std::invalid_argument("The group \"" + otherGroupName + "\" does not exist"); + throw UndefinedGroupError(otherGroupName); } auto vertex = groupVertices[group.GetName()]; diff --git a/src/api/sorting/plugin_sorter.cpp b/src/api/sorting/plugin_sorter.cpp index 033ab04a..2069b669 100644 --- a/src/api/sorting/plugin_sorter.cpp +++ b/src/api/sorting/plugin_sorter.cpp @@ -37,6 +37,7 @@ #include "api/metadata/condition_evaluator.h" #include "api/sorting/group_sort.h" #include "loot/exception/cyclic_interaction_error.h" +#include "loot/exception/undefined_group_error.h" using std::list; using std::string; @@ -266,8 +267,7 @@ void PluginSorter::AddPluginVertices(Game& game) { PluginSortingData& plugin = graph_[vertex]; auto groupsIt = groups.find(plugin.GetGroup()); if (groupsIt == groups.end()) { - throw std::invalid_argument("The group \"" + plugin.GetGroup() + - "\" set for plugin \"" + plugin.GetName() + "\" does not exist."); + throw UndefinedGroupError(plugin.GetGroup()); } else { plugin.SetAfterGroupPlugins(groupsIt->second); diff --git a/src/tests/api/internals/sorting/group_sort_test.h b/src/tests/api/internals/sorting/group_sort_test.h index ffd8144c..8056f4e8 100644 --- a/src/tests/api/internals/sorting/group_sort_test.h +++ b/src/tests/api/internals/sorting/group_sort_test.h @@ -30,6 +30,7 @@ along with LOOT. If not, see #include #include "loot/exception/cyclic_interaction_error.h" +#include "loot/exception/undefined_group_error.h" namespace loot { namespace test { @@ -52,7 +53,7 @@ TEST(GetTransitiveAfterGroups, shouldThrowIfAnAfterGroupDoesNotExist) { Group("b", std::unordered_set({ "a" })) }); - EXPECT_THROW(GetTransitiveAfterGroups(groups), std::invalid_argument); + EXPECT_THROW(GetTransitiveAfterGroups(groups), UndefinedGroupError); } TEST(GetTransitiveAfterGroups, shouldThrowIfAfterGroupsAreCyclic) { diff --git a/src/tests/api/internals/sorting/plugin_sorter_test.h b/src/tests/api/internals/sorting/plugin_sorter_test.h index 31c88599..fd3a423b 100644 --- a/src/tests/api/internals/sorting/plugin_sorter_test.h +++ b/src/tests/api/internals/sorting/plugin_sorter_test.h @@ -28,6 +28,7 @@ along with LOOT. If not, see #include "api/sorting/plugin_sorter.h" #include "loot/exception/cyclic_interaction_error.h" +#include "loot/exception/undefined_group_error.h" #include "tests/common_game_test_fixture.h" namespace loot { @@ -207,7 +208,7 @@ TEST_P(PluginSorterTest, sortingShouldThrowIfAPluginHasAGroupThatDoesNotExist) { game_.GetDatabase()->SetPluginUserMetadata(plugin); PluginSorter ps; - EXPECT_THROW(ps.Sort(game_), std::invalid_argument); + EXPECT_THROW(ps.Sort(game_), UndefinedGroupError); } TEST_P(PluginSorterTest, sortingShouldThrowIfAddingTwoGroupEdgesIntroducesACycle) {