summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/util/options_parser/environment.cpp22
-rw-r--r--src/mongo/util/options_parser/environment.h6
-rw-r--r--src/mongo/util/options_parser/environment_test.cpp18
-rw-r--r--src/mongo/util/options_parser/option_description.cpp21
-rw-r--r--src/mongo/util/options_parser/option_description.h41
-rw-r--r--src/mongo/util/options_parser/option_section.cpp20
-rw-r--r--src/mongo/util/options_parser/option_section.h7
-rw-r--r--src/mongo/util/options_parser/options_parser.cpp26
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp70
9 files changed, 211 insertions, 20 deletions
diff --git a/src/mongo/util/options_parser/environment.cpp b/src/mongo/util/options_parser/environment.cpp
index cc4ad2a71aa..bbf23d54168 100644
--- a/src/mongo/util/options_parser/environment.cpp
+++ b/src/mongo/util/options_parser/environment.cpp
@@ -28,12 +28,12 @@ namespace optionenvironment {
// Environment implementation
- Status Environment::addKeyConstraint(KeyConstraint* c) {
- keyConstraints.push_back(boost::shared_ptr<KeyConstraint>(c));
+ Status Environment::addKeyConstraint(KeyConstraint* keyConstraint) {
+ keyConstraints.push_back(keyConstraint);
return Status::OK();
}
- Status Environment::addConstraint(Constraint* c) {
- constraints.push_back(boost::shared_ptr<Constraint>(c));
+ Status Environment::addConstraint(Constraint* constraint) {
+ constraints.push_back(constraint);
return Status::OK();
}
@@ -110,7 +110,7 @@ namespace optionenvironment {
// 2. Add values to be added
std::map <Key, Value> add_values = add_environment.values;
- for(std::map<Key, Value>::const_iterator iterator = add_values.begin();
+ for (std::map<Key, Value>::const_iterator iterator = add_values.begin();
iterator != add_values.end(); iterator++) {
values[iterator->first] = iterator->second;
}
@@ -134,20 +134,20 @@ namespace optionenvironment {
Status Environment::validate() {
// 1. Iterate and check all KeyConstraints
- typedef std::vector<boost::shared_ptr<KeyConstraint> >::iterator it_keyConstraint;
- for(it_keyConstraint iterator = keyConstraints.begin();
+ typedef std::vector<KeyConstraint*>::iterator it_keyConstraint;
+ for (it_keyConstraint iterator = keyConstraints.begin();
iterator != keyConstraints.end(); iterator++) {
- Status ret = (*(*iterator).get())(*this);
+ Status ret = (**iterator)(*this);
if (!ret.isOK()) {
return ret;
}
}
// 2. Iterate and check all Constraints
- typedef std::vector<boost::shared_ptr<Constraint> >::iterator it_constraint;
- for(it_constraint iterator = constraints.begin();
+ typedef std::vector<Constraint*>::iterator it_constraint;
+ for (it_constraint iterator = constraints.begin();
iterator != constraints.end(); iterator++) {
- Status ret = (*(*iterator).get())(*this);
+ Status ret = (**iterator)(*this);
if (!ret.isOK()) {
return ret;
}
diff --git a/src/mongo/util/options_parser/environment.h b/src/mongo/util/options_parser/environment.h
index f7c8929814d..0e096ef40ad 100644
--- a/src/mongo/util/options_parser/environment.h
+++ b/src/mongo/util/options_parser/environment.h
@@ -107,7 +107,7 @@ namespace optionenvironment {
*
* It is an error to call these functions after "validate" has been called
*
- * WARNING: These take ownership of the pointer passed in
+ * NOTE: These DO NOT take ownership of the pointer passed in
*/
Status addKeyConstraint(KeyConstraint* keyConstraint);
Status addConstraint(Constraint* constraint);
@@ -197,8 +197,8 @@ namespace optionenvironment {
void dump();
protected:
- std::vector<boost::shared_ptr<Constraint> > constraints;
- std::vector<boost::shared_ptr<KeyConstraint> > keyConstraints;
+ std::vector<Constraint*> constraints;
+ std::vector<KeyConstraint*> keyConstraints;
std::map <Key, Value> values;
std::map <Key, Value> default_values;
bool valid;
diff --git a/src/mongo/util/options_parser/environment_test.cpp b/src/mongo/util/options_parser/environment_test.cpp
index 959d1d08f7b..c24d4a81423 100644
--- a/src/mongo/util/options_parser/environment_test.cpp
+++ b/src/mongo/util/options_parser/environment_test.cpp
@@ -33,7 +33,8 @@ namespace {
TEST(Environment, Immutable) {
moe::Environment environment;
- environment.addKeyConstraint(new moe::ImmutableKeyConstraint(moe::Key("port")));
+ moe::ImmutableKeyConstraint immutableKeyConstraint(moe::Key("port"));
+ environment.addKeyConstraint(&immutableKeyConstraint);
ASSERT_OK(environment.set(moe::Key("port"), moe::Value(5)));
ASSERT_OK(environment.validate());
ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value(0)));
@@ -41,29 +42,34 @@ namespace {
TEST(Environment, OutOfRange) {
moe::Environment environment;
- environment.addKeyConstraint(new moe::NumericKeyConstraint(moe::Key("port"), 1000, 65535));
+ moe::NumericKeyConstraint numericKeyConstraint(moe::Key("port"), 1000, 65535);
+ environment.addKeyConstraint(&numericKeyConstraint);
ASSERT_OK(environment.validate());
ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value(0)));
}
TEST(Environment, NonNumericRangeConstraint) {
moe::Environment environment;
- environment.addKeyConstraint(new moe::NumericKeyConstraint(moe::Key("port"), 1000, 65535));
+ moe::NumericKeyConstraint numericKeyConstraint(moe::Key("port"), 1000, 65535);
+ environment.addKeyConstraint(&numericKeyConstraint);
ASSERT_OK(environment.validate());
ASSERT_NOT_OK(environment.set(moe::Key("port"), moe::Value("string")));
}
TEST(Environment, BadType) {
moe::Environment environment;
- environment.addKeyConstraint(new moe::TypeKeyConstraint<int>(moe::Key("port")));
+ moe::TypeKeyConstraint<int> typeKeyConstraintInt(moe::Key("port"));
+ environment.addKeyConstraint(&typeKeyConstraintInt);
ASSERT_OK(environment.set(moe::Key("port"), moe::Value("string")));
ASSERT_NOT_OK(environment.validate());
}
TEST(Environment, AllowNumeric) {
moe::Environment environment;
- environment.addKeyConstraint(new moe::TypeKeyConstraint<long>(moe::Key("port")));
- environment.addKeyConstraint(new moe::TypeKeyConstraint<int>(moe::Key("port")));
+ moe::TypeKeyConstraint<long> typeKeyConstraintLong(moe::Key("port"));
+ environment.addKeyConstraint(&typeKeyConstraintLong);
+ moe::TypeKeyConstraint<int> typeKeyConstraintInt(moe::Key("port"));
+ environment.addKeyConstraint(&typeKeyConstraintInt);
ASSERT_OK(environment.set(moe::Key("port"), moe::Value(1)));
ASSERT_OK(environment.validate());
}
diff --git a/src/mongo/util/options_parser/option_description.cpp b/src/mongo/util/options_parser/option_description.cpp
index 1a439c99c5b..28e7f7a8f95 100644
--- a/src/mongo/util/options_parser/option_description.cpp
+++ b/src/mongo/util/options_parser/option_description.cpp
@@ -196,5 +196,26 @@ namespace optionenvironment {
return *this;
}
+ OptionDescription& OptionDescription::addConstraint(Constraint* c) {
+ _constraints.push_back(boost::shared_ptr<Constraint>(c));
+ return *this;
+ }
+
+ OptionDescription& OptionDescription::validRange(long min, long max) {
+ if (_type != Double &&
+ _type != Int &&
+ _type != Long &&
+ _type != UnsignedLongLong &&
+ _type != Unsigned) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "only options registered as a numeric type can have a valid range, "
+ << "but option has type: " << _type;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
+
+ return addConstraint(new NumericKeyConstraint(_dottedName, min, max));
+ }
+
} // 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 cee9a0f2d2c..20b3fc98409 100644
--- a/src/mongo/util/options_parser/option_description.h
+++ b/src/mongo/util/options_parser/option_description.h
@@ -15,9 +15,11 @@
#pragma once
+#include <boost/shared_ptr.hpp>
#include <iostream>
#include "mongo/base/status.h"
+#include "mongo/util/options_parser/constraints.h"
#include "mongo/util/options_parser/value.h"
namespace mongo {
@@ -79,6 +81,13 @@ namespace optionenvironment {
* more details on the chaining interface.
*/
+ /**
+ * Parsing Attributes.
+ *
+ * The functions below specify various attributes of our option that are relevant for
+ * parsing.
+ */
+
/*
* Make this option hidden so it does not appear in command line help
*/
@@ -140,6 +149,28 @@ namespace optionenvironment {
*/
OptionDescription& positional(int start, int end);
+ /**
+ * Validation Constraints.
+ *
+ * The functions below specify constraints that must be met in order for this option to be
+ * valid. These do not get checked during parsing, but will be added to the result
+ * Environment so that they will get checked when the Environment is validated.
+ */
+
+ /**
+ * Specifies the range allowed for this option. Only allowed for options with numeric type.
+ */
+ OptionDescription& validRange(long min, long max);
+
+ /**
+ * 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.
+ *
+ * WARNING: This function takes ownership of the Constraint pointer that is passed in.
+ */
+ OptionDescription& addConstraint(Constraint* c);
+
std::string _dottedName; // Used for JSON config and in Environment
std::string _singleName; // Used for boost command line and INI
OptionType _type; // Storage type of the argument value, or switch type (bool)
@@ -153,6 +184,16 @@ namespace optionenvironment {
// command line, json config, and ini config)
int _positionalStart; // The starting position if this is a positional option. -1 otherwise.
int _positionalEnd; // The ending position if this is a positional option. -1 if unlimited.
+
+ // TODO(sverch): We have to use pointers to keep track of the Constrants because we rely on
+ // inheritance to make Constraints work. We have to use shared_ptrs because the
+ // OptionDescription is sometimes copied and because it is stored in a std::list in the
+ // OptionSection. We should think about a better solution for the ownership semantics of
+ // these classes. Note that the Environment (the storage for results of option parsing) has
+ // to know about the constraints for all the options, which is another factor to consider
+ // when thinking about ownership.
+ std::vector<boost::shared_ptr<Constraint> > _constraints; // Constraints that must be met
+ // for this option to be valid
};
} // namespace optionenvironment
diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp
index 26853f30f63..08879b297e5 100644
--- a/src/mongo/util/options_parser/option_section.cpp
+++ b/src/mongo/util/options_parser/option_section.cpp
@@ -508,6 +508,26 @@ namespace optionenvironment {
return Status::OK();
}
+ Status OptionSection::getConstraints(
+ std::vector<boost::shared_ptr<Constraint > >* constraints) const {
+
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ std::vector<boost::shared_ptr<Constraint> >::const_iterator citerator;
+ for (citerator = oditerator->_constraints.begin();
+ citerator != oditerator->_constraints.end(); citerator++) {
+ constraints->push_back(*citerator);
+ }
+ }
+
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getConstraints(constraints);
+ }
+
+ return Status::OK();
+ }
+
std::string OptionSection::positionalHelpString(const std::string& execName) const {
po::positional_options_description boostPositionalOptions;
diff --git a/src/mongo/util/options_parser/option_section.h b/src/mongo/util/options_parser/option_section.h
index 9535bf52741..0da5fba3a90 100644
--- a/src/mongo/util/options_parser/option_section.h
+++ b/src/mongo/util/options_parser/option_section.h
@@ -17,6 +17,7 @@
#include "mongo/util/options_parser/option_description.h"
#include <boost/program_options.hpp>
+#include <boost/shared_ptr.hpp>
#include <iostream>
#include <list>
@@ -123,6 +124,12 @@ namespace optionenvironment {
*/
Status getDefaults(std::map<Key, Value>* values) const;
+ /**
+ * Populates the given vector with all the constraints for all options in this section and
+ * sub sections.
+ */
+ Status getConstraints(std::vector<boost::shared_ptr<Constraint > >* constraints) const;
+
std::string positionalHelpString(const std::string& execName) const;
std::string helpString() const;
diff --git a/src/mongo/util/options_parser/options_parser.cpp b/src/mongo/util/options_parser/options_parser.cpp
index 3725d7a7ffc..8873d19b409 100644
--- a/src/mongo/util/options_parser/options_parser.cpp
+++ b/src/mongo/util/options_parser/options_parser.cpp
@@ -418,6 +418,26 @@ namespace optionenvironment {
return Status::OK();
}
+ /**
+ * For all options that have constraints, add those constraints to our environment so that
+ * they run when the environment gets validated.
+ */
+ Status addConstraints(const OptionSection& options, Environment* dest) {
+ std::vector<boost::shared_ptr<Constraint> > constraints_vector;
+ Status ret = options.getConstraints(&constraints_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ std::vector<boost::shared_ptr<Constraint> >::const_iterator citerator;
+ for (citerator = constraints_vector.begin();
+ citerator != constraints_vector.end(); citerator++) {
+ dest->addConstraint(citerator->get());
+ }
+
+ return Status::OK();
+ }
+
} // namespace
/**
@@ -783,6 +803,12 @@ namespace optionenvironment {
return ret;
}
+ // Add the constraints from our options to the result environment
+ ret = addConstraints(options, environment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
return Status::OK();
}
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index 7b1a69c0bc6..6d6f0f78330 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -18,6 +18,7 @@
#include "mongo/bson/util/builder.h"
#include "mongo/unittest/unittest.h"
+#include "mongo/util/options_parser/constraints.h"
#include "mongo/util/options_parser/environment.h"
#include "mongo/util/options_parser/option_description.h"
#include "mongo/util/options_parser/option_section.h"
@@ -214,6 +215,19 @@ namespace {
}
}
+ TEST(Registration, NumericRangeConstraint) {
+ moe::OptionSection testOpts;
+ try {
+ std::vector<std::string> defaultVal;
+ defaultVal.push_back("default");
+ testOpts.addOptionChaining("port", "port", moe::String, "Port")
+ .validRange(1000, 65535);
+ FAIL("Was able to register non numeric option with constraint on range");
+ }
+ catch (::mongo::DBException &e) {
+ }
+ }
+
TEST(Parsing, Good) {
moe::OptionsParser parser;
moe::Environment environment;
@@ -2483,4 +2497,60 @@ namespace {
ASSERT_OK(value.get(&parameter));
ASSERT_EQUALS(parameter, "allowed");
}
+
+ TEST(Constraints, NumericRangeConstraint) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ int port;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .validRange(1000, 65535);
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("999");
+
+ 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("--port");
+ argv.push_back("65536");
+
+ 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("--port");
+ argv.push_back("65535");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 65535);
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("1000");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 1000);
+ }
} // unnamed namespace