Differentiate between load after and requirement metadata sources

When reporting a cyclic interaction error.
This commit is contained in:
Oliver Hamlet
2018-10-20 12:48:23 +01:00
parent 5250cb3696
commit e06ce7efee
9 changed files with 271 additions and 114 deletions
@@ -38,8 +38,10 @@ enum struct EdgeType : unsigned int {
Hardcoded,
MasterFlag,
Master,
Requirement,
LoadAfter,
MasterlistRequirement,
UserRequirement,
MasterlistLoadAfter,
UserLoadAfter,
Group,
Overlap,
TieBreak,
@@ -62,7 +64,7 @@ public:
/**
* @brief Get the name of the plugin or group.
* @return The name of the plugin or group.
*/
*/
std::string GetName() const;
/**
@@ -70,8 +72,9 @@ public:
* @details Each edge goes from the vertex that loads earlier to the vertex
* that loads later.
* @return The edge type.
*/
*/
EdgeType GetTypeOfEdgeToNextVertex() const;
private:
std::string name_;
EdgeType outEdgeType_;
+29 -27
View File
@@ -24,45 +24,47 @@
#include "loot/exception/cyclic_interaction_error.h"
namespace loot {
Vertex::Vertex(std::string name, EdgeType outEdgeType) : name_(name), outEdgeType_(outEdgeType) {}
Vertex::Vertex(std::string name, EdgeType outEdgeType) :
name_(name),
outEdgeType_(outEdgeType) {}
std::string Vertex::GetName() const {
return name_;
}
std::string Vertex::GetName() const { return name_; }
EdgeType Vertex::GetTypeOfEdgeToNextVertex() const {
return outEdgeType_;
}
EdgeType Vertex::GetTypeOfEdgeToNextVertex() const { return outEdgeType_; }
std::string describe(EdgeType edgeType) {
switch (edgeType) {
case EdgeType::Hardcoded:
return "Hardcoded";
case EdgeType::MasterFlag:
return "Master Flag";
case EdgeType::Master:
return "Master";
case EdgeType::Requirement:
return "Requirement";
case EdgeType::LoadAfter:
return "Load After";
case EdgeType::Group:
return "Group";
case EdgeType::Overlap:
return "Overlap";
case EdgeType::TieBreak:
return "Tie Break";
default:
return "Unknown";
case EdgeType::Hardcoded:
return "Hardcoded";
case EdgeType::MasterFlag:
return "Master Flag";
case EdgeType::Master:
return "Master";
case EdgeType::MasterlistRequirement:
return "Masterlist Requirement";
case EdgeType::UserRequirement:
return "User Requirement";
case EdgeType::MasterlistLoadAfter:
return "Masterlist Load After";
case EdgeType::UserLoadAfter:
return "User Load After";
case EdgeType::Group:
return "Group";
case EdgeType::Overlap:
return "Overlap";
case EdgeType::TieBreak:
return "Tie Break";
default:
return "Unknown";
}
}
// A.esp --[Master Flag]-> B.esp --Group->
std::string describeCycle(const std::vector<Vertex>& cycle) {
std::string text;
for (const auto& vertex : cycle) {
text += vertex.GetName() + " --[" + describe(vertex.GetTypeOfEdgeToNextVertex()) + "]-> ";
text += vertex.GetName() + " --[" +
describe(vertex.GetTypeOfEdgeToNextVertex()) + "]-> ";
}
if (!cycle.empty()) {
text += cycle[0].GetName();
+97 -26
View File
@@ -25,19 +25,49 @@
#include "group_sort.h"
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/graph_traits.hpp>
#include "api/helpers/logging.h"
#include "loot/exception/cyclic_interaction_error.h"
#include "loot/exception/undefined_group_error.h"
#include "api/helpers/logging.h"
namespace loot {
class GroupSortingData {
public:
GroupSortingData() {}
GroupSortingData(std::string name) : name_(name) {}
std::string GetName() const { return name_; }
std::unordered_set<std::string> GetMasterlistAfterGroups() const {
return masterlistAfterGroups_;
}
std::unordered_set<std::string> GetUserAfterGroups() const {
return userAfterGroups_;
}
void SetMasterlistAfterGroups(std::unordered_set<std::string> groups) {
masterlistAfterGroups_ = groups;
}
void SetUserAfterGroups(std::unordered_set<std::string> groups) {
userAfterGroups_ = groups;
}
private:
std::string name_;
std::unordered_set<std::string> masterlistAfterGroups_;
std::unordered_set<std::string> userAfterGroups_;
};
typedef boost::adjacency_list<boost::vecS,
boost::vecS,
boost::directedS,
std::string,
EdgeType> GroupGraph;
GroupSortingData,
EdgeType>
GroupGraph;
typedef boost::graph_traits<GroupGraph>::vertex_descriptor vertex_t;
typedef boost::graph_traits<GroupGraph>::edge_descriptor edge_t;
@@ -46,11 +76,11 @@ public:
void tree_edge(edge_t edge, const GroupGraph& graph) {
auto source = boost::source(edge, graph);
auto vertex = Vertex(graph[source], graph[edge]);
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
// Check if the plugin already exists in the recorded trail.
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
return v.GetName() == graph[source];
return v.GetName() == graph[source].GetName();
});
if (it != end(trail)) {
@@ -66,11 +96,11 @@ public:
auto source = boost::source(edge, graph);
auto target = boost::target(edge, graph);
auto vertex = Vertex(graph[source], graph[edge]);
auto vertex = Vertex(graph[source].GetName(), graph[edge]);
trail.push_back(vertex);
auto it = find_if(begin(trail), end(trail), [&](const Vertex& v) {
return v.GetName() == graph[target];
return v.GetName() == graph[target].GetName();
});
if (it != trail.end()) {
@@ -84,20 +114,22 @@ private:
class AfterGroupsVisitor : public boost::dfs_visitor<> {
public:
AfterGroupsVisitor(std::unordered_set<std::string>& visitedGroups) : visitedGroups_(visitedGroups) {}
AfterGroupsVisitor(std::unordered_set<std::string>& visitedGroups) :
visitedGroups_(visitedGroups) {}
void tree_edge(edge_t edge, const GroupGraph& graph) {
auto target = boost::target(edge, graph);
visitedGroups_.insert(graph[target]);
visitedGroups_.insert(graph[target].GetName());
}
std::unordered_set<std::string> get_visited_groups() const {
return visitedGroups_;
}
private:
std::unordered_set<std::string>& visitedGroups_;
};
std::string join(const std::unordered_set<std::string> set) {
std::string join(const std::unordered_set<std::string>& set) {
std::string output;
for (const auto& element : set) {
output += element + ", ";
@@ -106,7 +138,9 @@ std::string join(const std::unordered_set<std::string> set) {
return output.substr(0, output.length() - 2);
}
std::unordered_map<std::string, std::unordered_set<std::string>> GetTransitiveAfterGroups(const std::unordered_set<Group> groups) {
std::unordered_map<std::string, std::unordered_set<std::string>>
GetTransitiveAfterGroups(const std::unordered_set<Group>& masterlistGroups,
const std::unordered_set<Group>& userGroups) {
GroupGraph graph;
auto logger = getLogger();
@@ -115,24 +149,59 @@ std::unordered_map<std::string, std::unordered_set<std::string>> GetTransitiveAf
}
std::unordered_map<std::string, vertex_t> groupVertices;
for (const auto& group : groups) {
auto vertex = boost::add_vertex(group.GetName(), graph);
for (const auto& group : masterlistGroups) {
auto groupSortingData = GroupSortingData(group.GetName());
groupSortingData.SetMasterlistAfterGroups(group.GetAfterGroups());
auto vertex = boost::add_vertex(groupSortingData, graph);
groupVertices.emplace(group.GetName(), vertex);
}
for (const auto& group : userGroups) {
auto it = groupVertices.find(group.GetName());
if (it != groupVertices.end()) {
graph[it->second].SetUserAfterGroups(group.GetAfterGroups());
} else {
auto groupSortingData = GroupSortingData(group.GetName());
groupSortingData.SetUserAfterGroups(group.GetAfterGroups());
auto vertex = boost::add_vertex(groupSortingData, graph);
groupVertices.emplace(group.GetName(), vertex);
}
}
for (const auto& group : groups) {
for (const vertex_t& vertex :
boost::make_iterator_range(boost::vertices(graph))) {
auto group = graph[vertex];
if (logger) {
logger->trace("Group \"{}\" directly loads after groups \"{}\"",
group.GetName(), join(group.GetAfterGroups()));
logger->trace(
"Group \"{}\" directly loads after masterlist groups \"{}\" and user "
"groups \"{}\"",
group.GetName(),
join(group.GetMasterlistAfterGroups()),
join(group.GetUserAfterGroups()));
}
for (const auto& otherGroupName : group.GetAfterGroups()) {
for (const auto& otherGroupName : group.GetMasterlistAfterGroups()) {
auto otherVertex = groupVertices.find(otherGroupName);
if (otherVertex == groupVertices.end()) {
throw UndefinedGroupError(otherGroupName);
}
auto vertex = groupVertices[group.GetName()];
boost::add_edge(vertex, otherVertex->second, EdgeType::LoadAfter, graph);
boost::add_edge(
vertex, otherVertex->second, EdgeType::MasterlistLoadAfter, graph);
}
for (const auto& otherGroupName : group.GetUserAfterGroups()) {
auto otherVertex = groupVertices.find(otherGroupName);
if (otherVertex == groupVertices.end()) {
throw UndefinedGroupError(otherGroupName);
}
auto vertex = groupVertices[group.GetName()];
boost::add_edge(
vertex, otherVertex->second, EdgeType::UserLoadAfter, graph);
}
}
@@ -142,23 +211,25 @@ std::unordered_map<std::string, std::unordered_set<std::string>> GetTransitiveAf
}
boost::depth_first_search(graph, boost::visitor(CycleDetector()));
std::unordered_map<std::string, std::unordered_set<std::string>> transitiveAfterGroups;
for (const vertex_t& vertex : boost::make_iterator_range(boost::vertices(graph))) {
std::unordered_map<std::string, std::unordered_set<std::string>>
transitiveAfterGroups;
for (const vertex_t& vertex :
boost::make_iterator_range(boost::vertices(graph))) {
std::unordered_set<std::string> visitedGroups;
AfterGroupsVisitor afterGroupsVisitor(visitedGroups);
// Create a color map.
std::vector<boost::default_color_type> colorVec(boost::num_vertices(graph));
auto colorMap = boost::make_iterator_property_map(colorVec.begin(),
boost::get(boost::vertex_index, graph),
colorVec[0]);
auto colorMap = boost::make_iterator_property_map(
colorVec.begin(), boost::get(boost::vertex_index, graph), colorVec[0]);
boost::depth_first_visit(graph, vertex, afterGroupsVisitor, colorMap);
transitiveAfterGroups[graph[vertex]] = visitedGroups;
transitiveAfterGroups[graph[vertex].GetName()] = visitedGroups;
if (logger) {
logger->trace("Group \"{}\" transitively loads after groups \"{}\"",
graph[vertex], join(visitedGroups));
graph[vertex].GetName(),
join(visitedGroups));
}
}
+3 -1
View File
@@ -33,6 +33,8 @@
namespace loot {
// Map entries are a group name and names of transitive load after groups.
std::unordered_map<std::string, std::unordered_set<std::string>> GetTransitiveAfterGroups(const std::unordered_set<Group> groups);
std::unordered_map<std::string, std::unordered_set<std::string>>
GetTransitiveAfterGroups(const std::unordered_set<Group>& masterlistGroups,
const std::unordered_set<Group>& userGroups);
}
#endif
+28 -16
View File
@@ -208,15 +208,22 @@ void PluginSorter::AddPluginVertices(Game& game) {
for (const auto& plugin : game.GetCache()->GetPlugins()) {
if (logger_) {
logger_->trace("Getting and evaluating metadata for plugin {}",
logger_->trace("Getting and evaluating metadata for plugin \"{}\"",
plugin->GetName());
}
auto metadata = game.GetDatabase()
->GetPluginMetadata(plugin->GetName(), true, true)
.value_or(PluginMetadata(plugin->GetName()));
auto masterlistMetadata =
game.GetDatabase()
->GetPluginMetadata(plugin->GetName(), false, true)
.value_or(PluginMetadata(plugin->GetName()));
auto userMetadata = game.GetDatabase()
->GetPluginUserMetadata(plugin->GetName(), true)
.value_or(PluginMetadata(plugin->GetName()));
auto groupName = metadata.GetGroup().value_or(Group().GetName());
auto pluginSortingData =
PluginSortingData(*plugin, masterlistMetadata, userMetadata);
auto groupName = pluginSortingData.GetGroup();
auto groupIt = groupPlugins.find(groupName);
if (groupIt == groupPlugins.end()) {
groupPlugins.emplace(groupName,
@@ -225,18 +232,15 @@ void PluginSorter::AddPluginVertices(Game& game) {
groupIt->second.push_back(plugin->GetName());
}
if (logger_) {
logger_->trace("Getting and evaluating metadata for plugin \"{}\"",
plugin->GetName());
}
boost::add_vertex(PluginSortingData(*plugin, std::move(metadata)), graph_);
boost::add_vertex(pluginSortingData, graph_);
}
// Map sets of transitive group dependencies to sets of transitive plugin
// dependencies.
groups_ = game.GetDatabase()->GetGroups();
auto groups = GetTransitiveAfterGroups(groups_);
auto groups = GetTransitiveAfterGroups(game.GetDatabase()->GetGroups(false),
game.GetDatabase()->GetUserGroups());
for (auto& group : groups) {
std::unordered_set<std::string> transitivePlugins;
for (const auto& afterGroup : group.second) {
@@ -465,17 +469,25 @@ void PluginSorter::AddSpecificEdges() {
if (logger_) {
logger_->trace("Adding in-edges for requirements.");
}
for (const auto& file : graph_[*vit].GetRequirements()) {
for (const auto& file : graph_[*vit].GetMasterlistRequirements()) {
if (GetVertexByName(file.GetName(), parentVertex))
AddEdge(parentVertex, *vit, EdgeType::Requirement);
AddEdge(parentVertex, *vit, EdgeType::MasterlistRequirement);
}
for (const auto& file : graph_[*vit].GetUserRequirements()) {
if (GetVertexByName(file.GetName(), parentVertex))
AddEdge(parentVertex, *vit, EdgeType::UserRequirement);
}
if (logger_) {
logger_->trace("Adding in-edges for 'load after's.");
}
for (const auto& file : graph_[*vit].GetLoadAfterFiles()) {
for (const auto& file : graph_[*vit].GetMasterlistLoadAfterFiles()) {
if (GetVertexByName(file.GetName(), parentVertex))
AddEdge(parentVertex, *vit, EdgeType::LoadAfter);
AddEdge(parentVertex, *vit, EdgeType::MasterlistLoadAfter);
}
for (const auto& file : graph_[*vit].GetUserLoadAfterFiles()) {
if (GetVertexByName(file.GetName(), parentVertex))
AddEdge(parentVertex, *vit, EdgeType::UserLoadAfter);
}
}
}
+39 -5
View File
@@ -25,18 +25,34 @@
#include "plugin_sorting_data.h"
#include <boost/algorithm/string.hpp>
#include <boost/locale.hpp>
#include <loot/metadata/group.h>
namespace loot {
PluginSortingData::PluginSortingData(const Plugin& plugin,
const PluginMetadata&& metadata) :
const PluginMetadata& masterlistMetadata,
const PluginMetadata& userMetadata) :
plugin_(plugin),
PluginMetadata(metadata),
group_(metadata.GetGroup().value_or(Group().GetName())) {}
masterlistLoadAfter_(masterlistMetadata.GetLoadAfterFiles()),
userLoadAfter_(userMetadata.GetLoadAfterFiles()),
masterlistReq_(masterlistMetadata.GetRequirements()),
userReq_(userMetadata.GetRequirements()) {
if (userMetadata.GetGroup()) {
group_ = userMetadata.GetGroup().value();
} else if (masterlistMetadata.GetGroup()) {
group_ = masterlistMetadata.GetGroup().value();
} else {
group_ = Group().GetName();
}
}
std::string PluginSortingData::GetName() const { return plugin_.GetName(); }
std::string PluginSortingData::GetLowercasedName() const {
return boost::locale::to_lower(plugin_.GetName());
}
bool PluginSortingData::IsMaster() const {
return plugin_.IsMaster() || (plugin_.IsLightMaster() &&
!boost::iends_with(plugin_.GetName(), ".esp"));
@@ -59,11 +75,29 @@ bool PluginSortingData::DoFormIDsOverlap(
std::string PluginSortingData::GetGroup() const { return group_; }
std::unordered_set<std::string> PluginSortingData::GetAfterGroupPlugins() const {
std::unordered_set<std::string> PluginSortingData::GetAfterGroupPlugins()
const {
return afterGroupPlugins_;
}
void PluginSortingData::SetAfterGroupPlugins(std::unordered_set<std::string> plugins) {
void PluginSortingData::SetAfterGroupPlugins(
std::unordered_set<std::string> plugins) {
afterGroupPlugins_ = plugins;
}
const std::set<File>& PluginSortingData::GetMasterlistLoadAfterFiles() const {
return masterlistLoadAfter_;
}
const std::set<File>& PluginSortingData::GetUserLoadAfterFiles() const {
return userLoadAfter_;
}
const std::set<File>& PluginSortingData::GetMasterlistRequirements() const {
return masterlistReq_;
}
const std::set<File>& PluginSortingData::GetUserRequirements() const {
return userReq_;
}
}
+15 -6
View File
@@ -29,11 +29,14 @@
#include "loot/metadata/plugin_metadata.h"
namespace loot {
class PluginSortingData : private PluginMetadata {
class PluginSortingData {
public:
PluginSortingData(const Plugin& plugin, const PluginMetadata&& metadata);
PluginSortingData(const Plugin& plugin,
const PluginMetadata& masterlistMetadata,
const PluginMetadata& userMetadata);
std::string GetName() const;
std::string GetLowercasedName() const;
bool IsMaster() const;
bool LoadsArchive() const;
std::vector<std::string> GetMasters() const;
@@ -44,15 +47,21 @@ public:
std::unordered_set<std::string> GetAfterGroupPlugins() const;
void SetAfterGroupPlugins(std::unordered_set<std::string> plugins);
using PluginMetadata::GetLowercasedName;
using PluginMetadata::GetLoadAfterFiles;
using PluginMetadata::GetRequirements;
const std::set<File>& GetMasterlistLoadAfterFiles() const;
const std::set<File>& GetUserLoadAfterFiles() const;
const std::set<File>& GetMasterlistRequirements() const;
const std::set<File>& GetUserRequirements() const;
private:
const Plugin& plugin_;
std::string group_;
std::unordered_set<std::string> afterGroupPlugins_;
std::set<File> masterlistLoadAfter_;
std::set<File> userLoadAfter_;
std::set<File> masterlistReq_;
std::set<File> userReq_;
};
}
@@ -35,55 +35,73 @@ along with LOOT. If not, see
namespace loot {
namespace test {
TEST(GetTransitiveAfterGroups, shouldMapGroupsToTheirTransitiveAfterGroups) {
std::unordered_set<Group> groups({
Group("a"),
Group("b", std::unordered_set<std::string>({ "a" })),
Group("c", std::unordered_set<std::string>({"b"}))
});
std::unordered_set<Group> groups(
{Group("a"),
Group("b", std::unordered_set<std::string>({"a"})),
Group("c", std::unordered_set<std::string>({"b"}))});
auto mapped = GetTransitiveAfterGroups(groups);
auto mapped = GetTransitiveAfterGroups(groups, {});
EXPECT_TRUE(mapped["a"].empty());
EXPECT_EQ(std::unordered_set<std::string>({ "a" }), mapped["b"]);
EXPECT_EQ(std::unordered_set<std::string>({ "a", "b" }), mapped["c"]);
EXPECT_EQ(std::unordered_set<std::string>({"a"}), mapped["b"]);
EXPECT_EQ(std::unordered_set<std::string>({"a", "b"}), mapped["c"]);
}
TEST(GetTransitiveAfterGroups, shouldThrowIfAnAfterGroupDoesNotExist) {
std::unordered_set<Group> groups({
Group("b", std::unordered_set<std::string>({ "a" }))
});
std::unordered_set<Group> groups(
{Group("b", std::unordered_set<std::string>({"a"}))});
EXPECT_THROW(GetTransitiveAfterGroups(groups), UndefinedGroupError);
EXPECT_THROW(GetTransitiveAfterGroups(groups, {}), UndefinedGroupError);
}
TEST(GetTransitiveAfterGroups, shouldThrowIfAfterGroupsAreCyclic) {
std::unordered_set<Group> groups({
Group("a", std::unordered_set<std::string>({ "c" })),
Group("b", std::unordered_set<std::string>({ "a" })),
Group("c", std::unordered_set<std::string>({ "b" }))
});
std::unordered_set<Group> groups(
{Group("a", std::unordered_set<std::string>({"c"})),
Group("b", std::unordered_set<std::string>({"a"}))});
std::unordered_set<Group> userGroups(
{Group("c", std::unordered_set<std::string>({"b"}))});
try {
GetTransitiveAfterGroups(groups);
GetTransitiveAfterGroups(groups, userGroups);
FAIL();
}
catch (CyclicInteractionError &e) {
} catch (CyclicInteractionError &e) {
ASSERT_EQ(3, e.GetCycle().size());
EXPECT_EQ(EdgeType::LoadAfter, e.GetCycle()[0].GetTypeOfEdgeToNextVertex());
EXPECT_EQ(EdgeType::LoadAfter, e.GetCycle()[1].GetTypeOfEdgeToNextVertex());
EXPECT_EQ(EdgeType::LoadAfter, e.GetCycle()[2].GetTypeOfEdgeToNextVertex());
// Vertices can be added in any order, so which group is first is undefined.
if (e.GetCycle()[0].GetName() == "a") {
EXPECT_EQ(EdgeType::MasterlistLoadAfter,
e.GetCycle()[0].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("c", e.GetCycle()[1].GetName());
EXPECT_EQ(EdgeType::UserLoadAfter,
e.GetCycle()[1].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("b", e.GetCycle()[2].GetName());
EXPECT_EQ(EdgeType::MasterlistLoadAfter,
e.GetCycle()[2].GetTypeOfEdgeToNextVertex());
} else if (e.GetCycle()[0].GetName() == "b") {
EXPECT_EQ(EdgeType::MasterlistLoadAfter,
e.GetCycle()[0].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("a", e.GetCycle()[1].GetName());
EXPECT_EQ(EdgeType::MasterlistLoadAfter,
e.GetCycle()[1].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("c", e.GetCycle()[2].GetName());
EXPECT_EQ(EdgeType::UserLoadAfter,
e.GetCycle()[2].GetTypeOfEdgeToNextVertex());
} else {
EXPECT_EQ("c", e.GetCycle()[0].GetName());
EXPECT_EQ(EdgeType::UserLoadAfter,
e.GetCycle()[0].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("b", e.GetCycle()[1].GetName());
EXPECT_EQ(EdgeType::MasterlistLoadAfter,
e.GetCycle()[1].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("a", e.GetCycle()[2].GetName());
EXPECT_EQ(EdgeType::MasterlistLoadAfter,
e.GetCycle()[2].GetTypeOfEdgeToNextVertex());
}
}
}
@@ -98,9 +98,9 @@ protected:
std::string getCCCFilename() {
if (GetParam() == GameType::fo4) {
return "Fallout4.ccc";
}
else {
// Not every game has a .ccc file, but Skyrim SE does, so just assume that.
} else {
// Not every game has a .ccc file, but Skyrim SE does, so just assume
// that.
return "Skyrim.ccc";
}
}
@@ -147,23 +147,28 @@ TEST_P(PluginSorterTest,
auto esp = PluginSortingData(
*dynamic_cast<const Plugin *>(game_.GetPlugin(blankEsp).value().get()),
PluginMetadata(),
PluginMetadata());
EXPECT_FALSE(esp.IsMaster());
auto master = PluginSortingData(
*dynamic_cast<const Plugin *>(game_.GetPlugin(blankEsm).value().get()),
PluginMetadata(),
PluginMetadata());
EXPECT_TRUE(master.IsMaster());
if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) {
auto lightMaster = PluginSortingData(
*dynamic_cast<const Plugin *>(game_.GetPlugin(blankEsl).value().get()),
PluginMetadata(),
PluginMetadata());
EXPECT_TRUE(lightMaster.IsMaster());
auto lightMasterEsp = PluginSortingData(*dynamic_cast<const Plugin *>(
auto lightMasterEsp =
PluginSortingData(*dynamic_cast<const Plugin *>(
game_.GetPlugin(blankEslEsp).value().get()),
PluginMetadata());
PluginMetadata(),
PluginMetadata());
EXPECT_FALSE(lightMasterEsp.IsMaster());
}
}
@@ -379,7 +384,8 @@ TEST_P(
FAIL();
} catch (CyclicInteractionError &e) {
ASSERT_EQ(3, e.GetCycle().size());
EXPECT_EQ("Blank - Different Master Dependent.esm", e.GetCycle()[0].GetName());
EXPECT_EQ("Blank - Different Master Dependent.esm",
e.GetCycle()[0].GetName());
EXPECT_EQ(EdgeType::Group, e.GetCycle()[0].GetTypeOfEdgeToNextVertex());
EXPECT_EQ("Blank.esm", e.GetCycle()[1].GetName());
EXPECT_EQ(EdgeType::Master, e.GetCycle()[1].GetTypeOfEdgeToNextVertex());