diff --git a/src/api/api.cpp b/src/api/api.cpp index d46f70ed..714fd220 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -755,18 +755,28 @@ LOOT_API unsigned int loot_get_dirty_info(loot_db db, const char * const plugin, *needsCleaning = loot_needs_cleaning_unknown; - //Get all dirty info. - loot::Plugin p = db->masterlist.FindPlugin(loot::Plugin(plugin)); - std::set dirtyInfo(p.DirtyInfo()); - - p = db->userlist.FindPlugin(loot::Plugin(plugin)); - std::set temp(p.DirtyInfo()); - dirtyInfo.insert(temp.begin(), temp.end()); - - if (!dirtyInfo.empty()) { + // Is there any dirty info? Testing for applicability happens in loot_eval_lists(). + if (!db->masterlist.FindPlugin(loot::Plugin(plugin)).DirtyInfo().empty() + || !db->userlist.FindPlugin(loot::Plugin(plugin)).DirtyInfo().empty()) { *needsCleaning = loot_needs_cleaning_yes; } + // Is there a message beginning with the substring "Do not clean."? + // This isn't a very reliable system, because if the lists have been evaluated in some language + // other than English, the strings will be in different languages (and the API can't tell what they'd be) + // and the strings may be non-standard and begin with something other than "Do not clean." anyway. + std::list messages(db->masterlist.FindPlugin(loot::Plugin(plugin)).Messages()); + + std::list temp(db->userlist.FindPlugin(loot::Plugin(plugin)).Messages()); + messages.insert(messages.end(), temp.begin(), temp.end()); + + for (const auto& message : messages) { + if (boost::starts_with(message.ChooseContent(loot::Language::english).Str(), "Do not clean")) { + *needsCleaning = loot_needs_cleaning_no; + break; + } + } + return loot_ok; } diff --git a/src/api/api.h b/src/api/api.h index 605ebd35..07fc8df9 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -607,7 +607,12 @@ extern "C" /** * @brief Determines the database's knowledge of a plugin's dirtiness. * @details Outputs whether the plugin should be cleaned or not, or if - * no data is available. + * no data is available. The mechanism used to determine that + * a plugin should not be cleaned is not very reliable, and is + * likely to fail if `loot_eval_lists()` was called with a + * language other than English. As such, some plugins that should + * not be cleaned may have the `loot_needs_cleaning_unknown` + * code outputted. * @param db * The database the function acts on. * @param plugin diff --git a/src/tests/api/api.h b/src/tests/api/api.h index 1581f0a3..a05399a4 100644 --- a/src/tests/api/api.h +++ b/src/tests/api/api.h @@ -234,4 +234,28 @@ TEST_F(OblivionAPIOperationsTest, SortPlugins) { EXPECT_EQ(11, numPlugins); EXPECT_EQ(expectedOrder, actualOrder); } + +TEST_F(OblivionAPIOperationsTest, GetDirtyInfo) { + unsigned int needsCleaning; + EXPECT_EQ(loot_error_invalid_args, loot_get_dirty_info(NULL, "Oblivion.esm", &needsCleaning)); + EXPECT_EQ(loot_error_invalid_args, loot_get_dirty_info(db, NULL, &needsCleaning)); + EXPECT_EQ(loot_error_invalid_args, loot_get_dirty_info(db, "Oblivion.esm", NULL)); + + // Fetch and load the metadata. + bool updated; + ASSERT_EQ(loot_ok, loot_update_masterlist(db, masterlistPath.string().c_str(), "https://github.com/loot/oblivion.git", "master", &updated)); + ASSERT_EQ(loot_ok, loot_load_lists(db, masterlistPath.string().c_str(), NULL)); + + // A plugin with no metadata. + EXPECT_EQ(loot_ok, loot_get_dirty_info(db, "Oblivion.esm", &needsCleaning)); + EXPECT_EQ(loot_needs_cleaning_unknown, needsCleaning); + + // A plugin with dirty metadata. + EXPECT_EQ(loot_ok, loot_get_dirty_info(db, "Hammerfell.esm", &needsCleaning)); + EXPECT_EQ(loot_needs_cleaning_yes, needsCleaning); + + // A plugin with a standard "Do not clean" message. + EXPECT_EQ(loot_ok, loot_get_dirty_info(db, "Unofficial Oblivion Patch.esp", &needsCleaning)); + EXPECT_EQ(loot_needs_cleaning_no, needsCleaning); +} #endif