diff --git a/CMakeLists.txt b/CMakeLists.txt index 19f2568b..bdd39c9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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" diff --git a/include/loot/metadata/conditional_metadata.h b/include/loot/metadata/conditional_metadata.h index af758709..05c69904 100644 --- a/include/loot/metadata/conditional_metadata.h +++ b/include/loot/metadata/conditional_metadata.h @@ -27,21 +27,16 @@ #include 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_; }; } diff --git a/include/loot/metadata/plugin_cleaning_data.h b/include/loot/metadata/plugin_cleaning_data.h index 330b45eb..9686cdc4 100644 --- a/include/loot/metadata/plugin_cleaning_data.h +++ b/include/loot/metadata/plugin_cleaning_data.h @@ -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_; diff --git a/include/loot/metadata/plugin_metadata.h b/include/loot/metadata/plugin_metadata.h index 247a040d..8d6a16d4 100644 --- a/include/loot/metadata/plugin_metadata.h +++ b/include/loot/metadata/plugin_metadata.h @@ -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& info); void Locations(const std::set& locations); - PluginMetadata& EvalAllConditions(Game& game); bool HasNameOnly() const; bool IsRegexPlugin() const; diff --git a/resources/l10n/template.pot b/resources/l10n/template.pot index 56e40fda..d0c9b935 100644 --- a/resources/l10n/template.pot +++ b/resources/l10n/template.pot @@ -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 \n" "Language-Team: LANGUAGE \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 "" diff --git a/src/backend/metadata/condition_evaluator.cpp b/src/backend/metadata/condition_evaluator.cpp index 9edd695b..6a6e0655 100644 --- a/src/backend/metadata/condition_evaluator.cpp +++ b/src/backend/metadata/condition_evaluator.cpp @@ -29,6 +29,7 @@ #include #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 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 messages; + for (const auto& message : pluginMetadata.Messages()) { + if (evaluate(message.Condition())) + messages.push_back(message); + } + evaluatedMetadata.Messages(messages); + + std::set tagSet; + for (const auto& tag : pluginMetadata.Tags()) { + if (evaluate(tag.Condition())) + tagSet.insert(tag); + } + evaluatedMetadata.Tags(tagSet); + + if (!evaluatedMetadata.IsRegexPlugin()) { + std::set 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 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")); diff --git a/src/backend/metadata/condition_evaluator.h b/src/backend/metadata/condition_evaluator.h index 673d2913..589eb9aa 100644 --- a/src/backend/metadata/condition_evaluator.h +++ b/src/backend/metadata/condition_evaluator.h @@ -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& pathRegex, const std::function condition) const; + bool parseCondition(const std::string& condition); + Version getVersion(const std::string& filePath) const; Game * game_; diff --git a/src/backend/metadata/condition_grammar.h b/src/backend/metadata/condition_grammar.h index 33cff7dd..eb30465f 100644 --- a/src/backend/metadata/condition_grammar.h +++ b/src/backend/metadata/condition_grammar.h @@ -56,7 +56,7 @@ template 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 quotedStr_, filePath_, comparator_; boost::spirit::qi::rule invalidPathChars_; - ConditionEvaluator evaluator; + ConditionEvaluator& evaluator_; }; } #endif diff --git a/src/backend/metadata/conditional_metadata.cpp b/src/backend/metadata/conditional_metadata.cpp index d801933c..d62e5996 100644 --- a/src/backend/metadata/conditional_metadata.cpp +++ b/src/backend/metadata/conditional_metadata.cpp @@ -28,7 +28,7 @@ #include #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 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_); } } diff --git a/src/backend/metadata/plugin_cleaning_data.cpp b/src/backend/metadata/plugin_cleaning_data.cpp index ac4750a5..59dec880 100644 --- a/src/backend/metadata/plugin_cleaning_data.cpp +++ b/src/backend/metadata/plugin_cleaning_data.cpp @@ -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; -} } diff --git a/src/backend/metadata/plugin_metadata.cpp b/src/backend/metadata/plugin_metadata.cpp index 4184899a..0127c867 100644 --- a/src/backend/metadata/plugin_metadata.cpp +++ b/src/backend/metadata/plugin_metadata.cpp @@ -272,63 +272,6 @@ void PluginMetadata::Locations(const std::set& 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() diff --git a/src/backend/metadata_list.cpp b/src/backend/metadata_list.cpp index 1455f764..25a69e8b 100644 --- a/src/backend/metadata_list.cpp +++ b/src/backend/metadata_list.cpp @@ -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 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; } } } diff --git a/src/backend/plugin/plugin_sorter.cpp b/src/backend/plugin/plugin_sorter.cpp index 44e537a1..e0b0057b 100644 --- a/src/backend/plugin/plugin_sorter.cpp +++ b/src/backend/plugin/plugin_sorter.cpp @@ -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 messages(graph_[v].Messages()); diff --git a/src/gui/query/metadata_query.h b/src/gui/query/metadata_query.h index 46e0eac1..d0702ab3 100644 --- a/src/gui/query/metadata_query.h +++ b/src/gui/query/metadata_query.h @@ -29,6 +29,7 @@ along with LOOT. If not, see #include #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& 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 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 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) { diff --git a/src/tests/backend/main.cpp b/src/tests/backend/main.cpp index efc9c281..d4bc3577 100644 --- a/src/tests/backend/main.cpp +++ b/src/tests/backend/main.cpp @@ -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" diff --git a/src/tests/backend/metadata/condition_evaluator_test.h b/src/tests/backend/metadata/condition_evaluator_test.h new file mode 100644 index 00000000..5937fe0d --- /dev/null +++ b/src/tests/backend/metadata/condition_evaluator_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 +. +*/ + +#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("info", LanguageCode::english), + })), + game_(GetParam(), dataPath.parent_path(), localPath), + evaluator_(&game_) {} + + const std::vector 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 expectedFiles({file1}); + EXPECT_EQ(expectedFiles, plugin.LoadAfter()); + EXPECT_EQ(expectedFiles, plugin.Reqs()); + EXPECT_EQ(expectedFiles, plugin.Incs()); + EXPECT_EQ(std::vector({message1}), plugin.Messages()); + EXPECT_EQ(std::set({tag1}), plugin.Tags()); + EXPECT_EQ(std::set({info1}), plugin.DirtyInfo()); + EXPECT_EQ(std::set({info1}), plugin.CleanInfo()); +} +} +} + +#endif diff --git a/src/tests/backend/metadata/condition_grammar_test.h b/src/tests/backend/metadata/condition_grammar_test.h index 49b2d1f9..5e82e8e7 100644 --- a/src/tests/backend/metadata/condition_grammar_test.h +++ b/src/tests/backend/metadata/condition_grammar_test.h @@ -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 + " )"); diff --git a/src/tests/backend/metadata/conditional_metadata_test.h b/src/tests/backend/metadata/conditional_metadata_test.h index 49b2f4c1..7894abf2 100644 --- a/src/tests/backend/metadata/conditional_metadata_test.h +++ b/src/tests/backend/metadata/conditional_metadata_test.h @@ -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()); } diff --git a/src/tests/backend/metadata/plugin_cleaning_data_test.h b/src/tests/backend/metadata/plugin_cleaning_data_test.h index 8f4a378b..b59476a7 100644 --- a/src/tests/backend/metadata/plugin_cleaning_data_test.h +++ b/src/tests/backend/metadata/plugin_cleaning_data_test.h @@ -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(), 2, 10, 30); EXPECT_EQ(MessageContent(), dirtyInfo.ChooseInfo(LanguageCode::english)); diff --git a/src/tests/backend/metadata/plugin_metadata_test.h b/src/tests/backend/metadata/plugin_metadata_test.h index 2ac67ac4..c231b87d 100644 --- a/src/tests/backend/metadata/plugin_metadata_test.h +++ b/src/tests/backend/metadata/plugin_metadata_test.h @@ -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 expectedFiles({file1}); - EXPECT_EQ(expectedFiles, plugin.LoadAfter()); - EXPECT_EQ(expectedFiles, plugin.Reqs()); - EXPECT_EQ(expectedFiles, plugin.Incs()); - EXPECT_EQ(std::vector({message1}), plugin.Messages()); - EXPECT_EQ(std::set({tag1}), plugin.Tags()); - EXPECT_EQ(std::set({info1}), plugin.DirtyInfo()); - EXPECT_EQ(std::set({info1}), plugin.CleanInfo()); -} - TEST_P(PluginMetadataTest, hasNameOnlyShouldBeTrueForADefaultConstructedPluginMetadataObject) { PluginMetadata plugin;