summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/util/options_parser/option_section.cpp189
-rw-r--r--src/mongo/util/options_parser/option_section.h11
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp20
3 files changed, 124 insertions, 96 deletions
diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp
index 2e4634ca609..ccd4e3dea00 100644
--- a/src/mongo/util/options_parser/option_section.cpp
+++ b/src/mongo/util/options_parser/option_section.cpp
@@ -45,7 +45,58 @@ using std::shared_ptr;
// Registration interface
-// TODO: Make sure the section we are adding does not have duplicate options
+namespace {
+Status checkConflicts(const std::set<std::string>& allDottedNames,
+ const std::set<std::string>& allSingleNames,
+ const OptionDescription& option) {
+ // Check for duplication in dotted name(s).
+ if (allDottedNames.count(option._dottedName)) {
+ return {ErrorCodes::InternalError,
+ str::stream() << "Attempted to register option with duplicate dottedName: "
+ << option._dottedName};
+ }
+
+ for (const auto& name : option._deprecatedDottedNames) {
+ // Deprecated name must not already be registered by previous setting,
+ // must not match non-deprecated name,
+ // and must not match any other single deprecated name.
+ if (allDottedNames.count(name) || (option._dottedName == name) ||
+ (std::count(option._deprecatedDottedNames.begin(),
+ option._deprecatedDottedNames.end(),
+ name) > 1)) {
+ return {ErrorCodes::InternalError,
+ str::stream()
+ << "Attempted to register option with duplicate deprecated dottedName: "
+ << name};
+ }
+ }
+
+ // Check for duplication in single name(s).
+ if (allSingleNames.count(option._singleName)) {
+ return {ErrorCodes::InternalError,
+ str::stream() << "Attempted to register option with duplicate singleName: "
+ << option._singleName};
+ }
+
+ for (const auto& name : option._deprecatedSingleNames) {
+ // Deprecated name must not already be registered by previous setting,
+ // must not match non-deprecated name,
+ // and must not match any other single deprecated name.
+ if (allSingleNames.count(name) || (option._singleName == name) ||
+ (std::count(option._deprecatedSingleNames.begin(),
+ option._deprecatedSingleNames.end(),
+ name) > 1)) {
+ return {ErrorCodes::InternalError,
+ str::stream()
+ << "Attempted to register option with duplicate deprecated singleName: "
+ << name};
+ }
+ }
+
+ return Status::OK();
+}
+} // namespace
+
Status OptionSection::addSection(const OptionSection& newSection) {
if (newSection._subSections.size()) {
return {ErrorCodes::InternalError, "Option subsections may not contain nested subsections"};
@@ -57,8 +108,15 @@ Status OptionSection::addSection(const OptionSection& newSection) {
str::stream() << "Attempted to add subsection with positional option: "
<< opt._dottedName};
}
+ auto status = checkConflicts(_allDottedNames, _allSingleNames, opt);
+ if (!status.isOK()) {
+ return status;
+ }
}
+ _allDottedNames.insert(newSection._allDottedNames.begin(), newSection._allDottedNames.end());
+ _allSingleNames.insert(newSection._allSingleNames.begin(), newSection._allSingleNames.end());
+
for (auto& oldSection : _subSections) {
if (newSection._name == oldSection._name) {
// Matches existing section name, merge options.
@@ -83,111 +141,50 @@ OptionDescription& OptionSection::addOptionChaining(
const std::vector<std::string>& deprecatedSingleNames) {
OptionDescription option(
dottedName, singleName, type, description, deprecatedDottedNames, deprecatedSingleNames);
+
+ // dottedName must be non-empty.
+ uassert(ErrorCodes::InternalError,
+ "Attempted to register option with empty dottedName",
+ !dottedName.empty());
+
// Verify deprecated dotted names.
// No empty deprecated dotted names.
- if (std::count(deprecatedDottedNames.begin(), deprecatedDottedNames.end(), "")) {
- StringBuilder sb;
- sb << "Attempted to register option with empty string for deprecatedDottedName";
- uasserted(ErrorCodes::InternalError, sb.str());
- }
+ uassert(ErrorCodes::InternalError,
+ "Attempted to register option with empty string for deprecatedDottedName",
+ std::count(deprecatedDottedNames.begin(), deprecatedDottedNames.end(), "") == 0);
// Should not be the same as dottedName.
- if (std::count(deprecatedDottedNames.begin(), deprecatedDottedNames.end(), dottedName)) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between dottedName and "
- << "deprecatedDottedName: " << dottedName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
+ uassert(ErrorCodes::InternalError,
+ str::stream() << "Attempted to register option with conflict between dottedName and "
+ << "deprecatedDottedName: "
+ << dottedName,
+ !std::count(deprecatedDottedNames.begin(), deprecatedDottedNames.end(), dottedName));
// Verify deprecated single names.
// No empty deprecated single names.
- if (std::count(deprecatedSingleNames.begin(), deprecatedSingleNames.end(), "")) {
- StringBuilder sb;
- sb << "Attempted to register option with empty string for deprecatedSingleName";
- uasserted(ErrorCodes::InternalError, sb.str());
- }
+ uassert(ErrorCodes::InternalError,
+ "Attempted to register option with empty string for deprecatedSingleName",
+ std::count(deprecatedSingleNames.begin(), deprecatedSingleNames.end(), "") == 0);
// Should not be the same as singleName.
- if (std::count(deprecatedSingleNames.begin(), deprecatedSingleNames.end(), singleName)) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between singleName and "
- << "deprecatedSingleName: " << singleName;
- uasserted(ErrorCodes::InternalError, sb.str());
+ uassert(ErrorCodes::InternalError,
+ str::stream() << "Attempted to register option with conflict between singleName and "
+ << "deprecatedSingleName: "
+ << singleName,
+ !std::count(deprecatedSingleNames.begin(), deprecatedSingleNames.end(), singleName));
+
+ // Should not contain any already registered name.
+ uassertStatusOK(checkConflicts(_allDottedNames, _allSingleNames, option));
+
+ _allDottedNames.insert(option._dottedName);
+ _allDottedNames.insert(option._deprecatedDottedNames.begin(),
+ option._deprecatedDottedNames.end());
+ if (!option._singleName.empty()) {
+ _allSingleNames.insert(option._singleName);
}
-
- for (const OptionDescription& od : _options) {
- if (option._dottedName == od._dottedName) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate dottedName: " << dottedName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
-
- // Allow options with empty singleName since some options are not allowed on the command
- // line
- if (!option._singleName.empty() && option._singleName == od._singleName) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate singleName: " << singleName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
-
- if (std::count(
- od._deprecatedDottedNames.begin(), od._deprecatedDottedNames.end(), dottedName)) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between dottedName and existing "
- "deprecatedDottedName: "
- << dottedName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
-
- if (std::count(
- od._deprecatedSingleNames.begin(), od._deprecatedSingleNames.end(), singleName)) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between singleName and existing "
- "deprecatedSingleName: "
- << singleName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
-
- for (const std::string& deprecatedDottedName : deprecatedDottedNames) {
- if (deprecatedDottedName == od._dottedName) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between deprecatedDottedName "
- "and existing dottedName: "
- << dottedName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
-
- if (std::count(od._deprecatedDottedNames.begin(),
- od._deprecatedDottedNames.end(),
- deprecatedDottedName)) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate deprecatedDottedName: "
- << deprecatedDottedName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
- }
-
- for (const std::string& deprecatedSingleName : deprecatedSingleNames) {
- if (deprecatedSingleName == od._singleName) {
- StringBuilder sb;
- sb << "Attempted to register option with conflict between deprecatedSingleName "
- "and existing singleName: "
- << singleName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
-
- if (std::count(od._deprecatedSingleNames.begin(),
- od._deprecatedSingleNames.end(),
- deprecatedSingleName)) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate deprecatedSingleName: "
- << deprecatedSingleName;
- uasserted(ErrorCodes::InternalError, sb.str());
- }
- }
- }
-
- _options.push_back(option);
+ _allSingleNames.insert(option._deprecatedSingleNames.begin(),
+ option._deprecatedSingleNames.end());
+ _options.push_back(std::move(option));
return _options.back();
}
diff --git a/src/mongo/util/options_parser/option_section.h b/src/mongo/util/options_parser/option_section.h
index 685e3d869f2..d776c18ae00 100644
--- a/src/mongo/util/options_parser/option_section.h
+++ b/src/mongo/util/options_parser/option_section.h
@@ -170,6 +170,17 @@ private:
std::string _name;
std::list<OptionSection> _subSections;
std::list<OptionDescription> _options;
+
+ /**
+ * Internal accumulator of all dotted names (incl. deprecated) in _options and all _subSections.
+ * Used for ensuring duplicate entries don't find their way into different parts of the tree.
+ */
+ std::set<std::string> _allDottedNames;
+
+ /**
+ * Internal accumulator for all single names. See _allDottedNames for further info.
+ */
+ std::set<std::string> _allSingleNames;
};
} // namespace optionenvironment
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index b798cecbc73..4bbb7c8f36f 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -121,6 +121,26 @@ TEST(Registration, DuplicateSingleName) {
}
}
+TEST(Registration, DuplicateSeingleNameAcrossSections) {
+ moe::OptionSection group1;
+ group1.addOptionChaining("one", "", moe::Switch, "Uno");
+
+ moe::OptionSection group2;
+ group2.addOptionChaining("one", "", moe::Switch, "Dos");
+
+ moe::OptionSection root;
+ ASSERT_OK(root.addSection(group1));
+ ASSERT_NOT_OK(root.addSection(group2));
+
+ ASSERT_THROWS(root.addOptionChaining("one", "", moe::Switch, "Tres"),
+ mongo::AssertionException);
+ root.addOptionChaining("two", "", moe::Switch, "Quatro");
+
+ moe::OptionSection group3;
+ group3.addOptionChaining("two", "", moe::Switch, "Cinco");
+ ASSERT_NOT_OK(root.addSection(group3));
+}
+
TEST(Registration, DuplicateDottedName) {
moe::OptionSection testOpts;
try {