Refactor CheckInstallValidity() into GUI's Game

So that it can be more easily tested.
This commit is contained in:
Oliver Hamlet
2017-02-06 18:03:16 +00:00
parent 2c72967708
commit e499955e81
4 changed files with 121 additions and 44 deletions
+1 -44
View File
@@ -56,7 +56,7 @@ protected:
auto messages = metadata.Messages();
auto statusMessages = file->GetStatusMessages();
auto validityMessages = CheckInstallValidity(file, metadata);
auto validityMessages = state_.getCurrentGame().CheckInstallValidity(file, metadata);
messages.insert(end(messages), begin(statusMessages), end(statusMessages));
messages.insert(end(messages), begin(validityMessages), end(validityMessages));
metadata.Messages(messages);
@@ -155,49 +155,6 @@ private:
}
}
std::vector<Message> CheckInstallValidity(std::shared_ptr<const PluginInterface> plugin, const PluginMetadata& metadata) {
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to " << plugin->GetName() << "'s data.";
std::vector<Message> messages;
if (state_.getCurrentGame().IsPluginActive(plugin->GetName())) {
auto pluginExists = [&](const std::string& file) {
return boost::filesystem::exists(state_.getCurrentGame().DataPath() / file)
|| ((boost::iends_with(file, ".esp") || boost::iends_with(file, ".esm")) && boost::filesystem::exists(state_.getCurrentGame().DataPath() / (file + ".ghost")));
};
auto tags = metadata.Tags();
if (tags.find(Tag("Filter")) == std::end(tags)) {
for (const auto &master : plugin->GetMasters()) {
if (!pluginExists(master)) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" requires \"" << master << "\", but it is missing.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be installed, but it is missing.")) % master).str()));
} else if (!state_.getCurrentGame().IsPluginActive(master)) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" requires \"" << master << "\", but it is inactive.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be active, but it is inactive.")) % master).str()));
}
}
}
for (const auto &req : metadata.Reqs()) {
if (!pluginExists(req.Name())) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" requires \"" << req.Name() << "\", but it is missing.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be installed, but it is missing.")) % req.Name()).str()));
}
}
for (const auto &inc : metadata.Incs()) {
if (pluginExists(inc.Name()) && state_.getCurrentGame().IsPluginActive(inc.Name())) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" is incompatible with \"" << inc.Name() << "\", but both are present.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin is incompatible with \"%1%\", but both are present.")) % inc.Name()).str()));
}
}
}
// Also generate dirty messages.
for (const auto &element : metadata.DirtyInfo()) {
messages.push_back(element.AsMessage());
}
return messages;
}
LootState& state_;
};
}
+43
View File
@@ -128,6 +128,49 @@ std::set<std::shared_ptr<const PluginInterface>> Game::GetPlugins() const {
return gameHandle_->GetLoadedPlugins();
}
std::vector<Message> Game::CheckInstallValidity(std::shared_ptr<const PluginInterface> plugin, const PluginMetadata & metadata) {
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to " << plugin->GetName() << "'s data.";
std::vector<Message> messages;
if (IsPluginActive(plugin->GetName())) {
auto pluginExists = [&](const std::string& file) {
return boost::filesystem::exists(DataPath() / file)
|| ((boost::iends_with(file, ".esp") || boost::iends_with(file, ".esm")) && boost::filesystem::exists(DataPath() / (file + ".ghost")));
};
auto tags = metadata.Tags();
if (tags.find(Tag("Filter")) == std::end(tags)) {
for (const auto &master : plugin->GetMasters()) {
if (!pluginExists(master)) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" requires \"" << master << "\", but it is missing.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be installed, but it is missing.")) % master).str()));
} else if (!IsPluginActive(master)) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" requires \"" << master << "\", but it is inactive.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be active, but it is inactive.")) % master).str()));
}
}
}
for (const auto &req : metadata.Reqs()) {
if (!pluginExists(req.Name())) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" requires \"" << req.Name() << "\", but it is missing.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be installed, but it is missing.")) % req.Name()).str()));
}
}
for (const auto &inc : metadata.Incs()) {
if (pluginExists(inc.Name()) && IsPluginActive(inc.Name())) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin->GetName() << "\" is incompatible with \"" << inc.Name() << "\", but both are present.";
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("This plugin is incompatible with \"%1%\", but both are present.")) % inc.Name()).str()));
}
}
}
// Also generate dirty messages.
for (const auto &element : metadata.DirtyInfo()) {
messages.push_back(element.AsMessage());
}
return messages;
}
void Game::RedatePlugins() {
if (Type() != GameType::tes5 && Type() != GameType::tes5se) {
BOOST_LOG_TRIVIAL(warning) << "Cannot redate plugins for game " << Name();
+1
View File
@@ -51,6 +51,7 @@ public:
std::shared_ptr<const PluginInterface> GetPlugin(const std::string& name) const;
std::set<std::shared_ptr<const PluginInterface>> GetPlugins() const;
std::vector<Message> CheckInstallValidity(std::shared_ptr<const PluginInterface> plugin, const PluginMetadata& metadata);
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
+76
View File
@@ -171,6 +171,82 @@ TEST_P(GameTest, initShouldNotThrowIfGameAndLocalPathsAreNotEmpty) {
EXPECT_NO_THROW(game.Init());
}
TEST_P(GameTest, checkInstallValidityShouldCheckThatRequirementsArePresent) {
Game game = Game(GameSettings(GetParam()).SetGamePath(dataPath.parent_path()), "", localPath);
game.LoadAllInstalledPlugins(true);
PluginMetadata metadata(blankEsm);
metadata.Reqs({
File(missingEsp),
File(blankEsp),
});
auto messages = game.CheckInstallValidity(game.GetPlugin(blankEsm), metadata);
EXPECT_EQ(std::vector<Message>({
Message(MessageType::error, "This plugin requires \"" + missingEsp + "\" to be installed, but it is missing."),
}), messages);
}
TEST_P(GameTest, checkInstallValidityShouldCheckThatIncompatibilitiesAreAbsent) {
Game game = Game(GameSettings(GetParam()).SetGamePath(dataPath.parent_path()), "", localPath);
game.LoadAllInstalledPlugins(true);
PluginMetadata metadata(blankEsm);
metadata.Incs({
File(missingEsp),
File(masterFile),
});
auto messages = game.CheckInstallValidity(game.GetPlugin(blankEsm), metadata);
EXPECT_EQ(std::vector<Message>({
Message(MessageType::error, "This plugin is incompatible with \"" + masterFile + "\", but both are present."),
}), messages);
}
TEST_P(GameTest, checkInstallValidityShouldGenerateMessagesFromDirtyInfo) {
Game game = Game(GameSettings(GetParam()).SetGamePath(dataPath.parent_path()), "", localPath);
game.LoadAllInstalledPlugins(true);
PluginMetadata metadata(blankEsm);
const std::vector<MessageContent> info = std::vector<MessageContent>({
MessageContent("info", LanguageCode::english),
});
metadata.DirtyInfo({
PluginCleaningData(blankEsmCrc, "utility1", info, 0, 1, 2),
PluginCleaningData(0xDEADBEEF, "utility2", info, 0, 5, 10),
});
auto messages = game.CheckInstallValidity(game.GetPlugin(blankEsm), metadata);
EXPECT_EQ(std::vector<Message>({
PluginCleaningData(blankEsmCrc, "utility1", info, 0, 1, 2).AsMessage(),
PluginCleaningData(0xDEADBEEF, "utility2", info, 0, 5, 10).AsMessage(),
}), messages);
}
TEST_P(GameTest, checkInstallValidityShouldCheckIfAPluginsMastersAreAllPresentAndActiveIfNoFilterTagIsPresent) {
Game game = Game(GameSettings(GetParam()).SetGamePath(dataPath.parent_path()), "", localPath);
game.LoadAllInstalledPlugins(true);
PluginMetadata metadata(blankDifferentMasterDependentEsp);
auto messages = game.CheckInstallValidity(game.GetPlugin(blankDifferentMasterDependentEsp), metadata);
EXPECT_EQ(std::vector<Message>({
Message(MessageType::error, "This plugin requires \"" + blankDifferentEsm + "\" to be active, but it is inactive."),
}), messages);
}
TEST_P(GameTest, checkInstallValidityShouldNotCheckIfAPluginsMastersAreAllActiveIfAFilterTagIsPresent) {
Game game = Game(GameSettings(GetParam()).SetGamePath(dataPath.parent_path()), "", localPath);
game.LoadAllInstalledPlugins(true);
PluginMetadata metadata(blankDifferentMasterDependentEsp);
metadata.Tags({Tag("Filter")});
auto messages = game.CheckInstallValidity(game.GetPlugin(blankDifferentMasterDependentEsp), metadata);
EXPECT_TRUE(messages.empty());
}
TEST_P(GameTest, redatePluginsShouldRedatePluginsForSkyrimAndSkyrimSEAndDoNothingForOtherGames) {
Game game = Game(GameSettings(GetParam()).SetGamePath(dataPath.parent_path()), "", localPath);
game.Init();