mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-09 13:12:58 -06:00
Allow Documentations to be exhaustive to not allow extra dictionaries
This commit is contained in:
@@ -39,6 +39,7 @@ namespace documentation {
|
||||
struct Verifier;
|
||||
|
||||
using Optional = ghoul::Boolean;
|
||||
using Exhaustive = ghoul::Boolean;
|
||||
|
||||
struct TestResult {
|
||||
bool success;
|
||||
@@ -64,11 +65,13 @@ struct DocumentationEntry {
|
||||
using DocumentationEntries = std::vector<documentation::DocumentationEntry>;
|
||||
|
||||
struct Documentation {
|
||||
Documentation(std::string name = "", DocumentationEntries entries = {});
|
||||
Documentation(std::string name = "", DocumentationEntries entries = {},
|
||||
Exhaustive exhaustive = Exhaustive::No);
|
||||
Documentation(DocumentationEntries entries);
|
||||
|
||||
std::string name;
|
||||
DocumentationEntries entries;
|
||||
Exhaustive exhaustive;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -71,13 +71,14 @@ struct StringVerifier : public TemplateVerifier<std::string> {
|
||||
};
|
||||
|
||||
struct TableVerifier : public TemplateVerifier<ghoul::Dictionary> {
|
||||
TableVerifier(std::vector<DocumentationEntry> d = {});
|
||||
TableVerifier(std::vector<DocumentationEntry> d = {}, Exhaustive exhaustive = Exhaustive::No);
|
||||
|
||||
TestResult operator()(const ghoul::Dictionary& dict, const std::string& key) const override;
|
||||
|
||||
std::string type() const override;
|
||||
|
||||
std::vector<DocumentationEntry> doc;
|
||||
Exhaustive exhaustive;
|
||||
};
|
||||
|
||||
struct VectorVerifier {};
|
||||
|
||||
@@ -52,9 +52,11 @@ DocumentationEntry::DocumentationEntry(std::string key, Verifier* t, std::string
|
||||
, documentation(std::move(doc))
|
||||
, optional(optional) {}
|
||||
|
||||
Documentation::Documentation(std::string name, DocumentationEntries entries)
|
||||
Documentation::Documentation(std::string name, DocumentationEntries entries, Exhaustive exhaustive)
|
||||
: name(std::move(name))
|
||||
, entries(std::move(entries)) {}
|
||||
, entries(std::move(entries))
|
||||
, exhaustive(std::move(exhaustive))
|
||||
{}
|
||||
|
||||
Documentation::Documentation(DocumentationEntries entries)
|
||||
: Documentation("", std::move(entries)) {}
|
||||
@@ -97,6 +99,31 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di
|
||||
}
|
||||
}
|
||||
|
||||
if (d.exhaustive) {
|
||||
// If the documentation is exhaustive, we have to check if there are extra values
|
||||
// in the table that are not covered by the Documentation
|
||||
|
||||
for (const std::string& key : dictionary.keys()) {
|
||||
auto it = std::find_if(
|
||||
d.entries.begin(),
|
||||
d.entries.end(),
|
||||
[&key](const DocumentationEntry& entry) {
|
||||
if (entry.key == Wildcard) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return entry.key == key;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (it == d.entries.end()) {
|
||||
result.success = false;
|
||||
result.offenders.push_back(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicate offenders that might occur if multiple rules apply to a single
|
||||
// key and more than one of these rules are broken
|
||||
std::set<std::string> uniqueOffenders(
|
||||
@@ -104,7 +131,7 @@ TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& di
|
||||
);
|
||||
result.offenders = std::vector<std::string>(
|
||||
uniqueOffenders.begin(), uniqueOffenders.end()
|
||||
);
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -140,8 +140,9 @@ std::string StringVerifier::type() const {
|
||||
return "String";
|
||||
}
|
||||
|
||||
TableVerifier::TableVerifier(std::vector<DocumentationEntry> d)
|
||||
TableVerifier::TableVerifier(std::vector<DocumentationEntry> d, Exhaustive exhaustive)
|
||||
: doc(std::move(d))
|
||||
, exhaustive(std::move(exhaustive))
|
||||
{}
|
||||
|
||||
TestResult TableVerifier::operator()(const ghoul::Dictionary& dict,
|
||||
@@ -149,7 +150,7 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dict,
|
||||
{
|
||||
if (dict.hasKeyAndValue<Type>(key)) {
|
||||
ghoul::Dictionary d = dict.value<Type>(key);
|
||||
TestResult res = testSpecification(doc, d);
|
||||
TestResult res = testSpecification({ "", doc, exhaustive }, d);
|
||||
|
||||
for (std::string& s : res.offenders) {
|
||||
s = key + "." + s;
|
||||
|
||||
@@ -639,6 +639,70 @@ TEST_F(DocumentationTest, RequiredInOptional) {
|
||||
EXPECT_EQ("a.b", negativeRes.offenders[0]);
|
||||
}
|
||||
|
||||
TEST_F(DocumentationTest, Exhaustive) {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
Documentation doc {
|
||||
"Test",
|
||||
{{ "Int", new IntVerifier }},
|
||||
Exhaustive::Yes
|
||||
};
|
||||
|
||||
ghoul::Dictionary positive {
|
||||
{ "Int" , 1 }
|
||||
};
|
||||
TestResult positiveRes = testSpecification(doc, positive);
|
||||
EXPECT_TRUE(positiveRes.success);
|
||||
EXPECT_EQ(0, positiveRes.offenders.size());
|
||||
|
||||
ghoul::Dictionary negative {
|
||||
{ "False_Int", 1 }
|
||||
};
|
||||
TestResult negativeRes = testSpecification(doc, negative);
|
||||
EXPECT_FALSE(negativeRes.success);
|
||||
ASSERT_EQ(2, negativeRes.offenders.size());
|
||||
EXPECT_EQ("False_Int", negativeRes.offenders[0]);
|
||||
EXPECT_EQ("Int", negativeRes.offenders[1]);
|
||||
|
||||
ghoul::Dictionary negative2 {
|
||||
{ "Double", 2.0 }
|
||||
};
|
||||
negativeRes = testSpecification(doc, negative2);
|
||||
EXPECT_FALSE(negativeRes.success);
|
||||
ASSERT_EQ(2, negativeRes.offenders.size());
|
||||
EXPECT_EQ("Double", negativeRes.offenders[0]);
|
||||
EXPECT_EQ("Int", negativeRes.offenders[1]);
|
||||
}
|
||||
|
||||
TEST_F(DocumentationTest, NestedExhaustive) {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
Documentation doc {
|
||||
"Test",
|
||||
{{ "Table", new TableVerifier(
|
||||
{ { "a", new IntVerifier } },
|
||||
Exhaustive::Yes
|
||||
)
|
||||
}}
|
||||
};
|
||||
|
||||
ghoul::Dictionary positive {
|
||||
{ "Table", ghoul::Dictionary{{ "a", 1 }}}
|
||||
};
|
||||
TestResult positiveRes = testSpecification(doc, positive);
|
||||
EXPECT_TRUE(positiveRes.success);
|
||||
EXPECT_EQ(0, positiveRes.offenders.size());
|
||||
|
||||
ghoul::Dictionary negative {
|
||||
{ "Table", ghoul::Dictionary{{ "b", 2.0 }}}
|
||||
};
|
||||
TestResult negativeRes = testSpecification(doc, negative);
|
||||
EXPECT_FALSE(negativeRes.success);
|
||||
ASSERT_EQ(2, negativeRes.offenders.size());
|
||||
EXPECT_EQ("Table.a", negativeRes.offenders[0]);
|
||||
EXPECT_EQ("Table.b", negativeRes.offenders[1]);
|
||||
}
|
||||
|
||||
TEST_F(DocumentationTest, LessInt) {
|
||||
using namespace openspace::documentation;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user