mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Throw on non-unique exact plugin metadata.
Also fix some outdated information in the metadata syntax doc relating to how metadata is merged.
This commit is contained in:
@@ -439,21 +439,21 @@ nav: 0
|
||||
<tr><td><code>url</code><td>location list<td>✗<td>An unordered list of locations for this plugin. If the same version can be found at multiple locations, only one location should be recorded. This metadata is not currently used by LOOT.
|
||||
<tr><td><code>dirty</code><td>dirty info list<td>✗<td>An unordered list of dirty info structures for this plugin. Plugin entries with regular expression filenames <strong>must not</strong> contain dirty info.
|
||||
</table>
|
||||
<p><strong>Each plugin must have only one matching non-regex entry.</strong> If multiple non-regex entries exist with the same <code>name</code> value, all but the first will be ignored. A plugin may match any number of regex entries though, and their metadata will be merged, with later entries being merged into earlier entries as detailed in the table below. Merging only takes place if both entries have their <code>enabled</code> value set to <code>true</code> (which is the default if unspecified).
|
||||
<p><strong>Each plugin must have only one matching non-regex entry.</strong> A plugin may match any number of regex entries though, and their metadata will be merged, with later entries being merged into earlier entries as detailed in the table below.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Key Name<th>Merge Behaviour (merging B into A)
|
||||
<tbody>
|
||||
<tr><td><code>name</code><td>Not merged.
|
||||
<tr><td><code>enabled</code><td>Replaced but must be `true` anyway.
|
||||
<tr><td><code>priority</code><td>Replaced by B's value.
|
||||
<tr><td><code>enabled</code><td>Replaced by B's value.
|
||||
<tr><td><code>priority</code><td>Replaced by B's value, unless that value is <code>0</code> and it was not explicitly set.
|
||||
<tr><td><code>after</code><td>Merged. If A and B both contain an entry with the same <code>name</code> value, B's copy is skipped.
|
||||
<tr><td><code>req</code><td>Merged. If A and B both contain an entry with the same <code>name</code> value, B's copy is skipped.
|
||||
<tr><td><code>inc</code><td>Merged. If A and B both contain an entry with the same <code>name</code> value, B's copy is skipped.
|
||||
<tr><td><code>msg</code><td>Merged. If A and B both contain an entry with the same content string, then B's copy is skipped. If there are multiple content strings, the English strings are compared.
|
||||
<tr><td><code>tag</code><td>Merged. If A and B both contain an entry with the same <code>name</code> value, B's copy is skipped, unless one is suggesting the tag for addition and the other is suggesting it for removal, in which case both entries are kept.
|
||||
<tr><td><code>url</code><td>Currently skipped by the parser, so neither A nor B will contain any entries anyway.
|
||||
<tr><td><code>url</code><td>Merged. If A and B both contain an entry with the same <code>link</code> value, B's copy is skipped.
|
||||
<tr><td><code>dirty</code><td>Merged. If A and B both contain an entry with the same <code>crc</code> value, B's copy is skipped.
|
||||
</table>
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@ namespace loot {
|
||||
PluginMetadata plugin(node.as<PluginMetadata>());
|
||||
if (plugin.IsRegexPlugin())
|
||||
regexPlugins.push_back(plugin);
|
||||
else
|
||||
plugins.insert(plugin);
|
||||
else {
|
||||
if (!plugins.insert(plugin).second)
|
||||
throw error(error::path_read_fail, "More than one entry exists for \"" + plugin.Name() + "\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (metadataList["globals"])
|
||||
@@ -110,8 +112,10 @@ namespace loot {
|
||||
void MetadataList::AddPlugin(const PluginMetadata& plugin) {
|
||||
if (plugin.IsRegexPlugin())
|
||||
regexPlugins.push_back(plugin);
|
||||
else
|
||||
plugins.insert(plugin);
|
||||
else {
|
||||
if (!plugins.insert(plugin).second)
|
||||
throw error(error::invalid_args, "Cannot add \"" + plugin.Name() + "\" to the metadata list as another entry already exists.");
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't erase matching regex entries, because they might also
|
||||
|
||||
@@ -32,7 +32,8 @@ class MetadataList : public SkyrimTest {
|
||||
protected:
|
||||
MetadataList() :
|
||||
metadataPath("./testing-metadata-master/masterlist.yaml"),
|
||||
savedMetadataPath("./testing-metadata-master/saved.masterlist.yaml") {
|
||||
savedMetadataPath("./testing-metadata-master/saved.masterlist.yaml"),
|
||||
invalidMetadataPaths({"./testing-metadata-master/invalid/non_unique.yaml"}) {
|
||||
PluginMetadataToString = [](const loot::PluginMetadata& plugin) {
|
||||
return plugin.Name();
|
||||
};
|
||||
@@ -43,6 +44,10 @@ protected:
|
||||
|
||||
ASSERT_TRUE(boost::filesystem::exists(metadataPath));
|
||||
ASSERT_FALSE(boost::filesystem::exists(savedMetadataPath));
|
||||
|
||||
for (const auto& path : invalidMetadataPaths) {
|
||||
ASSERT_TRUE(boost::filesystem::exists(path));
|
||||
}
|
||||
}
|
||||
|
||||
inline virtual void TearDown() {
|
||||
@@ -50,10 +55,15 @@ protected:
|
||||
|
||||
ASSERT_TRUE(boost::filesystem::exists(metadataPath));
|
||||
ASSERT_NO_THROW(boost::filesystem::remove(savedMetadataPath));
|
||||
|
||||
for (const auto& path : invalidMetadataPaths) {
|
||||
ASSERT_TRUE(boost::filesystem::exists(path));
|
||||
}
|
||||
}
|
||||
|
||||
const boost::filesystem::path metadataPath;
|
||||
const boost::filesystem::path savedMetadataPath;
|
||||
const std::vector<boost::filesystem::path> invalidMetadataPaths;
|
||||
|
||||
std::function<std::string(const loot::PluginMetadata&)> PluginMetadataToString;
|
||||
};
|
||||
@@ -93,6 +103,13 @@ TEST_F(MetadataList, Load) {
|
||||
EXPECT_TRUE(ml.Plugins().empty());
|
||||
}
|
||||
|
||||
TEST_F(MetadataList, Load_Invalid) {
|
||||
loot::MetadataList ml;
|
||||
for (const auto& path : invalidMetadataPaths) {
|
||||
EXPECT_ANY_THROW(ml.Load(path));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MetadataList, Save) {
|
||||
loot::MetadataList ml;
|
||||
ASSERT_NO_THROW(ml.Load(metadataPath));
|
||||
@@ -172,6 +189,17 @@ TEST_F(MetadataList, AddPlugin) {
|
||||
EXPECT_EQ(-10, pm.Priority());
|
||||
}
|
||||
|
||||
TEST_F(MetadataList, AddPlugin_NonUnique) {
|
||||
loot::MetadataList ml;
|
||||
ASSERT_NO_THROW(ml.Load(metadataPath));
|
||||
|
||||
loot::PluginMetadata pm = ml.FindPlugin(loot::PluginMetadata("Blank.esm"));
|
||||
ASSERT_EQ("Blank.esm", pm.Name());
|
||||
ASSERT_FALSE(pm.HasNameOnly());
|
||||
|
||||
ASSERT_ANY_THROW(ml.AddPlugin(loot::PluginMetadata("Blank.esm")));
|
||||
}
|
||||
|
||||
TEST_F(MetadataList, ErasePlugin) {
|
||||
loot::MetadataList ml;
|
||||
ASSERT_NO_THROW(ml.Load(metadataPath));
|
||||
|
||||
Reference in New Issue
Block a user