summaryrefslogtreecommitdiff
path: root/src/mongo/util/options_parser
diff options
context:
space:
mode:
authorShaun Verch <shaun.verch@10gen.com>2013-12-06 03:15:44 -0500
committerShaun Verch <shaun.verch@10gen.com>2013-12-06 12:57:58 -0500
commit6bef7b4fa2b5648e11da5aeb4f44b2f6bae7952d (patch)
tree7ce7c82018c8d926c21d4c86aafe912c3036c92d /src/mongo/util/options_parser
parent0f0bd1d058375234a639928f90dab26293a584eb (diff)
downloadmongo-6bef7b4fa2b5648e11da5aeb4f44b2f6bae7952d.tar.gz
SERVER-11143 Added support for specifying that a string option must be of a specified format
Diffstat (limited to 'src/mongo/util/options_parser')
-rw-r--r--src/mongo/util/options_parser/SConscript3
-rw-r--r--src/mongo/util/options_parser/constraints.cpp35
-rw-r--r--src/mongo/util/options_parser/constraints.h18
-rw-r--r--src/mongo/util/options_parser/environment_test.cpp14
-rw-r--r--src/mongo/util/options_parser/option_description.cpp14
-rw-r--r--src/mongo/util/options_parser/option_description.h7
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp54
7 files changed, 139 insertions, 6 deletions
diff --git a/src/mongo/util/options_parser/SConscript b/src/mongo/util/options_parser/SConscript
index 21054497bcf..b4bf13d3ae0 100644
--- a/src/mongo/util/options_parser/SConscript
+++ b/src/mongo/util/options_parser/SConscript
@@ -12,7 +12,8 @@ env.Library('options_parser', ['environment.cpp',
'startup_options.cpp',
],
LIBDEPS=['$BUILD_DIR/mongo/bson',
- '$BUILD_DIR/third_party/shim_yaml'
+ '$BUILD_DIR/third_party/shim_yaml',
+ '$BUILD_DIR/third_party/shim_pcrecpp'
])
env.CppUnitTest('options_parser_test',
diff --git a/src/mongo/util/options_parser/constraints.cpp b/src/mongo/util/options_parser/constraints.cpp
index c7709e407b5..381d24a28e5 100644
--- a/src/mongo/util/options_parser/constraints.cpp
+++ b/src/mongo/util/options_parser/constraints.cpp
@@ -15,6 +15,8 @@
#include "mongo/util/options_parser/constraints.h"
+#include <pcrecpp.h>
+
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
@@ -39,14 +41,14 @@ namespace optionenvironment {
sb << "Error: Attempting to set " << _key << " to value: " <<
intVal << " which is out of range: (" <<
_min << "," << _max << ")";
- return Status(ErrorCodes::InternalError, sb.str());
+ return Status(ErrorCodes::BadValue, sb.str());
}
}
else {
StringBuilder sb;
sb << "Error: " << _key << " is of type: " << val.typeToString() <<
" but must be of a numeric type.";
- return Status(ErrorCodes::InternalError, sb.str());
+ return Status(ErrorCodes::BadValue, sb.str());
}
return Status::OK();
}
@@ -62,7 +64,7 @@ namespace optionenvironment {
if (!_value.equal(env_value)) {
StringBuilder sb;
sb << "Error: " << _key << " is immutable once set";
- return Status(ErrorCodes::InternalError, sb.str());
+ return Status(ErrorCodes::BadValue, sb.str());
}
}
}
@@ -78,7 +80,7 @@ namespace optionenvironment {
if (ret.isOK()) {
StringBuilder sb;
sb << _otherKey << " is not allowed when " << _key << " is specified";
- return Status(ErrorCodes::InternalError, sb.str());
+ return Status(ErrorCodes::BadValue, sb.str());
}
}
@@ -93,7 +95,30 @@ namespace optionenvironment {
if (!ret.isOK()) {
StringBuilder sb;
sb << _otherKey << " is required when " << _key << " is specified";
- return Status(ErrorCodes::InternalError, sb.str());
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ }
+
+ return Status::OK();
+ }
+
+ Status StringFormatKeyConstraint::check(const Environment& env) {
+ Value value;
+ Status ret = env.get(_key, &value);
+ if (ret.isOK()) {
+ std::string stringVal;
+ ret = value.get(&stringVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << _key << " could not be read as a string: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+
+ pcrecpp::RE re(_regexFormat);
+ if (!re.FullMatch(stringVal)) {
+ StringBuilder sb;
+ sb << _key << " must be a string of the format: " << _displayFormat;
+ return Status(ErrorCodes::BadValue, sb.str());
}
}
diff --git a/src/mongo/util/options_parser/constraints.h b/src/mongo/util/options_parser/constraints.h
index eaeb6ffa0ae..48b17576d6f 100644
--- a/src/mongo/util/options_parser/constraints.h
+++ b/src/mongo/util/options_parser/constraints.h
@@ -114,6 +114,24 @@ namespace optionenvironment {
Key _otherKey;
};
+ /** Implementation of a Constraint that enforces a specific format on a string value. Fails if
+ * the value of the key is not a string or does not match the given regex.
+ */
+ class StringFormatKeyConstraint : public KeyConstraint {
+ public:
+ StringFormatKeyConstraint(const Key& key,
+ const std::string& regexFormat,
+ const std::string& displayFormat) : KeyConstraint(key),
+ _regexFormat(regexFormat),
+ _displayFormat(displayFormat)
+ { }
+ virtual ~StringFormatKeyConstraint() {}
+ private:
+ virtual Status check(const Environment& env);
+ std::string _regexFormat;
+ std::string _displayFormat;
+ };
+
/** Implementation of a Constraint on the type of a Value. Fails if we cannot extract the given
* type from our Value, which means the implementation of the access functions of Value
* controls which types are "compatible"
diff --git a/src/mongo/util/options_parser/environment_test.cpp b/src/mongo/util/options_parser/environment_test.cpp
index f4d76519da0..e4ac8dea505 100644
--- a/src/mongo/util/options_parser/environment_test.cpp
+++ b/src/mongo/util/options_parser/environment_test.cpp
@@ -93,6 +93,20 @@ namespace {
ASSERT_OK(environment.validate());
}
+ TEST(Environment, StringFormat) {
+ moe::Environment environment;
+ environment.addKeyConstraint(new moe::StringFormatKeyConstraint(moe::Key("key"), "[0-9]",
+ "[0-9]"));
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("a"))));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("11"))));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(std::string("1"))));
+ ASSERT_OK(environment.validate());
+ }
+
TEST(Environment, DirectTypeAccess) {
moe::Environment environment;
ASSERT_OK(environment.set(moe::Key("number"), moe::Value(5)));
diff --git a/src/mongo/util/options_parser/option_description.cpp b/src/mongo/util/options_parser/option_description.cpp
index 6acb0e3371f..c7cba2cc3e2 100644
--- a/src/mongo/util/options_parser/option_description.cpp
+++ b/src/mongo/util/options_parser/option_description.cpp
@@ -225,5 +225,19 @@ namespace optionenvironment {
return addConstraint(new RequiresOtherKeyConstraint(_dottedName, otherDottedName));
}
+ OptionDescription& OptionDescription::format(const std::string& regexFormat,
+ const std::string& displayFormat) {
+ if (_type != String) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "only options registered as a string type can have a required format, "
+ << "but option has type: " << _type;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
+
+ return addConstraint(new StringFormatKeyConstraint(_dottedName, regexFormat,
+ displayFormat));
+ }
+
} // namespace optionenvironment
} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_description.h b/src/mongo/util/options_parser/option_description.h
index e1e41887e7b..0604f79ced4 100644
--- a/src/mongo/util/options_parser/option_description.h
+++ b/src/mongo/util/options_parser/option_description.h
@@ -179,6 +179,13 @@ namespace optionenvironment {
OptionDescription& requires(const std::string& otherDottedName);
/**
+ * Specifies that this option is required to match the given format, specified as a regular
+ * expression. The displayFormat argument is what gets printed to the user in the case
+ * where this constraint is not satisfied. This is only allowed on String options.
+ */
+ OptionDescription& format(const std::string& regexFormat, const std::string& displayFormat);
+
+ /**
* Adds a constraint for this option. During parsing, this Constraint will be added to the
* result Environment, ensuring that it will get checked when the environment is validated.
* See the documentation on the Constraint and Environment classes for more details.
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index 25ff3f7e6e8..12e8c291684 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -228,6 +228,17 @@ namespace {
}
}
+ TEST(Registration, StringFormatConstraint) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .format("[0-9]*", "[0-9]*");
+ FAIL("Was able to register non string option with constraint on format");
+ }
+ catch (::mongo::DBException &e) {
+ }
+ }
+
TEST(Parsing, Good) {
moe::OptionsParser parser;
moe::Environment environment;
@@ -3029,6 +3040,49 @@ namespace {
ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
}
+ TEST(Constraints, StringFormatConstraint) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("option", "option", moe::String, "Option")
+ .format("[a-z][0-9]", "[character][number]");
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option");
+ argv.push_back("aa");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option");
+ argv.push_back("11");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_NOT_OK(environment.validate());;
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option");
+ argv.push_back("a1");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ASSERT_OK(environment.get(moe::Key("option"), &value));
+ std::string option;
+ ASSERT_OK(value.get(&option));
+ ASSERT_EQUALS(option, "a1");
+ }
+
TEST(YAMLConfigFile, Basic) {
OptionsParserTester parser;
moe::Environment environment;