Move condition evaluation out of metadata classes

So that the API doesn't expose any references to the Game class.
Evaluation is now done in the ConditionEvaluator class. This complicates
evaluating conditions for Plugin objects, these have been checked to
ensure that metadata is only merged into them after evaluation.
This commit is contained in:
Oliver Hamlet
2017-02-06 18:02:18 +00:00
parent 15c1c91750
commit 174dea8b8d
20 changed files with 390 additions and 317 deletions
+1
View File
@@ -320,6 +320,7 @@ set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/language_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/version_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/helpers/yaml_set_helpers_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/condition_evaluator_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/condition_grammar_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/conditional_metadata_test.h"
"${CMAKE_SOURCE_DIR}/src/tests/backend/metadata/file_test.h"
+1 -6
View File
@@ -27,21 +27,16 @@
#include <string>
namespace loot {
class Game;
class ConditionalMetadata {
public:
ConditionalMetadata();
ConditionalMetadata(const std::string& condition);
bool IsConditional() const;
bool EvalCondition(Game& game) const;
void ParseCondition() const; // Throws error on parsing failure.
void ParseCondition() const;
std::string Condition() const;
private:
bool ParseCondition(Game * game) const; // Throws error on parsing failure.
std::string condition_;
};
}
@@ -31,8 +31,6 @@
#include "loot/metadata/message.h"
namespace loot {
class Game;
class PluginCleaningData {
public:
PluginCleaningData();
@@ -56,8 +54,6 @@ public:
MessageContent ChooseInfo(const LanguageCode language) const;
Message AsMessage() const;
bool EvalCondition(Game& game, const std::string& pluginName) const;
private:
uint32_t crc_;
unsigned int itm_;
-3
View File
@@ -40,8 +40,6 @@
#include "loot/metadata/tag.h"
namespace loot {
class Game;
class PluginMetadata {
public:
PluginMetadata();
@@ -84,7 +82,6 @@ public:
void CleanInfo(const std::set<PluginCleaningData>& info);
void Locations(const std::set<Location>& locations);
PluginMetadata& EvalAllConditions(Game& game);
bool HasNameOnly() const;
bool IsRegexPlugin() const;
+6 -6
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: LOOT 0.10.3\n"
"Report-Msgid-Bugs-To: https://github.com/loot/loot/issues\n"
"POT-Creation-Date: 2017-01-29 11:37+0000\n"
"POT-Creation-Date: 2017-01-29 13:46+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -700,25 +700,25 @@ msgid ""
"[LOOT's website](https://loot.github.io/)."
msgstr ""
#: src/gui/query/metadata_query.h:90 src/gui/query/metadata_query.h:91
#: src/gui/query/metadata_query.h:91 src/gui/query/metadata_query.h:92
msgid "N/A: No masterlist present"
msgstr ""
#: src/gui/query/metadata_query.h:94 src/gui/query/metadata_query.h:95
#: src/gui/query/metadata_query.h:95 src/gui/query/metadata_query.h:96
msgid "Unknown: Git repository missing"
msgstr ""
#: src/gui/query/metadata_query.h:118
#: src/gui/query/metadata_query.h:120
msgid ""
"A global message contains a condition that could not be evaluated. Details: "
"%1%"
msgstr ""
#: src/gui/query/metadata_query.h:144 src/backend/plugin/plugin_sorter.cpp:219
#: src/gui/query/metadata_query.h:146 src/backend/plugin/plugin_sorter.cpp:219
msgid "\"%1%\" contains a condition that could not be evaluated. Details: %2%"
msgstr ""
#: src/gui/query/metadata_query.h:175 src/gui/query/metadata_query.h:176
#: src/gui/query/metadata_query.h:178 src/gui/query/metadata_query.h:179
msgid "(edited)"
msgstr ""
@@ -29,6 +29,7 @@
#include <boost/log/trivial.hpp>
#include "backend/helpers/crc.h"
#include "backend/metadata/condition_grammar.h"
#include "loot/exception/condition_syntax_error.h"
using boost::format;
@@ -36,6 +37,117 @@ using boost::format;
namespace loot {
ConditionEvaluator::ConditionEvaluator(Game * game) : game_(game) {}
bool ConditionEvaluator::evaluate(const std::string& condition) {
if (game_ == nullptr) {
// Still check that the syntax is valid.
parseCondition(condition);
return false;
}
if (condition.empty())
return true;
BOOST_LOG_TRIVIAL(trace) << "Evaluating condition: " << condition;
auto cachedValue = game_->GetCachedCondition(condition);
if (cachedValue.second)
return cachedValue.first;
bool result = parseCondition(condition);
game_->CacheCondition(condition, result);
return result;
}
bool ConditionEvaluator::evaluate(const PluginCleaningData& cleaningData, const std::string& pluginName) {
if (game_ == nullptr || pluginName.empty())
return false;
// First need to get plugin's CRC.
uint32_t crc = 0;
// Get the CRC from the game plugin cache if possible.
try {
crc = game_->GetPlugin(pluginName).Crc();
} catch (...) {}
// Otherwise calculate it from the file.
if (crc == 0) {
if (boost::filesystem::exists(game_->DataPath() / pluginName)) {
crc = GetCrc32(game_->DataPath() / pluginName);
} else if (boost::filesystem::exists(game_->DataPath() / (pluginName + ".ghost"))) {
crc = GetCrc32(game_->DataPath() / (pluginName + ".ghost"));
}
}
return cleaningData.CRC() == crc;
}
PluginMetadata ConditionEvaluator::evaluateAll(const PluginMetadata& pluginMetadata) {
if (game_ == nullptr)
return pluginMetadata;
PluginMetadata evaluatedMetadata(pluginMetadata.Name());
evaluatedMetadata.Enabled(pluginMetadata.Enabled());
evaluatedMetadata.LocalPriority(pluginMetadata.LocalPriority());
evaluatedMetadata.GlobalPriority(pluginMetadata.GlobalPriority());
evaluatedMetadata.Locations(pluginMetadata.Locations());
std::set<File> fileSet;
for (const auto& file : pluginMetadata.LoadAfter()) {
if (evaluate(file.Condition()))
fileSet.insert(file);
}
evaluatedMetadata.LoadAfter(fileSet);
fileSet.clear();
for (const auto& file : pluginMetadata.Reqs()) {
if (evaluate(file.Condition()))
fileSet.insert(file);
}
evaluatedMetadata.Reqs(fileSet);
fileSet.clear();
for (const auto& file : pluginMetadata.Incs()) {
if (evaluate(file.Condition()))
fileSet.insert(file);
}
evaluatedMetadata.Incs(fileSet);
std::vector<Message> messages;
for (const auto& message : pluginMetadata.Messages()) {
if (evaluate(message.Condition()))
messages.push_back(message);
}
evaluatedMetadata.Messages(messages);
std::set<Tag> tagSet;
for (const auto& tag : pluginMetadata.Tags()) {
if (evaluate(tag.Condition()))
tagSet.insert(tag);
}
evaluatedMetadata.Tags(tagSet);
if (!evaluatedMetadata.IsRegexPlugin()) {
std::set<PluginCleaningData> infoSet;
for (const auto& info : pluginMetadata.DirtyInfo()) {
if (evaluate(info, pluginMetadata.Name()))
infoSet.insert(info);
}
evaluatedMetadata.DirtyInfo(infoSet);
infoSet.clear();
for (const auto& info : pluginMetadata.CleanInfo()) {
if (evaluate(info, pluginMetadata.Name()))
infoSet.insert(info);
}
evaluatedMetadata.CleanInfo(infoSet);
}
return evaluatedMetadata;
}
bool ConditionEvaluator::fileExists(const std::string& filePath) const {
validatePath(filePath);
@@ -264,6 +376,24 @@ bool ConditionEvaluator::areRegexMatchesInDataDirectory(const std::pair<boost::f
return false;
});
}
bool ConditionEvaluator::parseCondition(const std::string & condition) {
if (condition.empty())
return true;
ConditionGrammar<std::string::const_iterator, boost::spirit::qi::space_type> grammar(*this);
boost::spirit::qi::space_type skipper;
std::string::const_iterator begin = condition.begin();
std::string::const_iterator end = condition.end();
bool evaluation;
bool parseResult = boost::spirit::qi::phrase_parse(begin, end, grammar, skipper, evaluation);
if (!parseResult || begin != end) {
throw ConditionSyntaxError((boost::format("Failed to parse condition \"%1%\": only partially matched expected syntax.") % condition).str());
}
return evaluation;
}
Version ConditionEvaluator::getVersion(const std::string& filePath) const {
if (filePath == "LOOT")
return Version(boost::filesystem::absolute("LOOT.exe"));
@@ -32,12 +32,18 @@
#include "backend/game/game.h"
#include "backend/helpers/version.h"
#include "loot/metadata/plugin_cleaning_data.h"
#include "loot/metadata/plugin_metadata.h"
namespace loot {
class ConditionEvaluator {
public:
ConditionEvaluator(Game * game);
bool evaluate(const std::string& condition);
bool evaluate(const PluginCleaningData& cleaningData, const std::string& pluginName);
PluginMetadata evaluateAll(const PluginMetadata& pluginMetadata);
bool fileExists(const std::string& filePath) const;
bool regexMatchExists(const std::string& regexString) const;
bool regexMatchesExist(const std::string& regexString) const;
@@ -68,6 +74,8 @@ private:
bool areRegexMatchesInDataDirectory(const std::pair<boost::filesystem::path, std::regex>& pathRegex,
const std::function<bool(const std::string&)> condition) const;
bool parseCondition(const std::string& condition);
Version getVersion(const std::string& filePath) const;
Game * game_;
+10 -10
View File
@@ -56,7 +56,7 @@ template<typename Iterator, typename Skipper>
class ConditionGrammar : public boost::spirit::qi::grammar < Iterator, bool(), Skipper > {
public:
ConditionGrammar() : ConditionGrammar(nullptr) {}
ConditionGrammar(Game * game) : ConditionGrammar::base_type(expression_, "condition grammar"), evaluator(game) {
ConditionGrammar(ConditionEvaluator& evaluator) : ConditionGrammar::base_type(expression_, "condition grammar"), evaluator_(evaluator) {
using boost::spirit::unicode::char_;
using boost::spirit::unicode::string;
namespace phoenix = boost::phoenix;
@@ -144,9 +144,9 @@ private:
result = false;
if (IsRegex(file))
result = evaluator.regexMatchExists(file);
result = evaluator_.regexMatchExists(file);
else
result = evaluator.fileExists(file);
result = evaluator_.fileExists(file);
BOOST_LOG_TRIVIAL(trace) << "File check result: " << result;
}
@@ -155,21 +155,21 @@ private:
BOOST_LOG_TRIVIAL(trace) << "Checking to see if more than one file matching the regex \"" << regexStr << "\" exist.";
result = false;
result = evaluator.regexMatchesExist(regexStr);
result = evaluator_.regexMatchesExist(regexStr);
}
void CheckSum(bool& result, const std::string& file, const uint32_t checksum) {
BOOST_LOG_TRIVIAL(trace) << "Checking the CRC of the file \"" << file << "\".";
result = false;
result = evaluator.checksumMatches(file, checksum);
result = evaluator_.checksumMatches(file, checksum);
}
void CheckVersion(bool& result, const std::string& file, const std::string& version, const std::string& comparator) const {
BOOST_LOG_TRIVIAL(trace) << "Checking version of file \"" << file << "\".";
result = false;
result = evaluator.compareVersions(file, version, comparator);
result = evaluator_.compareVersions(file, version, comparator);
BOOST_LOG_TRIVIAL(trace) << "Version check result: " << result;
}
@@ -177,9 +177,9 @@ private:
void CheckActive(bool& result, const std::string& file) const {
result = false;
if (IsRegex(file))
result = evaluator.isPluginMatchingRegexActive(file);
result = evaluator_.isPluginMatchingRegexActive(file);
else
result = evaluator.isPluginActive(file);
result = evaluator_.isPluginActive(file);
BOOST_LOG_TRIVIAL(trace) << "Active check result: " << result;
}
@@ -188,7 +188,7 @@ private:
BOOST_LOG_TRIVIAL(trace) << "Checking to see if more than one file matching the regex \"" << regexStr << "\" exist.";
result = false;
result = evaluator.arePluginsActive(regexStr);
result = evaluator_.arePluginsActive(regexStr);
}
void SyntaxError(Iterator const& first, Iterator const& last, Iterator const& errorpos, boost::spirit::info const& what) {
@@ -203,7 +203,7 @@ private:
boost::spirit::qi::rule<Iterator, std::string()> quotedStr_, filePath_, comparator_;
boost::spirit::qi::rule<Iterator, char()> invalidPathChars_;
ConditionEvaluator evaluator;
ConditionEvaluator& evaluator_;
};
}
#endif
+3 -39
View File
@@ -28,7 +28,7 @@
#include <boost/log/trivial.hpp>
#include "backend/game/game.h"
#include "backend/metadata/condition_grammar.h"
#include "backend/metadata/condition_evaluator.h"
using std::string;
@@ -45,46 +45,10 @@ std::string ConditionalMetadata::Condition() const {
return condition_;
}
bool ConditionalMetadata::EvalCondition(Game& game) const {
if (condition_.empty())
return true;
BOOST_LOG_TRIVIAL(trace) << "Evaluating condition: " << condition_;
auto cachedValue = game.GetCachedCondition(condition_);
if (cachedValue.second)
return cachedValue.first;
bool result = ParseCondition(&game);
game.CacheCondition(condition_, result);
return result;
}
void ConditionalMetadata::ParseCondition() const {
BOOST_LOG_TRIVIAL(trace) << "Testing condition syntax: " << condition_;
ParseCondition(nullptr);
}
ConditionEvaluator evaluator(nullptr);
bool ConditionalMetadata::ParseCondition(Game * game) const {
if (condition_.empty())
return true;
BOOST_LOG_TRIVIAL(trace) << "Testing condition syntax: " << condition_;
ConditionGrammar<string::const_iterator, boost::spirit::qi::space_type> grammar(game);
boost::spirit::qi::space_type skipper;
string::const_iterator begin = condition_.begin();
string::const_iterator end = condition_.end();
bool evaluation;
bool parseResult = boost::spirit::qi::phrase_parse(begin, end, grammar, skipper, evaluation);
if (!parseResult || begin != end) {
throw ConditionSyntaxError((boost::format("Failed to parse condition \"%1%\": only partially matched expected syntax.") % condition_).str());
}
return evaluation;
evaluator.evaluate(condition_);
}
}
@@ -122,28 +122,4 @@ Message PluginCleaningData::AsMessage() const {
return Message(MessageType::warn, info);
}
bool PluginCleaningData::EvalCondition(Game& game, const std::string& pluginName) const {
if (pluginName.empty())
return false;
// First need to get plugin's CRC.
uint32_t crc = 0;
// Get the CRC from the game plugin cache if possible.
try {
crc = game.GetPlugin(pluginName).Crc();
} catch (...) {}
// Otherwise calculate it from the file.
if (crc == 0) {
if (boost::filesystem::exists(game.DataPath() / pluginName)) {
crc = GetCrc32(game.DataPath() / pluginName);
} else if (boost::filesystem::exists(game.DataPath() / (pluginName + ".ghost"))) {
crc = GetCrc32(game.DataPath() / (pluginName + ".ghost"));
}
}
return crc_ == crc;
}
}
-57
View File
@@ -272,63 +272,6 @@ void PluginMetadata::Locations(const std::set<Location>& locations) {
locations_ = locations;
}
PluginMetadata& PluginMetadata::EvalAllConditions(Game& game) {
for (auto it = loadAfter_.begin(); it != loadAfter_.end();) {
if (!it->EvalCondition(game))
loadAfter_.erase(it++);
else
++it;
}
for (auto it = requirements_.begin(); it != requirements_.end();) {
if (!it->EvalCondition(game))
requirements_.erase(it++);
else
++it;
}
for (auto it = incompatibilities_.begin(); it != incompatibilities_.end();) {
if (!it->EvalCondition(game))
incompatibilities_.erase(it++);
else
++it;
}
for (auto it = messages_.begin(); it != messages_.end();) {
if (!it->EvalCondition(game))
it = messages_.erase(it);
else
++it;
}
for (auto it = tags_.begin(); it != tags_.end();) {
if (!it->EvalCondition(game))
tags_.erase(it++);
else
++it;
}
if (IsRegexPlugin()) { // Remove any dirty metadata from a regex plugin.
dirtyInfo_.clear();
cleanInfo_.clear();
} else {
for (auto it = dirtyInfo_.begin(); it != dirtyInfo_.end();) {
if (!it->EvalCondition(game, name_))
dirtyInfo_.erase(it++);
else
++it;
}
for (auto it = cleanInfo_.begin(); it != cleanInfo_.end();) {
if (!it->EvalCondition(game, name_))
cleanInfo_.erase(it++);
else
++it;
}
}
return *this;
}
bool PluginMetadata::HasNameOnly() const {
return !localPriority_.isExplicit()
&& !globalPriority_.isExplicit()
+10 -6
View File
@@ -31,6 +31,7 @@
#include "loot/exception/file_access_error.h"
#include "loot/yaml/plugin_metadata.h"
#include "backend/game/game.h"
#include "backend/metadata/condition_evaluator.h"
namespace loot {
void MetadataList::Load(const boost::filesystem::path& filepath) {
@@ -149,18 +150,21 @@ void MetadataList::AppendMessage(const Message& message) {
}
void MetadataList::EvalAllConditions(Game& game) {
ConditionEvaluator evaluator(&game);
std::unordered_set<PluginMetadata> replacementSet;
for (auto &plugin : plugins_) {
PluginMetadata p(plugin);
p.EvalAllConditions(game);
replacementSet.insert(p);
replacementSet.insert(evaluator.evaluateAll(plugin));
}
plugins_ = replacementSet;
for (auto &plugin : regexPlugins_) {
plugin.EvalAllConditions(game);
plugin = evaluator.evaluateAll(plugin);
}
for (auto &message : messages_) {
message.EvalCondition(game);
for (auto it = std::begin(messages_); it != std::end(messages_);) {
if (!evaluator.evaluate(it->Condition()))
it = messages_.erase(it);
else
++it;
}
}
}
+18 -15
View File
@@ -36,6 +36,7 @@
#include "loot/exception/cyclic_interaction_error.h"
#include "backend/game/game.h"
#include "backend/metadata/condition_evaluator.h"
using std::list;
using std::string;
@@ -190,26 +191,28 @@ void PluginSorter::AddPluginVertices(Game& game, const LanguageCode language) {
// Using a set of plugin names followed by finding the matching key
// in the unordered map, as it's probably faster than copying the
// full plugin objects then sorting them.
ConditionEvaluator evaluator(&game);
for (const auto &plugin : game.GetPlugins()) {
vertex_t v = boost::add_vertex(plugin, graph_);
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph_[v].Name() << "\"";
//Check if there is a plugin entry in the masterlist. This will also find matching regex entries.
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data.";
graph_[v].MergeMetadata(game.GetMasterlist().FindPlugin(graph_[v]));
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
PluginMetadata ulistPlugin = game.GetUserlist().FindPlugin(graph_[v]);
if (!ulistPlugin.HasNameOnly() && ulistPlugin.Enabled()) {
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
graph_[v].MergeMetadata(ulistPlugin);
}
//Now that items are merged, evaluate any conditions they have.
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
try {
graph_[v].EvalAllConditions(game);
//Check if there is a plugin entry in the masterlist. This will also find matching regex entries.
BOOST_LOG_TRIVIAL(trace) << "Evaluating conditions for any masterlist metadata.";
auto metadata = game.GetMasterlist().FindPlugin(graph_[v]);
metadata = evaluator.evaluateAll(metadata);
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist metadata down to plugin list data.";
graph_[v].MergeMetadata(metadata);
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
metadata = game.GetUserlist().FindPlugin(graph_[v]);
if (!metadata.HasNameOnly() && metadata.Enabled()) {
BOOST_LOG_TRIVIAL(trace) << "Evaluating conditions for userlist metadata.";
metadata = evaluator.evaluateAll(metadata);
BOOST_LOG_TRIVIAL(trace) << "Merging userlist metadata down to plugin list data.";
graph_[v].MergeMetadata(metadata);
}
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "\"" << graph_[v].Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
vector<Message> messages(graph_[v].Messages());
+17 -14
View File
@@ -29,6 +29,7 @@ along with LOOT. If not, see
#include <boost/log/trivial.hpp>
#include "backend/plugin/plugin.h"
#include "backend/metadata/condition_evaluator.h"
#include "gui/query/query.h"
#include "loot/exception/file_access_error.h"
#include "loot/exception/git_state_error.h"
@@ -54,10 +55,10 @@ protected:
const PluginMetadata& userlistEntry) {
Plugin plugin(file);
plugin.MergeMetadata(masterlistEntry);
plugin.MergeMetadata(userlistEntry);
plugin.MergeMetadata(evaluateMetadata(masterlistEntry));
plugin.MergeMetadata(evaluateMetadata(userlistEntry));
evaluatePlugin(plugin);
plugin.CheckInstallValidity(state_.getCurrentGame());
return toYaml(plugin);
}
@@ -106,9 +107,10 @@ private:
void evaluateMessageConditions(std::vector<Message>& messages) {
try {
ConditionEvaluator evaluator(&state_.getCurrentGame());
auto it = begin(messages);
while (it != end(messages)) {
if (!it->EvalCondition(state_.getCurrentGame()))
if (!evaluator.evaluate(it->Condition()))
it = messages.erase(it);
else
++it;
@@ -133,20 +135,21 @@ private:
return simpleMessages;
}
void evaluatePlugin(Plugin& plugin) {
//Evaluate any conditions
PluginMetadata evaluateMetadata(const PluginMetadata& pluginMetadata) {
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
try {
plugin.EvalAllConditions(state_.getCurrentGame());
ConditionEvaluator evaluator(&state_.getCurrentGame());
return evaluator.evaluateAll(pluginMetadata);
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "\"" << plugin.Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
std::vector<Message> messages(plugin.Messages());
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % plugin.Name() % e.what()).str()));
plugin.Messages(messages);
BOOST_LOG_TRIVIAL(error) << "\"" << pluginMetadata.Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
std::vector<Message> messages(pluginMetadata.Messages());
messages.push_back(Message(MessageType::error, (boost::format(boost::locale::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % pluginMetadata.Name() % e.what()).str()));
PluginMetadata newMetadata(pluginMetadata);
newMetadata.Messages(messages);
return newMetadata;
}
//Also check install validity.
plugin.CheckInstallValidity(state_.getCurrentGame());
}
YAML::Node toYaml(const Plugin& plugin) {
+1
View File
@@ -32,6 +32,7 @@
#include "tests/backend/helpers/language_test.h"
#include "tests/backend/helpers/version_test.h"
#include "tests/backend/helpers/yaml_set_helpers_test.h"
#include "tests/backend/metadata/condition_evaluator_test.h"
#include "tests/backend/metadata/condition_grammar_test.h"
#include "tests/backend/metadata/conditional_metadata_test.h"
#include "tests/backend/metadata/file_test.h"
@@ -0,0 +1,132 @@
/* 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
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_TESTS_BACKEND_METADATA_CONDITION_EVALUATOR_TEST
#define LOOT_TESTS_BACKEND_METADATA_CONDITION_EVALUATOR_TEST
#include "backend/metadata/condition_evaluator.h"
#include "loot/exception/condition_syntax_error.h"
#include "tests/common_game_test_fixture.h"
namespace loot {
namespace test {
class ConditionEvaluatorTest : public CommonGameTestFixture {
protected:
ConditionEvaluatorTest() :
info_(std::vector<MessageContent>({
MessageContent("info", LanguageCode::english),
})),
game_(GetParam(), dataPath.parent_path(), localPath),
evaluator_(&game_) {}
const std::vector<MessageContent> info_;
Game game_;
ConditionEvaluator evaluator_;
};
// 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(,
ConditionEvaluatorTest,
::testing::Values(
GameType::tes4,
GameType::tes5,
GameType::fo3,
GameType::fonv,
GameType::fo4,
GameType::tes5se));
TEST_P(ConditionEvaluatorTest, evaluateShouldReturnTrueForAnEmptyConditionString) {
EXPECT_TRUE(evaluator_.evaluate(""));
}
TEST_P(ConditionEvaluatorTest, evaluateShouldThrowForAnInvalidConditionString) {
EXPECT_THROW(evaluator_.evaluate("condition"), ConditionSyntaxError);
}
TEST_P(ConditionEvaluatorTest, evaluateShouldReturnTrueForAConditionThatIsTrue) {
EXPECT_TRUE(evaluator_.evaluate("file(\"" + blankEsm + "\")"));
}
TEST_P(ConditionEvaluatorTest, evaluateShouldReturnFalseForAConditionThatIsFalse) {
EXPECT_FALSE(evaluator_.evaluate("file(\"" + missingEsp + "\")"));
}
TEST_P(ConditionEvaluatorTest, evaluateConditionShouldBeTrueIfTheCrcInThePluginCleaningDataGivenMatchesTheRealPluginCrc) {
PluginCleaningData dirtyInfo(blankEsmCrc, "cleaner", info_, 2, 10, 30);
EXPECT_TRUE(evaluator_.evaluate(dirtyInfo, blankEsm));
}
TEST_P(ConditionEvaluatorTest, evaluateShouldBeFalseIfTheCrcInThePluginCleaningDataGivenDoesNotMatchTheRealPluginCrc) {
PluginCleaningData dirtyInfo(0xDEADBEEF, "cleaner", info_, 2, 10, 30);
EXPECT_FALSE(evaluator_.evaluate(dirtyInfo, blankEsm));
}
TEST_P(ConditionEvaluatorTest, evaluateShouldBeFalseIfAnEmptyPluginFilenameIsGiven) {
PluginCleaningData dirtyInfo(blankEsmCrc, "cleaner", info_, 2, 10, 30);
EXPECT_FALSE(evaluator_.evaluate(dirtyInfo, ""));
}
TEST_P(ConditionEvaluatorTest, evaluateAllShouldEvaluateAllMetadataConditions) {
PluginMetadata plugin(blankEsm);
File file1(blankEsp);
File file2(blankDifferentEsm, "", "file(\"" + missingEsp + "\")");
plugin.LoadAfter({file1, file2});
plugin.Reqs({file1, file2});
plugin.Incs({file1, file2});
Message message1(MessageType::say, "content");
Message message2(MessageType::say, "content", "file(\"" + missingEsp + "\")");
plugin.Messages({message1, message2});
Tag tag1("Relev");
Tag tag2("Relev", true, "file(\"" + missingEsp + "\")");
plugin.Tags({tag1, tag2});
PluginCleaningData info1(blankEsmCrc, "utility", info_, 1, 2, 3);
PluginCleaningData info2(0xDEADBEEF, "utility", info_, 1, 2, 3);
plugin.DirtyInfo({info1, info2});
plugin.CleanInfo({info1, info2});
EXPECT_NO_THROW(plugin = evaluator_.evaluateAll(plugin));
std::set<File> expectedFiles({file1});
EXPECT_EQ(expectedFiles, plugin.LoadAfter());
EXPECT_EQ(expectedFiles, plugin.Reqs());
EXPECT_EQ(expectedFiles, plugin.Incs());
EXPECT_EQ(std::vector<Message>({message1}), plugin.Messages());
EXPECT_EQ(std::set<Tag>({tag1}), plugin.Tags());
EXPECT_EQ(std::set<PluginCleaningData>({info1}), plugin.DirtyInfo());
EXPECT_EQ(std::set<PluginCleaningData>({info1}), plugin.CleanInfo());
}
}
}
#endif
@@ -38,6 +38,7 @@ protected:
ConditionGrammarTest() :
resourcePath(dataPath / "resource" / "detail" / "resource.txt"),
game_(GetParam(), dataPath.parent_path(), localPath),
evaluator_(&game_),
result_(false),
success_(false) {}
@@ -83,6 +84,7 @@ protected:
const boost::filesystem::path resourcePath;
Game game_;
ConditionEvaluator evaluator_;
boost::spirit::qi::space_type skipper_;
bool result_;
bool success_;
@@ -101,7 +103,8 @@ INSTANTIATE_TEST_CASE_P(,
GameType::tes5se));
TEST_P(ConditionGrammarTest, parsingInvalidSyntaxShouldThrow) {
Grammar grammar(nullptr);
ConditionEvaluator evaluator(nullptr);
Grammar grammar(evaluator);
std::string condition("file(foo)");
EXPECT_THROW(boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -112,7 +115,7 @@ TEST_P(ConditionGrammarTest, parsingInvalidSyntaxShouldThrow) {
}
TEST_P(ConditionGrammarTest, evaluatingInvalidSyntaxShouldThrow) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(foo)");
EXPECT_THROW(boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -123,7 +126,8 @@ TEST_P(ConditionGrammarTest, evaluatingInvalidSyntaxShouldThrow) {
}
TEST_P(ConditionGrammarTest, parsingAnEmptyConditionShouldThrow) {
Grammar grammar(nullptr);
ConditionEvaluator evaluator(nullptr);
Grammar grammar(evaluator);
std::string condition("");
EXPECT_THROW(boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -134,7 +138,7 @@ TEST_P(ConditionGrammarTest, parsingAnEmptyConditionShouldThrow) {
}
TEST_P(ConditionGrammarTest, evaluatingAnEmptyConditionShouldThrow) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("");
EXPECT_THROW(boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -145,7 +149,7 @@ TEST_P(ConditionGrammarTest, evaluatingAnEmptyConditionShouldThrow) {
}
TEST_P(ConditionGrammarTest, aFileConditionWithAPluginThatExistsShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -158,7 +162,7 @@ TEST_P(ConditionGrammarTest, aFileConditionWithAPluginThatExistsShouldEvaluateTo
}
TEST_P(ConditionGrammarTest, aFileConditionWithAPluginThatDoesNotExistShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + missingEsp + "\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -171,7 +175,7 @@ TEST_P(ConditionGrammarTest, aFileConditionWithAPluginThatDoesNotExistShouldEval
}
TEST_P(ConditionGrammarTest, evaluatingAFileConditionForAnUnsafePathShouldThrow) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"../../" + blankEsm + "\")");
EXPECT_THROW(boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -182,7 +186,7 @@ TEST_P(ConditionGrammarTest, evaluatingAFileConditionForAnUnsafePathShouldThrow)
}
TEST_P(ConditionGrammarTest, aFileConditionWithAnInvalidRegexShouldThrow) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"RagnvaldBook(Farengar(+Ragnvald)?)?\\.esp\")");
EXPECT_THROW(boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -193,7 +197,7 @@ TEST_P(ConditionGrammarTest, aFileConditionWithAnInvalidRegexShouldThrow) {
}
TEST_P(ConditionGrammarTest, aFileConditionWithARegexMatchingAPluginThatExistsShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"Blank.+\\.esm\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -206,7 +210,7 @@ TEST_P(ConditionGrammarTest, aFileConditionWithARegexMatchingAPluginThatExistsSh
}
TEST_P(ConditionGrammarTest, aFileConditionWithARegexMatchingAPluginThatDoesNotExistShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"Blank\\.m.+\\.esm\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -219,7 +223,7 @@ TEST_P(ConditionGrammarTest, aFileConditionWithARegexMatchingAPluginThatDoesNotE
}
TEST_P(ConditionGrammarTest, aFileConditionWithARegexMatchingAFileInASubfolderThatExistsShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"resource/detail/resource\\.txt\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -232,7 +236,7 @@ TEST_P(ConditionGrammarTest, aFileConditionWithARegexMatchingAFileInASubfolderTh
}
TEST_P(ConditionGrammarTest, aManyConditionWithARegexMatchingMoreThanOnePluginShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("many(\"Blank.+\\.esm\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -245,7 +249,7 @@ TEST_P(ConditionGrammarTest, aManyConditionWithARegexMatchingMoreThanOnePluginSh
}
TEST_P(ConditionGrammarTest, aManyConditionWithARegexMatchingOnlyOnePluginShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("many(\"Blank\\.esm\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -258,7 +262,7 @@ TEST_P(ConditionGrammarTest, aManyConditionWithARegexMatchingOnlyOnePluginShould
}
TEST_P(ConditionGrammarTest, aChecksumConditionWithACrcThatMatchesTheActualPluginCrcShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("checksum(\"" + blankEsm + "\", " + IntToHexString(blankEsmCrc) + ")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -274,7 +278,7 @@ TEST_P(ConditionGrammarTest, aChecksumConditionWithACrcThatMatchesTheActualCache
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, false));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("checksum(\"" + blankEsm + "\", " + IntToHexString(blankEsmCrc) + ")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -287,7 +291,7 @@ TEST_P(ConditionGrammarTest, aChecksumConditionWithACrcThatMatchesTheActualCache
}
TEST_P(ConditionGrammarTest, aChecksumConditionWithACrcThatDoesNotMatchTheActualPluginCrcShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("checksum(\"" + blankEsm + "\", DEADBEEF)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -303,7 +307,7 @@ TEST_P(ConditionGrammarTest, aVersionEqualityConditionWithAVersionThatEqualsTheA
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"5.0\", ==)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -319,7 +323,7 @@ TEST_P(ConditionGrammarTest, aVersionEqualityConditionWithAVersionThatDoesNotEqu
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"6.0\", ==)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -335,7 +339,7 @@ TEST_P(ConditionGrammarTest, aVersionEqualityConditionForAPluginWithNoVersionSho
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsp + "\", \"6.0\", ==)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -351,7 +355,7 @@ TEST_P(ConditionGrammarTest, aVersionInequalityConditionWithAVersionThatDoesNotE
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"6.0\", !=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -367,7 +371,7 @@ TEST_P(ConditionGrammarTest, aVersionInequalityConditionWithAVersionThatEqualsTh
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"5.0\", !=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -383,7 +387,7 @@ TEST_P(ConditionGrammarTest, aVersionInequalityConditionForAPluginWithNoVersionS
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsp + "\", \"6.0\", !=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -399,7 +403,7 @@ TEST_P(ConditionGrammarTest, aVersionLessThanConditionWithAnActualPluginVersionL
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"6.0\", <)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -415,7 +419,7 @@ TEST_P(ConditionGrammarTest, aVersionLessThanConditionWithAnActualPluginVersionE
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"5.0\", <)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -431,7 +435,7 @@ TEST_P(ConditionGrammarTest, aVersionLessThanConditionForAPluginWithNoVersionSho
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsp + "\", \"5.0\", <)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -447,7 +451,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanConditionWithAnActualPluginVersi
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"4.0\", >)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -463,7 +467,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanConditionWithAnActualPluginVersi
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"5.0\", >)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -479,7 +483,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanConditionForAPluginWithNoVersion
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsp + "\", \"5.0\", >)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -495,7 +499,7 @@ TEST_P(ConditionGrammarTest, aVersionLessThanOrEqualToConditionWithAnActualPlugi
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"5.0\", <=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -511,7 +515,7 @@ TEST_P(ConditionGrammarTest, aVersionLessThanOrEqualToConditionWithAnActualPlugi
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"4.0\", <=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -527,7 +531,7 @@ TEST_P(ConditionGrammarTest, aVersionLessThanOrEqualToConditionForAPluginWithNoV
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsp + "\", \"5.0\", <=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -543,7 +547,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanOrEqualToConditionWithAnActualPl
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"5.0\", >=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -559,7 +563,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanOrEqualToConditionWithAnActualPl
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsm + "\", \"6.0\", >=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -575,7 +579,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanOrEqualToConditionForAPluginWith
ASSERT_NO_THROW(game_.Init());
ASSERT_NO_THROW(loadInstalledPlugins(game_, true));
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("version(\"" + blankEsp + "\", \"5.0\", >=)");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -590,7 +594,7 @@ TEST_P(ConditionGrammarTest, aVersionGreaterThanOrEqualToConditionForAPluginWith
TEST_P(ConditionGrammarTest, anActiveConditionWithAPluginThatIsActiveShouldEvaluateToTrue) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("active(\"" + blankEsm + "\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -605,7 +609,7 @@ TEST_P(ConditionGrammarTest, anActiveConditionWithAPluginThatIsActiveShouldEvalu
TEST_P(ConditionGrammarTest, anActiveConditionWithAPluginThatIsNotActiveShouldEvaluateToFalse) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("active(\"" + blankEsp + "\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -620,7 +624,7 @@ TEST_P(ConditionGrammarTest, anActiveConditionWithAPluginThatIsNotActiveShouldEv
TEST_P(ConditionGrammarTest, anActiveConditionWithARegexMatchingAnActivePluginShouldEvaluateToTrue) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("active(\"Blank\\.esm\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -635,7 +639,7 @@ TEST_P(ConditionGrammarTest, anActiveConditionWithARegexMatchingAnActivePluginSh
TEST_P(ConditionGrammarTest, anActiveConditionWithARegexMatchingNoActivePluginsShouldEvaluateToFalse) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("active(\"Blank\\.esp\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -650,7 +654,7 @@ TEST_P(ConditionGrammarTest, anActiveConditionWithARegexMatchingNoActivePluginsS
TEST_P(ConditionGrammarTest, aManyActiveConditionWithARegexMatchingMoreThanOnePluginThatIsActiveShouldEvaluateToTrue) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("many_active(\"Blank( - Different Master Dependent)?\\.es(m|p)\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -665,7 +669,7 @@ TEST_P(ConditionGrammarTest, aManyActiveConditionWithARegexMatchingMoreThanOnePl
TEST_P(ConditionGrammarTest, aManyActiveConditionWithARegexMatchingOnlyOnePluginThatIsActiveShouldEvaluateToFalse) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("many_active(\"Blank\\.esm\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -680,7 +684,7 @@ TEST_P(ConditionGrammarTest, aManyActiveConditionWithARegexMatchingOnlyOnePlugin
TEST_P(ConditionGrammarTest, aManyActiveConditionWithARegexMatchingNoPluginsThatAreActiveShouldEvaluateToFalse) {
ASSERT_NO_THROW(game_.Init());
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("many_active(\"Blank\\.esp\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -693,7 +697,7 @@ TEST_P(ConditionGrammarTest, aManyActiveConditionWithARegexMatchingNoPluginsThat
}
TEST_P(ConditionGrammarTest, aFalseConditionPrecededByANegatorShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("not file(\"" + missingEsp + "\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -706,7 +710,7 @@ TEST_P(ConditionGrammarTest, aFalseConditionPrecededByANegatorShouldEvaluateToTr
}
TEST_P(ConditionGrammarTest, aTrueConditionPrecededByANegatorShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("not file(\"" + blankEsm + "\")");
success_ = boost::spirit::qi::phrase_parse(std::cbegin(condition),
@@ -719,7 +723,7 @@ TEST_P(ConditionGrammarTest, aTrueConditionPrecededByANegatorShouldEvaluateToFal
}
TEST_P(ConditionGrammarTest, twoTrueConditionsJoinedByAnAndShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
std::string compound(condition + " and " + condition);
@@ -733,7 +737,7 @@ TEST_P(ConditionGrammarTest, twoTrueConditionsJoinedByAnAndShouldEvaluateToTrue)
}
TEST_P(ConditionGrammarTest, aTrueAndAFalseConditionJoinedByAnAndShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
std::string compound(condition + " and not " + condition);
@@ -747,7 +751,7 @@ TEST_P(ConditionGrammarTest, aTrueAndAFalseConditionJoinedByAnAndShouldEvaluateT
}
TEST_P(ConditionGrammarTest, aFalseAndATrueConditionJoinedByAnOrShouldEvaluateToTrue) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
std::string compound("not " + condition + " or " + condition);
@@ -761,7 +765,7 @@ TEST_P(ConditionGrammarTest, aFalseAndATrueConditionJoinedByAnOrShouldEvaluateTo
}
TEST_P(ConditionGrammarTest, twoFalseConditionsJoinedByAnOrShouldEvaluateToFalse) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
std::string compound("not " + condition + " or not " + condition);
@@ -775,7 +779,7 @@ TEST_P(ConditionGrammarTest, twoFalseConditionsJoinedByAnOrShouldEvaluateToFalse
}
TEST_P(ConditionGrammarTest, andOperatorsShouldTakePrecedenceOverOrOperators) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
std::string compound("not " + condition + " and " + condition + " or " + condition);
@@ -789,7 +793,7 @@ TEST_P(ConditionGrammarTest, andOperatorsShouldTakePrecedenceOverOrOperators) {
}
TEST_P(ConditionGrammarTest, parenthesesShouldTakePrecedenceOverAndOperators) {
Grammar grammar(&game_);
Grammar grammar(evaluator_);
std::string condition("file(\"" + blankEsm + "\")");
std::string compound("not " + condition + " and ( " + condition + " or " + condition + " )");
@@ -68,33 +68,6 @@ TEST_P(ConditionalMetadataTest, isConditionalShouldBeTrueForANonEmptyConditionSt
EXPECT_TRUE(conditionalMetadata_.IsConditional());
}
TEST_P(ConditionalMetadataTest, evalConditionShouldReturnTrueForAnEmptyCondition) {
Game game(GetParam(), dataPath.parent_path(), localPath);
EXPECT_TRUE(conditionalMetadata_.EvalCondition(game));
}
TEST_P(ConditionalMetadataTest, evalConditionShouldThrowForAnInvalidCondition) {
Game game(GetParam(), dataPath.parent_path(), localPath);
conditionalMetadata_ = ConditionalMetadata("condition");
EXPECT_THROW(conditionalMetadata_.EvalCondition(game), ConditionSyntaxError);
}
TEST_P(ConditionalMetadataTest, evalConditionShouldReturnTrueForAConditionThatIsTrue) {
Game game(GetParam(), dataPath.parent_path(), localPath);
conditionalMetadata_ = ConditionalMetadata("file(\"" + blankEsm + "\")");
EXPECT_TRUE(conditionalMetadata_.EvalCondition(game));
}
TEST_P(ConditionalMetadataTest, evalConditionShouldReturnFalseForAConditionThatIsFalse) {
Game game(GetParam(), dataPath.parent_path(), localPath);
conditionalMetadata_ = ConditionalMetadata("file(\"" + missingEsp + "\")");
EXPECT_FALSE(conditionalMetadata_.EvalCondition(game));
}
TEST_P(ConditionalMetadataTest, parseConditionShouldNotThrowForAnEmptyCondition) {
EXPECT_NO_THROW(conditionalMetadata_.ParseCondition());
}
@@ -145,27 +145,6 @@ TEST_P(PluginCleaningDataTest, LessThanOperatorShouldCompareCrcValues) {
EXPECT_FALSE(info2 < info1);
}
TEST_P(PluginCleaningDataTest, evalConditionShouldBeTrueIfTheCrcGivenMatchesTheRealPluginCrc) {
Game game(GetParam(), dataPath.parent_path(), localPath);
PluginCleaningData dirtyInfo(blankEsmCrc, "cleaner", info_, 2, 10, 30);
EXPECT_TRUE(dirtyInfo.EvalCondition(game, blankEsm));
}
TEST_P(PluginCleaningDataTest, evalConditionShouldBeFalseIfTheCrcGivenDoesNotMatchTheRealPluginCrc) {
Game game(GetParam(), dataPath.parent_path(), localPath);
PluginCleaningData dirtyInfo(0xDEADBEEF, "cleaner", info_, 2, 10, 30);
EXPECT_FALSE(dirtyInfo.EvalCondition(game, blankEsm));
}
TEST_P(PluginCleaningDataTest, evalConditionShouldBeFalseIfAnEmptyPluginFilenameIsGiven) {
Game game(GetParam(), dataPath.parent_path(), localPath);
PluginCleaningData dirtyInfo;
EXPECT_FALSE(dirtyInfo.EvalCondition(game, ""));
}
TEST_P(PluginCleaningDataTest, chooseInfoShouldCreateADefaultContentObjectIfNoneExists) {
PluginCleaningData dirtyInfo(0xDEADBEEF, "cleaner", std::vector<MessageContent>(), 2, 10, 30);
EXPECT_EQ(MessageContent(), dirtyInfo.ChooseInfo(LanguageCode::english));
@@ -476,42 +476,6 @@ TEST_P(PluginMetadataTest, simpleMessagesShouldReturnMessagesAsSimpleMessages) {
EXPECT_EQ("content3", simpleMessages.back().text);
}
TEST_P(PluginMetadataTest, evalAllConditionsShouldEvaluateAllMetadataConditions) {
Game game(GetParam(), dataPath.parent_path(), localPath);
PluginMetadata plugin(blankEsm);
File file1(blankEsp);
File file2(blankDifferentEsm, "", "file(\"" + missingEsp + "\")");
plugin.LoadAfter({file1, file2});
plugin.Reqs({file1, file2});
plugin.Incs({file1, file2});
Message message1(MessageType::say, "content");
Message message2(MessageType::say, "content", "file(\"" + missingEsp + "\")");
plugin.Messages({message1, message2});
Tag tag1("Relev");
Tag tag2("Relev", true, "file(\"" + missingEsp + "\")");
plugin.Tags({tag1, tag2});
PluginCleaningData info1(blankEsmCrc, "utility", info_, 1, 2, 3);
PluginCleaningData info2(0xDEADBEEF, "utility", info_, 1, 2, 3);
plugin.DirtyInfo({info1, info2});
plugin.CleanInfo({info1, info2});
EXPECT_NO_THROW(plugin.EvalAllConditions(game));
std::set<File> expectedFiles({file1});
EXPECT_EQ(expectedFiles, plugin.LoadAfter());
EXPECT_EQ(expectedFiles, plugin.Reqs());
EXPECT_EQ(expectedFiles, plugin.Incs());
EXPECT_EQ(std::vector<Message>({message1}), plugin.Messages());
EXPECT_EQ(std::set<Tag>({tag1}), plugin.Tags());
EXPECT_EQ(std::set<PluginCleaningData>({info1}), plugin.DirtyInfo());
EXPECT_EQ(std::set<PluginCleaningData>({info1}), plugin.CleanInfo());
}
TEST_P(PluginMetadataTest, hasNameOnlyShouldBeTrueForADefaultConstructedPluginMetadataObject) {
PluginMetadata plugin;