From a2813f0e4d660ba41b34b8f1e9919a20b4a72e31 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sat, 5 Dec 2015 13:32:22 +0000 Subject: [PATCH] Refactor dirty metadata evaluation Into the PluginDirtyInfo class, to match other conditional metadata. --- src/backend/metadata/plugin_dirty_info.cpp | 28 +++++ src/backend/metadata/plugin_dirty_info.h | 4 + src/backend/metadata/plugin_metadata.cpp | 28 +---- .../backend/metadata/test_plugin_dirty_info.h | 111 +++++++++++------- 4 files changed, 101 insertions(+), 70 deletions(-) diff --git a/src/backend/metadata/plugin_dirty_info.cpp b/src/backend/metadata/plugin_dirty_info.cpp index edbf27de..03f68346 100644 --- a/src/backend/metadata/plugin_dirty_info.cpp +++ b/src/backend/metadata/plugin_dirty_info.cpp @@ -24,6 +24,9 @@ #include "plugin_dirty_info.h" +#include "../game/game.h" +#include "../helpers/helpers.h" + #include #include @@ -86,6 +89,31 @@ namespace loot { return Message(Message::warn, f.str()); } + + bool PluginDirtyInfo::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. + auto pluginPairIt = game.plugins.find(boost::locale::to_lower(pluginName)); + if (pluginPairIt != game.plugins.end()) + crc = pluginPairIt->second.Crc(); + + // 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; + } } namespace YAML { diff --git a/src/backend/metadata/plugin_dirty_info.h b/src/backend/metadata/plugin_dirty_info.h index 195f6af4..0fa6ec04 100644 --- a/src/backend/metadata/plugin_dirty_info.h +++ b/src/backend/metadata/plugin_dirty_info.h @@ -32,6 +32,8 @@ #include namespace loot { + class Game; + class PluginDirtyInfo { public: PluginDirtyInfo(); @@ -47,6 +49,8 @@ namespace loot { std::string CleaningUtility() const; Message AsMessage() const; + + bool EvalCondition(Game& game, const std::string& pluginName) const; private: uint32_t _crc; unsigned int _itm; diff --git a/src/backend/metadata/plugin_metadata.cpp b/src/backend/metadata/plugin_metadata.cpp index e5a6ca0a..44ce201d 100644 --- a/src/backend/metadata/plugin_metadata.cpp +++ b/src/backend/metadata/plugin_metadata.cpp @@ -296,33 +296,11 @@ namespace loot { ++it; } - // Regex plugins shouldn't have dirty info, but just clear in case. - if (IsRegexPlugin()) + if (IsRegexPlugin()) // Remove any dirty metadata from a regex plugin. _dirtyInfo.clear(); - - if (!_dirtyInfo.empty()) { - //First need to get plugin's CRC, if it is an exact plugin and it does not have its CRC set. - uint32_t crc = game.GetCachedCrc(name); - if (crc == 0) { - if (boost::filesystem::exists(game.DataPath() / name)) { - crc = GetCrc32(game.DataPath() / name); - } - else if (boost::filesystem::exists(game.DataPath() / (name + ".ghost"))) { - crc = GetCrc32(game.DataPath() / (name + ".ghost")); - } - else { - // The plugin isn't installed, discard the dirty info. - _dirtyInfo.clear(); - } - - // Store the CRC in the cache in case it's not already in there. - if (crc != 0) - game.CacheCrc(name, crc); - } - - // Now use the CRC to evaluate the dirty info. + else { for (auto it = _dirtyInfo.begin(); it != _dirtyInfo.end();) { - if (it->CRC() != crc) + if (!it->EvalCondition(game, name)) _dirtyInfo.erase(it++); else ++it; diff --git a/src/tests/backend/metadata/test_plugin_dirty_info.h b/src/tests/backend/metadata/test_plugin_dirty_info.h index b6121574..72336533 100644 --- a/src/tests/backend/metadata/test_plugin_dirty_info.h +++ b/src/tests/backend/metadata/test_plugin_dirty_info.h @@ -28,17 +28,17 @@ along with LOOT. If not, see #include "backend/metadata/plugin_dirty_info.h" #include "tests/fixtures.h" -using loot::PluginDirtyInfo; +class PluginDirtyInfo : public SkyrimTest {}; -TEST(PluginDirtyInfo, ConstructorsAndDataAccess) { - PluginDirtyInfo info; +TEST_F(PluginDirtyInfo, ConstructorsAndDataAccess) { + loot::PluginDirtyInfo info; EXPECT_EQ(0, info.CRC()); EXPECT_EQ(0, info.ITMs()); EXPECT_EQ(0, info.DeletedRefs()); EXPECT_EQ(0, info.DeletedNavmeshes()); EXPECT_EQ("", info.CleaningUtility()); - info = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); EXPECT_EQ(0x12345678, info.CRC()); EXPECT_EQ(2, info.ITMs()); EXPECT_EQ(10, info.DeletedRefs()); @@ -46,100 +46,121 @@ TEST(PluginDirtyInfo, ConstructorsAndDataAccess) { EXPECT_EQ("cleaner", info.CleaningUtility()); } -TEST(PluginDirtyInfo, MessageOutput) { +TEST_F(PluginDirtyInfo, MessageOutput) { loot::Message message; - message = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 2 ITM records, 10 deleted references and 30 deleted navmeshes. Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 0, 0, 0, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 0, 0, 0, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 0, 10, 30, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 0, 10, 30, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 10 deleted references and 30 deleted navmeshes. Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 0, 0, 30, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 0, 0, 30, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 30 deleted navmeshes. Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 0, 10, 0, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 0, 10, 0, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 10 deleted references. Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 2, 0, 30, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 2, 0, 30, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 2 ITM records and 30 deleted navmeshes. Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 2, 0, 0, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 2, 0, 0, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 2 ITM records. Clean with cleaner.", message.ChooseContent(Language::any).Str()); - message = PluginDirtyInfo(0x12345678, 2, 10, 0, "cleaner").AsMessage(); + message = loot::PluginDirtyInfo(0x12345678, 2, 10, 0, "cleaner").AsMessage(); EXPECT_EQ(loot::Message::warn, message.Type()); EXPECT_EQ("Contains 2 ITM records and 10 deleted references. Clean with cleaner.", message.ChooseContent(Language::any).Str()); } -TEST(PluginDirtyInfo, EqualityOperator) { - PluginDirtyInfo info1, info2; +TEST_F(PluginDirtyInfo, EqualityOperator) { + loot::PluginDirtyInfo info1, info2; EXPECT_TRUE(info1 == info2); - info1 = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner1"); - info2 = PluginDirtyInfo(0x12345678, 4, 20, 60, "cleaner2"); + info1 = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner1"); + info2 = loot::PluginDirtyInfo(0x12345678, 4, 20, 60, "cleaner2"); EXPECT_TRUE(info1 == info2); - info1 = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); - info2 = PluginDirtyInfo(0x87654321, 2, 10, 30, "cleaner"); + info1 = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); + info2 = loot::PluginDirtyInfo(0x87654321, 2, 10, 30, "cleaner"); EXPECT_FALSE(info1 == info2); } -TEST(PluginDirtyInfo, LessThanOperator) { - PluginDirtyInfo info1, info2; +TEST_F(PluginDirtyInfo, LessThanOperator) { + loot::PluginDirtyInfo info1, info2; EXPECT_FALSE(info1 < info2); EXPECT_FALSE(info2 < info1); - info1 = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner1"); - info2 = PluginDirtyInfo(0x12345678, 4, 20, 60, "cleaner2"); + info1 = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner1"); + info2 = loot::PluginDirtyInfo(0x12345678, 4, 20, 60, "cleaner2"); EXPECT_FALSE(info1 < info2); EXPECT_FALSE(info2 < info1); - info1 = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); - info2 = PluginDirtyInfo(0x87654321, 2, 10, 30, "cleaner"); + info1 = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); + info2 = loot::PluginDirtyInfo(0x87654321, 2, 10, 30, "cleaner"); EXPECT_TRUE(info1 < info2); EXPECT_FALSE(info2 < info1); } -TEST(PluginDirtyInfo, YamlEmitter) { - PluginDirtyInfo info; +TEST_F(PluginDirtyInfo, EvalConditionTrue) { + loot::Game game(loot::Game::tes5); + game.SetGamePath(dataPath.parent_path()); + ASSERT_NO_THROW(game.Init(false, localPath)); - info = PluginDirtyInfo(0x12345678, 0, 0, 0, "cleaner"); + loot::PluginDirtyInfo dirtyInfo = loot::PluginDirtyInfo(0x24F0E2A1, 2, 10, 30, "cleaner"); + EXPECT_TRUE(dirtyInfo.EvalCondition(game, "Blank.esp")); +} + +TEST_F(PluginDirtyInfo, EvalConditionFalse) { + loot::Game game(loot::Game::tes5); + game.SetGamePath(dataPath.parent_path()); + ASSERT_NO_THROW(game.Init(false, localPath)); + + loot::PluginDirtyInfo dirtyInfo; + EXPECT_FALSE(dirtyInfo.EvalCondition(game, "")); + + dirtyInfo = loot::PluginDirtyInfo(0xDEADBEEF, 2, 10, 30, "cleaner"); + EXPECT_FALSE(dirtyInfo.EvalCondition(game, "Blank.esp")); +} + +TEST_F(PluginDirtyInfo, YamlEmitter) { + loot::PluginDirtyInfo info; + + info = loot::PluginDirtyInfo(0x12345678, 0, 0, 0, "cleaner"); YAML::Emitter e1; e1 << info; EXPECT_STREQ("crc: 0x12345678\nutil: 'cleaner'", e1.c_str()); - info = PluginDirtyInfo(0x12345678, 2, 0, 0, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 0, 0, "cleaner"); YAML::Emitter e2; e2 << info; EXPECT_STREQ("crc: 0x12345678\nutil: 'cleaner'\nitm: 2", e2.c_str()); - info = PluginDirtyInfo(0x12345678, 2, 10, 0, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 10, 0, "cleaner"); YAML::Emitter e3; e3 << info; EXPECT_STREQ("crc: 0x12345678\nutil: 'cleaner'\nitm: 2\nudr: 10", e3.c_str()); - info = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); YAML::Emitter e4; e4 << info; EXPECT_STREQ("crc: 0x12345678\nutil: 'cleaner'\nitm: 2\nudr: 10\nnav: 30", e4.c_str()); } -TEST(PluginDirtyInfo, YamlEncode) { +TEST_F(PluginDirtyInfo, YamlEncode) { YAML::Node node; - PluginDirtyInfo info; + loot::PluginDirtyInfo info; - info = PluginDirtyInfo(0x12345678, 0, 0, 0, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 0, 0, 0, "cleaner"); node = info; EXPECT_EQ(0x12345678, node["crc"].as()); EXPECT_EQ("cleaner", node["util"].as()); @@ -147,7 +168,7 @@ TEST(PluginDirtyInfo, YamlEncode) { EXPECT_FALSE(node["udr"]); EXPECT_FALSE(node["nav"]); - info = PluginDirtyInfo(0x12345678, 2, 0, 0, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 0, 0, "cleaner"); node = info; EXPECT_EQ(0x12345678, node["crc"].as()); EXPECT_EQ("cleaner", node["util"].as()); @@ -155,7 +176,7 @@ TEST(PluginDirtyInfo, YamlEncode) { EXPECT_FALSE(node["udr"]); EXPECT_FALSE(node["nav"]); - info = PluginDirtyInfo(0x12345678, 2, 10, 0, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 10, 0, "cleaner"); node = info; EXPECT_EQ(0x12345678, node["crc"].as()); EXPECT_EQ("cleaner", node["util"].as()); @@ -163,7 +184,7 @@ TEST(PluginDirtyInfo, YamlEncode) { EXPECT_EQ(10, node["udr"].as()); EXPECT_FALSE(node["nav"]); - info = PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); + info = loot::PluginDirtyInfo(0x12345678, 2, 10, 30, "cleaner"); node = info; EXPECT_EQ(0x12345678, node["crc"].as()); EXPECT_EQ("cleaner", node["util"].as()); @@ -172,12 +193,12 @@ TEST(PluginDirtyInfo, YamlEncode) { EXPECT_EQ(30, node["nav"].as()); } -TEST(PluginDirtyInfo, YamlDecode) { +TEST_F(PluginDirtyInfo, YamlDecode) { YAML::Node node; - PluginDirtyInfo info; + loot::PluginDirtyInfo info; node = YAML::Load("{crc: 0x12345678, util: cleaner}"); - info = node.as(); + info = node.as(); EXPECT_EQ(0x12345678, info.CRC()); EXPECT_EQ(0, info.ITMs()); EXPECT_EQ(0, info.DeletedRefs()); @@ -185,7 +206,7 @@ TEST(PluginDirtyInfo, YamlDecode) { EXPECT_EQ("cleaner", info.CleaningUtility()); node = YAML::Load("{crc: 0x12345678, util: cleaner, itm: 2}"); - info = node.as(); + info = node.as(); EXPECT_EQ(0x12345678, info.CRC()); EXPECT_EQ(2, info.ITMs()); EXPECT_EQ(0, info.DeletedRefs()); @@ -193,7 +214,7 @@ TEST(PluginDirtyInfo, YamlDecode) { EXPECT_EQ("cleaner", info.CleaningUtility()); node = YAML::Load("{crc: 0x12345678, util: cleaner, itm: 2, udr: 10}"); - info = node.as(); + info = node.as(); EXPECT_EQ(0x12345678, info.CRC()); EXPECT_EQ(2, info.ITMs()); EXPECT_EQ(10, info.DeletedRefs()); @@ -201,7 +222,7 @@ TEST(PluginDirtyInfo, YamlDecode) { EXPECT_EQ("cleaner", info.CleaningUtility()); node = YAML::Load("{crc: 0x12345678, util: cleaner, itm: 2, udr: 10, nav: 30}"); - info = node.as(); + info = node.as(); EXPECT_EQ(0x12345678, info.CRC()); EXPECT_EQ(2, info.ITMs()); EXPECT_EQ(10, info.DeletedRefs()); @@ -209,10 +230,10 @@ TEST(PluginDirtyInfo, YamlDecode) { EXPECT_EQ("cleaner", info.CleaningUtility()); node = YAML::Load("scalar"); - EXPECT_ANY_THROW(node.as()); + EXPECT_ANY_THROW(node.as()); node = YAML::Load("[0, 1, 2]"); - EXPECT_ANY_THROW(node.as()); + EXPECT_ANY_THROW(node.as()); } #endif