diff options
author | Shaun Verch <shaun.verch@10gen.com> | 2013-12-06 03:15:44 -0500 |
---|---|---|
committer | Shaun Verch <shaun.verch@10gen.com> | 2013-12-06 12:57:58 -0500 |
commit | 6bef7b4fa2b5648e11da5aeb4f44b2f6bae7952d (patch) | |
tree | 7ce7c82018c8d926c21d4c86aafe912c3036c92d /src/mongo/util/options_parser | |
parent | 0f0bd1d058375234a639928f90dab26293a584eb (diff) | |
download | mongo-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/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/util/options_parser/constraints.cpp | 35 | ||||
-rw-r--r-- | src/mongo/util/options_parser/constraints.h | 18 | ||||
-rw-r--r-- | src/mongo/util/options_parser/environment_test.cpp | 14 | ||||
-rw-r--r-- | src/mongo/util/options_parser/option_description.cpp | 14 | ||||
-rw-r--r-- | src/mongo/util/options_parser/option_description.h | 7 | ||||
-rw-r--r-- | src/mongo/util/options_parser/options_parser_test.cpp | 54 |
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; |