summaryrefslogtreecommitdiff
path: root/src/mongo/util/options_parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/options_parser')
-rw-r--r--src/mongo/util/options_parser/constraints.cpp161
-rw-r--r--src/mongo/util/options_parser/constraints.h281
-rw-r--r--src/mongo/util/options_parser/environment.cpp586
-rw-r--r--src/mongo/util/options_parser/environment.h382
-rw-r--r--src/mongo/util/options_parser/environment_test.cpp273
-rw-r--r--src/mongo/util/options_parser/option_description.cpp491
-rw-r--r--src/mongo/util/options_parser/option_description.h376
-rw-r--r--src/mongo/util/options_parser/option_section.cpp989
-rw-r--r--src/mongo/util/options_parser/option_section.h246
-rw-r--r--src/mongo/util/options_parser/options_parser.cpp1663
-rw-r--r--src/mongo/util/options_parser/options_parser.h153
-rw-r--r--src/mongo/util/options_parser/options_parser_init.cpp10
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp8739
-rw-r--r--src/mongo/util/options_parser/startup_option_init.cpp33
-rw-r--r--src/mongo/util/options_parser/startup_option_init.h23
-rw-r--r--src/mongo/util/options_parser/startup_options.cpp8
-rw-r--r--src/mongo/util/options_parser/startup_options.h60
-rw-r--r--src/mongo/util/options_parser/value.cpp396
-rw-r--r--src/mongo/util/options_parser/value.h260
19 files changed, 7517 insertions, 7613 deletions
diff --git a/src/mongo/util/options_parser/constraints.cpp b/src/mongo/util/options_parser/constraints.cpp
index 8c79138a44d..1ed195e19c6 100644
--- a/src/mongo/util/options_parser/constraints.cpp
+++ b/src/mongo/util/options_parser/constraints.cpp
@@ -35,107 +35,104 @@
namespace mongo {
namespace optionenvironment {
- Status NumericKeyConstraint::check(const Environment& env) {
- Value val;
- Status s = env.get(_key, &val);
+Status NumericKeyConstraint::check(const Environment& env) {
+ Value val;
+ Status s = env.get(_key, &val);
- if (s == ErrorCodes::NoSuchKey) {
- // Key not set, skipping numeric constraint check
- return Status::OK();
- }
-
- // The code that controls whether a type is "compatible" is contained in the Value
- // class, so if that handles compatibility between numeric types then this will too.
- long intVal;
- if (val.get(&intVal).isOK()) {
- if (intVal < _min || intVal > _max) {
- StringBuilder sb;
- sb << "Error: Attempting to set " << _key << " to value: " <<
- intVal << " which is out of range: (" <<
- _min << "," << _max << ")";
- 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::BadValue, sb.str());
- }
+ if (s == ErrorCodes::NoSuchKey) {
+ // Key not set, skipping numeric constraint check
return Status::OK();
}
- Status ImmutableKeyConstraint::check(const Environment& env) {
- Value env_value;
- Status ret = env.get(_key, &env_value);
- if (ret.isOK()) {
- if (_value.isEmpty()) {
- _value = env_value;
- }
- else {
- if (!_value.equal(env_value)) {
- StringBuilder sb;
- sb << "Error: " << _key << " is immutable once set";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- }
+ // The code that controls whether a type is "compatible" is contained in the Value
+ // class, so if that handles compatibility between numeric types then this will too.
+ long intVal;
+ if (val.get(&intVal).isOK()) {
+ if (intVal < _min || intVal > _max) {
+ StringBuilder sb;
+ sb << "Error: Attempting to set " << _key << " to value: " << intVal
+ << " which is out of range: (" << _min << "," << _max << ")";
+ return Status(ErrorCodes::BadValue, sb.str());
}
-
- return ret;
+ } else {
+ StringBuilder sb;
+ sb << "Error: " << _key << " is of type: " << val.typeToString()
+ << " but must be of a numeric type.";
+ return Status(ErrorCodes::BadValue, sb.str());
}
-
- Status MutuallyExclusiveKeyConstraint::check(const Environment& env) {
- Value env_value;
- Status ret = env.get(_key, &env_value);
- if (ret.isOK()) {
- ret = env.get(_otherKey, &env_value);
- if (ret.isOK()) {
+ return Status::OK();
+}
+
+Status ImmutableKeyConstraint::check(const Environment& env) {
+ Value env_value;
+ Status ret = env.get(_key, &env_value);
+ if (ret.isOK()) {
+ if (_value.isEmpty()) {
+ _value = env_value;
+ } else {
+ if (!_value.equal(env_value)) {
StringBuilder sb;
- sb << _otherKey << " is not allowed when " << _key << " is specified";
+ sb << "Error: " << _key << " is immutable once set";
return Status(ErrorCodes::BadValue, sb.str());
}
}
-
- return Status::OK();
}
- Status RequiresOtherKeyConstraint::check(const Environment& env) {
- Value env_value;
- Status ret = env.get(_key, &env_value);
+ return ret;
+}
+
+Status MutuallyExclusiveKeyConstraint::check(const Environment& env) {
+ Value env_value;
+ Status ret = env.get(_key, &env_value);
+ if (ret.isOK()) {
+ ret = env.get(_otherKey, &env_value);
if (ret.isOK()) {
- ret = env.get(_otherKey, &env_value);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << _otherKey << " is required when " << _key << " is specified";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ StringBuilder sb;
+ sb << _otherKey << " is not allowed when " << _key << " is specified";
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ }
- return Status::OK();
+ return Status::OK();
+}
+
+Status RequiresOtherKeyConstraint::check(const Environment& env) {
+ Value env_value;
+ Status ret = env.get(_key, &env_value);
+ if (ret.isOK()) {
+ ret = env.get(_otherKey, &env_value);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << _otherKey << " is required when " << _key << " is specified";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
}
- 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());
- }
+ return Status::OK();
+}
- 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());
- }
+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());
}
- return Status::OK();
+ 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());
+ }
}
-} // namespace optionenvironment
-} // namespace mongo
+ return Status::OK();
+}
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/constraints.h b/src/mongo/util/options_parser/constraints.h
index 4f9b0244b61..b4a820f983d 100644
--- a/src/mongo/util/options_parser/constraints.h
+++ b/src/mongo/util/options_parser/constraints.h
@@ -34,149 +34,144 @@
namespace mongo {
namespace optionenvironment {
- /** A Constraint validates an Environment. It has one function, which takes an Environment as
- * an argument and returns either a success or failure Status depending on whether the
- * Environment was valid according to this constraint
- *
- * These are meant to be registered with an Environment to define what it means for that
- * Environment to be "valid" and run as part of its validation process
- */
- class Constraint {
- public:
- // Interface
- Status operator()(const Environment& env) { return check(env); }
- virtual ~Constraint() {}
- private:
- // Implementation
- virtual Status check(const Environment&) = 0;
- };
-
- /** A KeyConstraint is a Constraint on a specific Key. Currently this is not handled any
- * differently than a Constraint, and is only here as a way to help document whether a
- * Constraint applies to a single Key or an Environment as a whole
- */
- class KeyConstraint : public Constraint {
- public:
- KeyConstraint(const Key& key) :
- _key(key)
- { }
- virtual ~KeyConstraint() {}
- protected:
- Key _key;
- };
-
- /** Implementation of a Constraint on the range of a numeric Value. Fails if the Value is not a
- * number, or if it is a number but outside the given range
- */
- class NumericKeyConstraint : public KeyConstraint {
- public:
- NumericKeyConstraint(const Key& k, long min, long max) :
- KeyConstraint(k),
- _min(min),
- _max(max)
- { }
- virtual ~NumericKeyConstraint() {}
-
- private:
- virtual Status check(const Environment& env);
- long _min;
- long _max;
- };
-
- /** Implementation of a Constraint that makes a Value immutable. Fails if the Value has already
- * been set and we are attempting to set it to a different Value. Note that setting it to the
- * same value is allowed in this implementation
- */
- class ImmutableKeyConstraint : public KeyConstraint {
- public:
- ImmutableKeyConstraint(const Key& k) : KeyConstraint(k)
- { }
- virtual ~ImmutableKeyConstraint() {}
-
- private:
- virtual Status check(const Environment& env);
- Value _value;
- };
-
- /** Implementation of a Constraint that makes two keys mutually exclusive. Fails if both keys
- * are set.
- */
- class MutuallyExclusiveKeyConstraint : public KeyConstraint {
- public:
- MutuallyExclusiveKeyConstraint(const Key& key, const Key& otherKey) : KeyConstraint(key),
- _otherKey(otherKey)
- { }
- virtual ~MutuallyExclusiveKeyConstraint() {}
- private:
- virtual Status check(const Environment& env);
- Key _otherKey;
- };
-
- /** Implementation of a Constraint that makes one key require another. Fails if the first key
- * is set but the other is not.
- */
- class RequiresOtherKeyConstraint : public KeyConstraint {
- public:
- RequiresOtherKeyConstraint(const Key& key, const Key& otherKey) : KeyConstraint(key),
- _otherKey(otherKey)
- { }
- virtual ~RequiresOtherKeyConstraint() {}
- private:
- virtual Status check(const Environment& env);
- Key _otherKey;
- };
-
- /** Implementation of a Constraint that enforces a specific format on a std::string value. Fails if
- * the value of the key is not a std::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"
- */
- template <typename T>
- class TypeKeyConstraint : public KeyConstraint {
- public:
- TypeKeyConstraint(const Key& k) :
- KeyConstraint(k)
- { }
- virtual ~TypeKeyConstraint() {}
-
- private:
- virtual Status check(const Environment& env) {
- Value val;
- Status s = env.get(_key, &val);
- if (!s.isOK()) {
- // Key not set, skipping type constraint check
- return Status::OK();
- }
-
- // The code that controls whether a type is "compatible" is contained in the Value
- // class, so if that handles compatibility between numeric types then this will too.
- T typedVal;
- if (!val.get(&typedVal).isOK()) {
- StringBuilder sb;
- sb << "Error: value for key: " << _key << " was found as type: "
- << val.typeToString() << " but is required to be type: " << typeid(typedVal).name();
- return Status(ErrorCodes::InternalError, sb.str());
- }
+/** A Constraint validates an Environment. It has one function, which takes an Environment as
+ * an argument and returns either a success or failure Status depending on whether the
+ * Environment was valid according to this constraint
+ *
+ * These are meant to be registered with an Environment to define what it means for that
+ * Environment to be "valid" and run as part of its validation process
+ */
+class Constraint {
+public:
+ // Interface
+ Status operator()(const Environment& env) {
+ return check(env);
+ }
+ virtual ~Constraint() {}
+
+private:
+ // Implementation
+ virtual Status check(const Environment&) = 0;
+};
+
+/** A KeyConstraint is a Constraint on a specific Key. Currently this is not handled any
+ * differently than a Constraint, and is only here as a way to help document whether a
+ * Constraint applies to a single Key or an Environment as a whole
+ */
+class KeyConstraint : public Constraint {
+public:
+ KeyConstraint(const Key& key) : _key(key) {}
+ virtual ~KeyConstraint() {}
+
+protected:
+ Key _key;
+};
+
+/** Implementation of a Constraint on the range of a numeric Value. Fails if the Value is not a
+ * number, or if it is a number but outside the given range
+ */
+class NumericKeyConstraint : public KeyConstraint {
+public:
+ NumericKeyConstraint(const Key& k, long min, long max)
+ : KeyConstraint(k), _min(min), _max(max) {}
+ virtual ~NumericKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ long _min;
+ long _max;
+};
+
+/** Implementation of a Constraint that makes a Value immutable. Fails if the Value has already
+ * been set and we are attempting to set it to a different Value. Note that setting it to the
+ * same value is allowed in this implementation
+ */
+class ImmutableKeyConstraint : public KeyConstraint {
+public:
+ ImmutableKeyConstraint(const Key& k) : KeyConstraint(k) {}
+ virtual ~ImmutableKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ Value _value;
+};
+
+/** Implementation of a Constraint that makes two keys mutually exclusive. Fails if both keys
+ * are set.
+ */
+class MutuallyExclusiveKeyConstraint : public KeyConstraint {
+public:
+ MutuallyExclusiveKeyConstraint(const Key& key, const Key& otherKey)
+ : KeyConstraint(key), _otherKey(otherKey) {}
+ virtual ~MutuallyExclusiveKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ Key _otherKey;
+};
+
+/** Implementation of a Constraint that makes one key require another. Fails if the first key
+ * is set but the other is not.
+ */
+class RequiresOtherKeyConstraint : public KeyConstraint {
+public:
+ RequiresOtherKeyConstraint(const Key& key, const Key& otherKey)
+ : KeyConstraint(key), _otherKey(otherKey) {}
+ virtual ~RequiresOtherKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env);
+ Key _otherKey;
+};
+
+/** Implementation of a Constraint that enforces a specific format on a std::string value. Fails if
+ * the value of the key is not a std::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"
+ */
+template <typename T>
+class TypeKeyConstraint : public KeyConstraint {
+public:
+ TypeKeyConstraint(const Key& k) : KeyConstraint(k) {}
+ virtual ~TypeKeyConstraint() {}
+
+private:
+ virtual Status check(const Environment& env) {
+ Value val;
+ Status s = env.get(_key, &val);
+ if (!s.isOK()) {
+ // Key not set, skipping type constraint check
return Status::OK();
}
- };
-} // namespace optionenvironment
-} // namespace mongo
+ // The code that controls whether a type is "compatible" is contained in the Value
+ // class, so if that handles compatibility between numeric types then this will too.
+ T typedVal;
+ if (!val.get(&typedVal).isOK()) {
+ StringBuilder sb;
+ sb << "Error: value for key: " << _key << " was found as type: " << val.typeToString()
+ << " but is required to be type: " << typeid(typedVal).name();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ return Status::OK();
+ }
+};
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/environment.cpp b/src/mongo/util/options_parser/environment.cpp
index 1178b6e356f..b5a9a61a7e6 100644
--- a/src/mongo/util/options_parser/environment.cpp
+++ b/src/mongo/util/options_parser/environment.cpp
@@ -38,351 +38,337 @@
namespace mongo {
namespace optionenvironment {
- using boost::shared_ptr;
- using std::string;
- using std::type_info;
-
- // Environment implementation
-
- Status Environment::addKeyConstraint(KeyConstraint* keyConstraint) {
- keyConstraints.push_back(keyConstraint);
- return Status::OK();
- }
- Status Environment::addConstraint(Constraint* constraint) {
- constraints.push_back(constraint);
- return Status::OK();
- }
-
- /** Get the value at Key. Note that we should not be able to add empty values to the
- * environment, so we don't check for that here */
- Status Environment::get(const Key& get_key, Value* get_value) const {
- typedef std::map<Key, Value>::const_iterator it_type;
- it_type value = values.find(get_key);
- if (value == values.end()) {
- value = default_values.find(get_key);
- if (value == default_values.end()) {
- StringBuilder sb;
- sb << "Value not found for key: " << get_key;
- return Status(ErrorCodes::NoSuchKey, sb.str());
- }
+using boost::shared_ptr;
+using std::string;
+using std::type_info;
+
+// Environment implementation
+
+Status Environment::addKeyConstraint(KeyConstraint* keyConstraint) {
+ keyConstraints.push_back(keyConstraint);
+ return Status::OK();
+}
+Status Environment::addConstraint(Constraint* constraint) {
+ constraints.push_back(constraint);
+ return Status::OK();
+}
+
+/** Get the value at Key. Note that we should not be able to add empty values to the
+ * environment, so we don't check for that here */
+Status Environment::get(const Key& get_key, Value* get_value) const {
+ typedef std::map<Key, Value>::const_iterator it_type;
+ it_type value = values.find(get_key);
+ if (value == values.end()) {
+ value = default_values.find(get_key);
+ if (value == default_values.end()) {
+ StringBuilder sb;
+ sb << "Value not found for key: " << get_key;
+ return Status(ErrorCodes::NoSuchKey, sb.str());
}
- *get_value = value->second;
- return Status::OK();
+ }
+ *get_value = value->second;
+ return Status::OK();
+}
+
+/** Set the Value in our Environment. Always disallow empty values */
+Status Environment::set(const Key& add_key, const Value& add_value) {
+ // 1. Make sure value is not empty
+ if (add_value.isEmpty()) {
+ return Status(ErrorCodes::InternalError, "Attempted to add an empty value");
}
- /** Set the Value in our Environment. Always disallow empty values */
- Status Environment::set(const Key& add_key, const Value& add_value) {
-
- // 1. Make sure value is not empty
- if (add_value.isEmpty()) {
- return Status(ErrorCodes::InternalError, "Attempted to add an empty value");
- }
-
- // 2. Save old values
- std::map <Key, Value> old_values = values;
+ // 2. Save old values
+ std::map<Key, Value> old_values = values;
- // 3. Add value to be added
- values[add_key] = add_value;
+ // 3. Add value to be added
+ values[add_key] = add_value;
- // 4. Validate only if our environment is already valid
- if (valid) {
- Status ret = validate();
- if (!ret.isOK()) {
- // 5. Revert to old values if this was invalid
- values = old_values;
- return ret;
- }
+ // 4. Validate only if our environment is already valid
+ if (valid) {
+ Status ret = validate();
+ if (!ret.isOK()) {
+ // 5. Revert to old values if this was invalid
+ values = old_values;
+ return ret;
}
-
- return Status::OK();
}
- /** Removes a Value from our Environment */
- Status Environment::remove(const Key& remove_key) {
+ return Status::OK();
+}
- // 1. Save old values
- std::map <Key, Value> old_values = values;
+/** Removes a Value from our Environment */
+Status Environment::remove(const Key& remove_key) {
+ // 1. Save old values
+ std::map<Key, Value> old_values = values;
- // 2. Remove value to be removed
- values.erase(remove_key);
+ // 2. Remove value to be removed
+ values.erase(remove_key);
- // 3. Validate only if our environment is already valid
- if (valid) {
- Status ret = validate();
- if (!ret.isOK()) {
- // 4. Revert to old values if this was invalid
- values = old_values;
- return ret;
- }
+ // 3. Validate only if our environment is already valid
+ if (valid) {
+ Status ret = validate();
+ if (!ret.isOK()) {
+ // 4. Revert to old values if this was invalid
+ values = old_values;
+ return ret;
}
-
- return Status::OK();
}
- /** Set the default Value for the given Key in our Environment. Always disallow empty values */
- Status Environment::setDefault(const Key& add_key, const Value& add_value) {
-
- // 1. Make sure value is not empty
- if (add_value.isEmpty()) {
- return Status(ErrorCodes::InternalError, "Attempted to set an empty default value");
- }
-
- // 2. Disallow modifying defaults after calling validate on this Environment
- if (valid) {
- return Status(ErrorCodes::InternalError,
- "Attempted to set a default value after calling validate");
- }
-
- // 3. Add this value to our defaults
- default_values[add_key] = add_value;
+ return Status::OK();
+}
- return Status::OK();
+/** Set the default Value for the given Key in our Environment. Always disallow empty values */
+Status Environment::setDefault(const Key& add_key, const Value& add_value) {
+ // 1. Make sure value is not empty
+ if (add_value.isEmpty()) {
+ return Status(ErrorCodes::InternalError, "Attempted to set an empty default value");
}
- /** Set all the Values from the source Environment in our Environment. Does not check for empty
- * values as the source Environment should not have been allowed to have any */
- Status Environment::setAll(const Environment& add_environment) {
+ // 2. Disallow modifying defaults after calling validate on this Environment
+ if (valid) {
+ return Status(ErrorCodes::InternalError,
+ "Attempted to set a default value after calling validate");
+ }
- // 1. Save old values
- std::map <Key, Value> old_values = values;
+ // 3. Add this value to our defaults
+ default_values[add_key] = add_value;
- // 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();
- iterator != add_values.end(); iterator++) {
- values[iterator->first] = iterator->second;
- }
+ return Status::OK();
+}
- // 3. Validate only if our environment is already valid
- if (valid) {
- Status ret = validate();
- if (!ret.isOK()) {
- // 4. Revert to old values if this was invalid
- values = old_values;
- return ret;
- }
- }
+/** Set all the Values from the source Environment in our Environment. Does not check for empty
+ * values as the source Environment should not have been allowed to have any */
+Status Environment::setAll(const Environment& add_environment) {
+ // 1. Save old values
+ std::map<Key, Value> old_values = values;
- return Status::OK();
+ // 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();
+ iterator != add_values.end();
+ iterator++) {
+ values[iterator->first] = iterator->second;
}
- /** Validate the Environment by iterating over all our constraints and calling them on our
- * Environment
- */
- Status Environment::validate(bool setValid) {
-
- // 1. Iterate and check all KeyConstraints
- typedef std::vector<KeyConstraint*>::iterator it_keyConstraint;
- for (it_keyConstraint iterator = keyConstraints.begin();
- iterator != keyConstraints.end(); iterator++) {
- Status ret = (**iterator)(*this);
- if (!ret.isOK()) {
- return ret;
- }
+ // 3. Validate only if our environment is already valid
+ if (valid) {
+ Status ret = validate();
+ if (!ret.isOK()) {
+ // 4. Revert to old values if this was invalid
+ values = old_values;
+ return ret;
}
+ }
- // 2. Iterate and check all Constraints
- typedef std::vector<Constraint*>::iterator it_constraint;
- for (it_constraint iterator = constraints.begin();
- iterator != constraints.end(); iterator++) {
- Status ret = (**iterator)(*this);
- if (!ret.isOK()) {
- return ret;
- }
- }
+ return Status::OK();
+}
- // 3. Our Environment is now valid. Record this if we should and return success
- if (setValid) {
- valid = true;
+/** Validate the Environment by iterating over all our constraints and calling them on our
+ * Environment
+ */
+Status Environment::validate(bool setValid) {
+ // 1. Iterate and check all KeyConstraints
+ typedef std::vector<KeyConstraint*>::iterator it_keyConstraint;
+ for (it_keyConstraint iterator = keyConstraints.begin(); iterator != keyConstraints.end();
+ iterator++) {
+ Status ret = (**iterator)(*this);
+ if (!ret.isOK()) {
+ return ret;
}
- return Status::OK();
}
- /** Implementation of legacy interface to be consistent with
- * boost::program_options::variables_map during the transition period
- *
- * boost::program_options::variables_map inherits the count function from std::map, which
- * returns 1 if the value is set, and 0 if it is not set
- */
- bool Environment::count(const Key& key) const {
- Value value;
- Status ret = get(key, &value);
- if (ret.isOK()) {
- return true;
- }
- else {
- return false;
+ // 2. Iterate and check all Constraints
+ typedef std::vector<Constraint*>::iterator it_constraint;
+ for (it_constraint iterator = constraints.begin(); iterator != constraints.end(); iterator++) {
+ Status ret = (**iterator)(*this);
+ if (!ret.isOK()) {
+ return ret;
}
}
- Value Environment::operator[](const Key& key) const {
- Value value;
- Status ret = get(key, &value);
- return value;
+ // 3. Our Environment is now valid. Record this if we should and return success
+ if (setValid) {
+ valid = true;
}
+ return Status::OK();
+}
- /* Debugging */
- void Environment::dump() const {
- std::map<Key, Value>::const_iterator iter;
- for (iter = values.begin(); iter != values.end(); ++iter) {
- std::cout << "Key: '"
- << iter->first
- << "', Value: '"
- << iter->second.toString()
- << "'" << std::endl;
- }
+/** Implementation of legacy interface to be consistent with
+ * boost::program_options::variables_map during the transition period
+ *
+ * boost::program_options::variables_map inherits the count function from std::map, which
+ * returns 1 if the value is set, and 0 if it is not set
+ */
+bool Environment::count(const Key& key) const {
+ Value value;
+ Status ret = get(key, &value);
+ if (ret.isOK()) {
+ return true;
+ } else {
+ return false;
}
+}
+
+Value Environment::operator[](const Key& key) const {
+ Value value;
+ Status ret = get(key, &value);
+ return value;
+}
+
+/* Debugging */
+void Environment::dump() const {
+ std::map<Key, Value>::const_iterator iter;
+ for (iter = values.begin(); iter != values.end(); ++iter) {
+ std::cout << "Key: '" << iter->first << "', Value: '" << iter->second.toString() << "'"
+ << std::endl;
+ }
+}
namespace {
- // Converts a map of values with dotted key names to a BSONObj with sub objects.
- // 1. Check for dotted field names and call valueMapToBSON recursively.
- // 2. Append the actual value to our builder if we did not find a dot in our key name.
- Status valueMapToBSON(const std::map<Key, Value>& params,
- BSONObjBuilder* builder,
- const std::string& prefix = std::string()) {
- for (std::map<Key, Value>::const_iterator it(params.begin());
- it != params.end(); it++) {
- Key key = it->first;
- Value value = it->second;
-
- // 1. Check for dotted field names and call valueMapToBSON recursively.
- // NOTE: this code depends on the fact that std::map is sorted
- //
- // EXAMPLE:
- // The map:
- // {
- // "var1.dotted1" : false,
- // "var2" : true,
- // "var1.dotted2" : 6
- // }
- //
- // Gets sorted by keys as:
- // {
- // "var1.dotted1" : false,
- // "var1.dotted2" : 6,
- // "var2" : true
- // }
- //
- // Which means when we see the "var1" prefix, we can iterate until we see either a name
- // without a dot or without "var1" as a prefix, aggregating its fields in a new map as
- // we go. Because the map is sorted, once we see a name without a dot or a "var1"
- // prefix we know that we've seen everything with "var1" as a prefix and can recursively
- // build the entire sub object at once using our new map (which is the only way to make
- // a single coherent BSON sub object using this append only builder).
- //
- // The result of this function for this example should be a BSON object of the form:
- // {
- // "var1" : {
- // "dotted1" : false,
- // "dotted2" : 6
- // },
- // "var2" : true
- // }
-
- // Check to see if this key name is dotted
- std::string::size_type dotOffset = key.find('.');
- if (dotOffset != string::npos) {
-
- // Get the name of the "section" that we are currently iterating. This will be
- // the name of our sub object.
- std::string sectionName = key.substr(0, dotOffset);
-
- // Build a map of the "section" that we are iterating to be passed in a
- // recursive call.
- std::map<Key, Value> sectionMap;
-
- std::string beforeDot = key.substr(0, dotOffset);
- std::string afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
- std::map<Key, Value>::const_iterator it_next = it;
-
- do {
- // Here we know that the key at it_next has a dot and has the prefix we are
- // currently creating a sub object for. Since that means we will definitely
- // process that element in this loop, advance the outer for loop iterator here.
- it = it_next;
-
- // Add the value to our section map with a key of whatever is after the dot
- // since the section name itself will be part of our sub object builder.
- sectionMap[afterDot] = value;
-
- // Peek at the next value for our iterator and check to see if we've finished.
- if (++it_next == params.end()) {
- break;
- }
- key = it_next->first;
- value = it_next->second;
-
- // Look for a dot for our next iteration.
- dotOffset = key.find('.');
-
- beforeDot = key.substr(0, dotOffset);
- afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
+// Converts a map of values with dotted key names to a BSONObj with sub objects.
+// 1. Check for dotted field names and call valueMapToBSON recursively.
+// 2. Append the actual value to our builder if we did not find a dot in our key name.
+Status valueMapToBSON(const std::map<Key, Value>& params,
+ BSONObjBuilder* builder,
+ const std::string& prefix = std::string()) {
+ for (std::map<Key, Value>::const_iterator it(params.begin()); it != params.end(); it++) {
+ Key key = it->first;
+ Value value = it->second;
+
+ // 1. Check for dotted field names and call valueMapToBSON recursively.
+ // NOTE: this code depends on the fact that std::map is sorted
+ //
+ // EXAMPLE:
+ // The map:
+ // {
+ // "var1.dotted1" : false,
+ // "var2" : true,
+ // "var1.dotted2" : 6
+ // }
+ //
+ // Gets sorted by keys as:
+ // {
+ // "var1.dotted1" : false,
+ // "var1.dotted2" : 6,
+ // "var2" : true
+ // }
+ //
+ // Which means when we see the "var1" prefix, we can iterate until we see either a name
+ // without a dot or without "var1" as a prefix, aggregating its fields in a new map as
+ // we go. Because the map is sorted, once we see a name without a dot or a "var1"
+ // prefix we know that we've seen everything with "var1" as a prefix and can recursively
+ // build the entire sub object at once using our new map (which is the only way to make
+ // a single coherent BSON sub object using this append only builder).
+ //
+ // The result of this function for this example should be a BSON object of the form:
+ // {
+ // "var1" : {
+ // "dotted1" : false,
+ // "dotted2" : 6
+ // },
+ // "var2" : true
+ // }
+
+ // Check to see if this key name is dotted
+ std::string::size_type dotOffset = key.find('.');
+ if (dotOffset != string::npos) {
+ // Get the name of the "section" that we are currently iterating. This will be
+ // the name of our sub object.
+ std::string sectionName = key.substr(0, dotOffset);
+
+ // Build a map of the "section" that we are iterating to be passed in a
+ // recursive call.
+ std::map<Key, Value> sectionMap;
+
+ std::string beforeDot = key.substr(0, dotOffset);
+ std::string afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
+ std::map<Key, Value>::const_iterator it_next = it;
+
+ do {
+ // Here we know that the key at it_next has a dot and has the prefix we are
+ // currently creating a sub object for. Since that means we will definitely
+ // process that element in this loop, advance the outer for loop iterator here.
+ it = it_next;
+
+ // Add the value to our section map with a key of whatever is after the dot
+ // since the section name itself will be part of our sub object builder.
+ sectionMap[afterDot] = value;
+
+ // Peek at the next value for our iterator and check to see if we've finished.
+ if (++it_next == params.end()) {
+ break;
}
- while (dotOffset != string::npos && beforeDot == sectionName);
+ key = it_next->first;
+ value = it_next->second;
- // Use the section name in our object builder, and recursively call
- // valueMapToBSON with our sub map with keys that have the section name removed.
- BSONObjBuilder sectionObjBuilder(builder->subobjStart(sectionName));
- valueMapToBSON(sectionMap, &sectionObjBuilder, sectionName);
- sectionObjBuilder.done();
+ // Look for a dot for our next iteration.
+ dotOffset = key.find('.');
- // Our iterator is currently on the last field that matched our dot and prefix, so
- // continue to the next loop iteration.
- continue;
- }
+ beforeDot = key.substr(0, dotOffset);
+ afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1);
+ } while (dotOffset != string::npos && beforeDot == sectionName);
- // 2. Append the actual value to our builder if we did not find a dot in our key name.
- const type_info& type = value.type();
+ // Use the section name in our object builder, and recursively call
+ // valueMapToBSON with our sub map with keys that have the section name removed.
+ BSONObjBuilder sectionObjBuilder(builder->subobjStart(sectionName));
+ valueMapToBSON(sectionMap, &sectionObjBuilder, sectionName);
+ sectionObjBuilder.done();
- if (type == typeid(string)){
- if (value.as<string>().empty()) {
- // boost po uses empty string for flags like --quiet
- // TODO: Remove this when we remove boost::program_options
- builder->appendBool(key, true);
- }
- else {
- builder->append(key, value.as<string>());
- }
+ // Our iterator is currently on the last field that matched our dot and prefix, so
+ // continue to the next loop iteration.
+ continue;
+ }
+
+ // 2. Append the actual value to our builder if we did not find a dot in our key name.
+ const type_info& type = value.type();
+
+ if (type == typeid(string)) {
+ if (value.as<string>().empty()) {
+ // boost po uses empty string for flags like --quiet
+ // TODO: Remove this when we remove boost::program_options
+ builder->appendBool(key, true);
+ } else {
+ builder->append(key, value.as<string>());
}
- else if (type == typeid(int))
- builder->append(key, value.as<int>());
- else if (type == typeid(double))
- builder->append(key, value.as<double>());
- else if (type == typeid(bool))
- builder->appendBool(key, value.as<bool>());
- else if (type == typeid(long))
- builder->appendNumber(key, (long long)value.as<long>());
- else if (type == typeid(unsigned))
- builder->appendNumber(key, (long long)value.as<unsigned>());
- else if (type == typeid(unsigned long long))
- builder->appendNumber(key, (long long)value.as<unsigned long long>());
- else if (type == typeid(StringVector_t))
- builder->append(key, value.as<StringVector_t>());
- else if (type == typeid(StringMap_t)) {
- BSONObjBuilder subBuilder(builder->subobjStart(key));
- StringMap_t stringMap = value.as<StringMap_t>();
- for (StringMap_t::iterator stringMapIt = stringMap.begin();
- stringMapIt != stringMap.end(); stringMapIt++) {
- subBuilder.append(stringMapIt->first, stringMapIt->second);
- }
- subBuilder.done();
+ } else if (type == typeid(int))
+ builder->append(key, value.as<int>());
+ else if (type == typeid(double))
+ builder->append(key, value.as<double>());
+ else if (type == typeid(bool))
+ builder->appendBool(key, value.as<bool>());
+ else if (type == typeid(long))
+ builder->appendNumber(key, (long long)value.as<long>());
+ else if (type == typeid(unsigned))
+ builder->appendNumber(key, (long long)value.as<unsigned>());
+ else if (type == typeid(unsigned long long))
+ builder->appendNumber(key, (long long)value.as<unsigned long long>());
+ else if (type == typeid(StringVector_t))
+ builder->append(key, value.as<StringVector_t>());
+ else if (type == typeid(StringMap_t)) {
+ BSONObjBuilder subBuilder(builder->subobjStart(key));
+ StringMap_t stringMap = value.as<StringMap_t>();
+ for (StringMap_t::iterator stringMapIt = stringMap.begin();
+ stringMapIt != stringMap.end();
+ stringMapIt++) {
+ subBuilder.append(stringMapIt->first, stringMapIt->second);
}
- else
- builder->append(key, "UNKNOWN TYPE: " + demangleName(type));
- }
- return Status::OK();
+ subBuilder.done();
+ } else
+ builder->append(key, "UNKNOWN TYPE: " + demangleName(type));
}
-} // namespace
-
- BSONObj Environment::toBSON() const {
- BSONObjBuilder builder;
- Status ret = valueMapToBSON(values, &builder);
- if (!ret.isOK()) {
- return BSONObj();
- }
- return builder.obj();
+ return Status::OK();
+}
+} // namespace
+
+BSONObj Environment::toBSON() const {
+ BSONObjBuilder builder;
+ Status ret = valueMapToBSON(values, &builder);
+ if (!ret.isOK()) {
+ return BSONObj();
}
+ return builder.obj();
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/environment.h b/src/mongo/util/options_parser/environment.h
index 8c44eb661d1..2941435b9bb 100644
--- a/src/mongo/util/options_parser/environment.h
+++ b/src/mongo/util/options_parser/environment.h
@@ -38,206 +38,206 @@
namespace mongo {
namespace optionenvironment {
- class Constraint;
- class KeyConstraint;
+class Constraint;
+class KeyConstraint;
- typedef std::string Key;
+typedef std::string Key;
- /** An Environment is a map of values that can be validated according to a set of registered
- * constraints
- *
- * Usage overview:
- *
- * 1. Create an empty Environment
- * 2. Add Constraints
- * 3. Set Key/Value pairs (will not cause constraints to be triggered)
- * 4. Validate (will run all constraints)
- * 5. Access
- * 6. Set/Modify Key/Value pairs (will run all constraints and reject invalid modifications)
- * 7. Access
- *
- * Since the constraints are run whenever we try to set or modify Key/Value pairs after we
- * validate, we have the invariant that the Environment is always valid according to its
- * Constraints after validation. Adding new constraints is disallowed after validation.
- *
- * Usage example:
- *
- * // Create an empty Environment
- * Environment environment;
- *
- * // Initialize our first Key and Value
- * Key key1("key1");
- * Value value1(1);
+/** An Environment is a map of values that can be validated according to a set of registered
+ * constraints
+ *
+ * Usage overview:
+ *
+ * 1. Create an empty Environment
+ * 2. Add Constraints
+ * 3. Set Key/Value pairs (will not cause constraints to be triggered)
+ * 4. Validate (will run all constraints)
+ * 5. Access
+ * 6. Set/Modify Key/Value pairs (will run all constraints and reject invalid modifications)
+ * 7. Access
+ *
+ * Since the constraints are run whenever we try to set or modify Key/Value pairs after we
+ * validate, we have the invariant that the Environment is always valid according to its
+ * Constraints after validation. Adding new constraints is disallowed after validation.
+ *
+ * Usage example:
+ *
+ * // Create an empty Environment
+ * Environment environment;
+ *
+ * // Initialize our first Key and Value
+ * Key key1("key1");
+ * Value value1(1);
+ *
+ * // Add a Constraint on "key1"
+ * Status ret = environment.addConstraint(new ImmutableKeyConstraint("key1"));
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Set our first Key and Value to the Environment
+ * ret = environment.set(key1, value1);
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Attempt to mutate should be successful, since validate has not been called
+ * ret = environment.set(key1, Value(2));
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Validate our Environment
+ * ret = environment.validate();
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Access our Environment
+ * int intvalue1;
+ * ret = environment.get(key1, &intvalue1);
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ *
+ * // Attempt to mutate should fail, since validate has been called
+ * ret = environment.set(key1, Value(3));
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ */
+
+class Environment {
+public:
+ Environment() : valid(false) {}
+ ~Environment() {}
+
+ /** These functions are to add Constraints and KeyConstraints which will be run against
+ * this environment in the following situations:
+ * 1. in the "validate" function
+ * 2. in the "set" function after validate has been called successfully
*
- * // Add a Constraint on "key1"
- * Status ret = environment.addConstraint(new ImmutableKeyConstraint("key1"));
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * It is an error to call these functions after "validate" has been called
*
- * // Set our first Key and Value to the Environment
- * ret = environment.set(key1, value1);
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * NOTE: These DO NOT take ownership of the pointer passed in
+ */
+ Status addKeyConstraint(KeyConstraint* keyConstraint);
+ Status addConstraint(Constraint* constraint);
+
+ /** Add the Value to this Environment with the given Key. If "validate" has already
+ * been called on this Environment, runs all Constraints on the new Environment. If
+ * any of the Constraints fail, reverts to the old Environment and returns an error
+ */
+ Status set(const Key& key, const Value& value);
+
+ /** Remove the Value from this Environment with the given Key. If "validate" has
+ * already been called on this Environment, runs all Constraints on the new Environment.
+ * If any of the Constraints fail, reverts to the old Environment and returns an error
+ */
+ Status remove(const Key& key);
+
+ /** Add a default Value to this Environment with the given Key. Fails if validate has
+ * already been called on our environment. The get functions will return the default
+ * if one exists and the value has not been explicitly set.
+ */
+ Status setDefault(const Key& key, const Value& value);
+
+ /** Populate the given Value with the Value stored for the given Key. Return a success
+ * status if the value was found, or an error status if the value was not found.
+ * Leaves the Value unchanged on error.
+ */
+ Status get(const Key& key, Value* value) const;
+
+ /** Same as the above get interface, but supports directly getting C++ types without the
+ * intermediate Value and has the added failure case of the value being the wrong type
+ */
+ template <typename T>
+ Status get(const Key& key, T* value_contents) const;
+
+ /** Runs all registered Constraints and returns the result. If "setValid" is true and
+ * validation succeeds, marks this as a valid Environment so that any modifications will
+ * re run all Constraints
+ */
+ Status validate(bool setValid = true);
+
+ /** Sets all variables in the given Environment in this Environment. Does not add
+ * Constraints
+ */
+ Status setAll(const Environment& other);
+
+ /** The functions below are the legacy interface to be consistent with
+ * boost::program_options::variables_map during the transition period
+ */
+
+ /**
+ * @return 1 if the given Key has a Value set in this Environment and 0 if not
+ */
+ bool count(const Key& key) const;
+
+ /**
+ * @return the Value for the given Key in this Environment. Returns an empty Value if
+ * Key is not set.
+ */
+ Value operator[](const Key& key) const;
+
+ /**
+ * Gets the BSON representation of this Environment. This will collapse dotted fields
+ * into sub objects.
*
- * // Attempt to mutate should be successful, since validate has not been called
- * ret = environment.set(key1, Value(2));
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * Example:
*
- * // Validate our Environment
- * ret = environment.validate();
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * The following Environment values map:
+ * "a.b.c" -> true
+ * "a.b.d" -> false
+ * "a.e.f" -> 0
+ * "a.e.g" -> 1
+ * "a.h" -> "foo"
*
- * // Access our Environment
- * int intvalue1;
- * ret = environment.get(key1, &intvalue1);
- * if (!ret.isOK()) {
- * return ret;
+ * Has a BSON represation of (shown as JSON):
+ * { "a" : {
+ * "b" : {
+ * "c" : true,
+ * "d" : false
+ * },
+ * "e" : {
+ * "f" : 0,
+ * "g" : 1
+ * },
+ * "h" : "foo"
+ * }
* }
*
- * // Attempt to mutate should fail, since validate has been called
- * ret = environment.set(key1, Value(3));
- * if (!ret.isOK()) {
- * return ret;
- * }
+ * Note that the BSON representation only includes fields that were explicitly set using
+ * setAll or set, and not defaults that were specified using setDefault.
*/
-
- class Environment {
- public:
- Environment() : valid(false) { }
- ~Environment() { }
-
- /** These functions are to add Constraints and KeyConstraints which will be run against
- * this environment in the following situations:
- * 1. in the "validate" function
- * 2. in the "set" function after validate has been called successfully
- *
- * It is an error to call these functions after "validate" has been called
- *
- * NOTE: These DO NOT take ownership of the pointer passed in
- */
- Status addKeyConstraint(KeyConstraint* keyConstraint);
- Status addConstraint(Constraint* constraint);
-
- /** Add the Value to this Environment with the given Key. If "validate" has already
- * been called on this Environment, runs all Constraints on the new Environment. If
- * any of the Constraints fail, reverts to the old Environment and returns an error
- */
- Status set(const Key& key, const Value& value);
-
- /** Remove the Value from this Environment with the given Key. If "validate" has
- * already been called on this Environment, runs all Constraints on the new Environment.
- * If any of the Constraints fail, reverts to the old Environment and returns an error
- */
- Status remove(const Key& key);
-
- /** Add a default Value to this Environment with the given Key. Fails if validate has
- * already been called on our environment. The get functions will return the default
- * if one exists and the value has not been explicitly set.
- */
- Status setDefault(const Key& key, const Value& value);
-
- /** Populate the given Value with the Value stored for the given Key. Return a success
- * status if the value was found, or an error status if the value was not found.
- * Leaves the Value unchanged on error.
- */
- Status get(const Key& key, Value* value) const;
-
- /** Same as the above get interface, but supports directly getting C++ types without the
- * intermediate Value and has the added failure case of the value being the wrong type
- */
- template <typename T>
- Status get(const Key& key, T* value_contents) const;
-
- /** Runs all registered Constraints and returns the result. If "setValid" is true and
- * validation succeeds, marks this as a valid Environment so that any modifications will
- * re run all Constraints
- */
- Status validate(bool setValid=true);
-
- /** Sets all variables in the given Environment in this Environment. Does not add
- * Constraints
- */
- Status setAll(const Environment& other);
-
- /** The functions below are the legacy interface to be consistent with
- * boost::program_options::variables_map during the transition period
- */
-
- /**
- * @return 1 if the given Key has a Value set in this Environment and 0 if not
- */
- bool count(const Key& key) const;
-
- /**
- * @return the Value for the given Key in this Environment. Returns an empty Value if
- * Key is not set.
- */
- Value operator[](const Key& key) const;
-
- /**
- * Gets the BSON representation of this Environment. This will collapse dotted fields
- * into sub objects.
- *
- * Example:
- *
- * The following Environment values map:
- * "a.b.c" -> true
- * "a.b.d" -> false
- * "a.e.f" -> 0
- * "a.e.g" -> 1
- * "a.h" -> "foo"
- *
- * Has a BSON represation of (shown as JSON):
- * { "a" : {
- * "b" : {
- * "c" : true,
- * "d" : false
- * },
- * "e" : {
- * "f" : 0,
- * "g" : 1
- * },
- * "h" : "foo"
- * }
- * }
- *
- * Note that the BSON representation only includes fields that were explicitly set using
- * setAll or set, and not defaults that were specified using setDefault.
- */
- BSONObj toBSON() const;
-
- /* Debugging */
- void dump() const;
-
- protected:
- std::vector<Constraint*> constraints;
- std::vector<KeyConstraint*> keyConstraints;
- std::map <Key, Value> values;
- std::map <Key, Value> default_values;
- bool valid;
- };
-
- template <typename T>
- Status Environment::get(const Key& get_key, T* get_value) const {
- Value value;
- Status ret = get(get_key, &value);
- if (!ret.isOK()) {
- return ret;
- }
- ret = value.get(get_value);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting value for key: \"" << get_key << "\": " << ret.toString();
- return Status(ErrorCodes::NoSuchKey, sb.str());
- }
- return Status::OK();
+ BSONObj toBSON() const;
+
+ /* Debugging */
+ void dump() const;
+
+protected:
+ std::vector<Constraint*> constraints;
+ std::vector<KeyConstraint*> keyConstraints;
+ std::map<Key, Value> values;
+ std::map<Key, Value> default_values;
+ bool valid;
+};
+
+template <typename T>
+Status Environment::get(const Key& get_key, T* get_value) const {
+ Value value;
+ Status ret = get(get_key, &value);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ ret = value.get(get_value);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting value for key: \"" << get_key << "\": " << ret.toString();
+ return Status(ErrorCodes::NoSuchKey, sb.str());
}
+ return Status::OK();
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/environment_test.cpp b/src/mongo/util/options_parser/environment_test.cpp
index 20c54466b6f..e87267c013e 100644
--- a/src/mongo/util/options_parser/environment_test.cpp
+++ b/src/mongo/util/options_parser/environment_test.cpp
@@ -33,140 +33,139 @@
namespace {
- using mongo::ErrorCodes;
- using mongo::Status;
-
- namespace moe = mongo::optionenvironment;
-
- TEST(Environment, EmptyValue) {
- moe::Environment environment;
- ASSERT_NOT_OK(environment.set(moe::Key("empty"), moe::Value()));
- }
-
- TEST(Environment, Immutable) {
- moe::Environment environment;
- 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)));
- }
-
- TEST(Environment, OutOfRange) {
- moe::Environment environment;
- 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;
- 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;
- 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;
- 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());
- }
-
- TEST(Environment, MutuallyExclusive) {
- moe::Environment environment;
- moe::MutuallyExclusiveKeyConstraint constraint(moe::Key("key"),moe::Key("otherKey"));
- environment.addKeyConstraint(&constraint);
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
- ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
- ASSERT_NOT_OK(environment.validate());
- }
-
- TEST(Environment, RequiresOther) {
- moe::Environment environment;
- moe::RequiresOtherKeyConstraint constraint(moe::Key("key"),moe::Key("otherKey"));
- environment.addKeyConstraint(&constraint);
- ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
- ASSERT_NOT_OK(environment.validate());
- ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
- ASSERT_OK(environment.validate());
- }
-
- TEST(Environment, StringFormat) {
- moe::Environment environment;
- moe::StringFormatKeyConstraint constraint(moe::Key("key"), "[0-9]","[0-9]");
- environment.addKeyConstraint(&constraint);
- 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)));
- std::string notNumber;
- ASSERT_NOT_OK(environment.get(moe::Key("number"), &notNumber));
- int number;
- ASSERT_OK(environment.get(moe::Key("number"), &number));
- ASSERT_EQUALS(number, 5);
- }
-
- TEST(ToBSONTests, NormalValues) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("val1"), moe::Value(6)));
- ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(std::string("string"))));
- mongo::BSONObj obj = BSON( "val1" << 6 << "val2" << "string" );
- // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
- // based on the sort order of keys in a std::map.
- ASSERT_EQUALS(obj, environment.toBSON());
- }
-
- TEST(ToBSONTests, DottedValues) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("val1.dotted1"), moe::Value(6)));
- ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(true)));
- ASSERT_OK(environment.set(moe::Key("val1.dotted2"), moe::Value(std::string("string"))));
- mongo::BSONObj obj = BSON("val1" << BSON( "dotted1" << 6 << "dotted2" << "string") <<
- "val2" << true );
- // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
- // based on the sort order of keys in a std::map.
- ASSERT_EQUALS(obj, environment.toBSON());
- }
-
- TEST(ToBSONTests, DeepDottedValues) {
- moe::Environment environment;
- ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third1"), moe::Value(6)));
- ASSERT_OK(environment.set(moe::Key("val1.first1.second2.third1"), moe::Value(false)));
- ASSERT_OK(environment.set(moe::Key("val1.first2"), moe::Value(std::string("string"))));
- ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third2"), moe::Value(true)));
- ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(6.0)));
- mongo::BSONObj obj = BSON("val1" << BSON("first1" <<
- BSON("second1" <<
- BSON("third1" << 6 << "third2" << true) <<
- "second2" <<
- BSON("third1" << false)) <<
- "first2" << "string") <<
- "val2" << 6.0);
- // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
- // based on the sort order of keys in a std::map.
- ASSERT_EQUALS(obj, environment.toBSON());
- }
-} // unnamed namespace
+using mongo::ErrorCodes;
+using mongo::Status;
+
+namespace moe = mongo::optionenvironment;
+
+TEST(Environment, EmptyValue) {
+ moe::Environment environment;
+ ASSERT_NOT_OK(environment.set(moe::Key("empty"), moe::Value()));
+}
+
+TEST(Environment, Immutable) {
+ moe::Environment environment;
+ 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)));
+}
+
+TEST(Environment, OutOfRange) {
+ moe::Environment environment;
+ 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;
+ 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;
+ 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;
+ 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());
+}
+
+TEST(Environment, MutuallyExclusive) {
+ moe::Environment environment;
+ moe::MutuallyExclusiveKeyConstraint constraint(moe::Key("key"), moe::Key("otherKey"));
+ environment.addKeyConstraint(&constraint);
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
+ ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
+ ASSERT_NOT_OK(environment.validate());
+}
+
+TEST(Environment, RequiresOther) {
+ moe::Environment environment;
+ moe::RequiresOtherKeyConstraint constraint(moe::Key("key"), moe::Key("otherKey"));
+ environment.addKeyConstraint(&constraint);
+ ASSERT_OK(environment.set(moe::Key("key"), moe::Value(1)));
+ ASSERT_NOT_OK(environment.validate());
+ ASSERT_OK(environment.set(moe::Key("otherKey"), moe::Value(1)));
+ ASSERT_OK(environment.validate());
+}
+
+TEST(Environment, StringFormat) {
+ moe::Environment environment;
+ moe::StringFormatKeyConstraint constraint(moe::Key("key"), "[0-9]", "[0-9]");
+ environment.addKeyConstraint(&constraint);
+ 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)));
+ std::string notNumber;
+ ASSERT_NOT_OK(environment.get(moe::Key("number"), &notNumber));
+ int number;
+ ASSERT_OK(environment.get(moe::Key("number"), &number));
+ ASSERT_EQUALS(number, 5);
+}
+
+TEST(ToBSONTests, NormalValues) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("val1"), moe::Value(6)));
+ ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(std::string("string"))));
+ mongo::BSONObj obj = BSON("val1" << 6 << "val2"
+ << "string");
+ // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
+ // based on the sort order of keys in a std::map.
+ ASSERT_EQUALS(obj, environment.toBSON());
+}
+
+TEST(ToBSONTests, DottedValues) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("val1.dotted1"), moe::Value(6)));
+ ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(true)));
+ ASSERT_OK(environment.set(moe::Key("val1.dotted2"), moe::Value(std::string("string"))));
+ mongo::BSONObj obj = BSON("val1" << BSON("dotted1" << 6 << "dotted2"
+ << "string") << "val2" << true);
+ // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
+ // based on the sort order of keys in a std::map.
+ ASSERT_EQUALS(obj, environment.toBSON());
+}
+
+TEST(ToBSONTests, DeepDottedValues) {
+ moe::Environment environment;
+ ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third1"), moe::Value(6)));
+ ASSERT_OK(environment.set(moe::Key("val1.first1.second2.third1"), moe::Value(false)));
+ ASSERT_OK(environment.set(moe::Key("val1.first2"), moe::Value(std::string("string"))));
+ ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third2"), moe::Value(true)));
+ ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(6.0)));
+ mongo::BSONObj obj =
+ BSON("val1" << BSON("first1" << BSON("second1" << BSON("third1" << 6 << "third2" << true)
+ << "second2" << BSON("third1" << false))
+ << "first2"
+ << "string") << "val2" << 6.0);
+ // TODO: Put a comparison here that doesn't depend on the field order. Right now it is
+ // based on the sort order of keys in a std::map.
+ ASSERT_EQUALS(obj, environment.toBSON());
+}
+} // unnamed namespace
diff --git a/src/mongo/util/options_parser/option_description.cpp b/src/mongo/util/options_parser/option_description.cpp
index c903a3ddce0..d863a614604 100644
--- a/src/mongo/util/options_parser/option_description.cpp
+++ b/src/mongo/util/options_parser/option_description.cpp
@@ -35,296 +35,275 @@
namespace mongo {
namespace optionenvironment {
- using boost::shared_ptr;
-
- namespace {
- /**
- * Utility function check that the type of our Value matches our OptionType
- */
- Status checkValueType(OptionType type, Value value) {
- switch (type) {
- case StringVector:
- {
- std::vector<std::string> valueType;
- return value.get(&valueType);
- }
- case Bool:
- {
- bool valueType;
- return value.get(&valueType);
- }
- case Double:
- {
- double valueType;
- return value.get(&valueType);
- }
- case Int:
- {
- int valueType;
- return value.get(&valueType);
- }
- case Long:
- {
- long valueType;
- return value.get(&valueType);
- }
- case String:
- {
- std::string valueType;
- return value.get(&valueType);
- }
- case UnsignedLongLong:
- {
- unsigned long long valueType;
- return value.get(&valueType);
- }
- case Unsigned:
- {
- unsigned valueType;
- return value.get(&valueType);
- }
- case Switch:
- {
- bool valueType;
- return value.get(&valueType);
- }
- default:
- {
- StringBuilder sb;
- sb << "Unrecognized option type: " << type;
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
+using boost::shared_ptr;
+
+namespace {
+/**
+ * Utility function check that the type of our Value matches our OptionType
+ */
+Status checkValueType(OptionType type, Value value) {
+ switch (type) {
+ case StringVector: {
+ std::vector<std::string> valueType;
+ return value.get(&valueType);
}
- } // namespace
-
- OptionDescription::OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description)
- : _dottedName(dottedName),
- _singleName(singleName),
- _type(type),
- _description(description),
- _isVisible(true),
- _default(Value()),
- _implicit(Value()),
- _isComposing(false),
- _sources(SourceAll),
- _positionalStart(-1),
- _positionalEnd(-1),
- _constraints(),
- _deprecatedDottedNames() { }
-
- OptionDescription::OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames)
- : _dottedName(dottedName),
- _singleName(singleName),
- _type(type),
- _description(description),
- _isVisible(true),
- _default(Value()),
- _implicit(Value()),
- _isComposing(false),
- _sources(SourceAll),
- _positionalStart(-1),
- _positionalEnd(-1),
- _constraints(),
- _deprecatedDottedNames(deprecatedDottedNames) {
-
- // 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 deprecated dotted name";
- throw DBException(sb.str(), ErrorCodes::BadValue);
+ case Bool: {
+ bool valueType;
+ return value.get(&valueType);
}
- // 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 deprecated "
- << "dotted name: " << _dottedName;
- throw DBException(sb.str(), ErrorCodes::BadValue);
+ case Double: {
+ double valueType;
+ return value.get(&valueType);
}
- }
-
- OptionDescription& OptionDescription::hidden() {
- _isVisible = false;
- return *this;
- }
-
- OptionDescription& OptionDescription::setDefault(Value defaultValue) {
-
- // Disallow registering a default for a composing option since the interaction between the
- // two is unclear (for example, should we override or compose the default)
- if (_isComposing) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot register a default value for a composing option";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case Int: {
+ int valueType;
+ return value.get(&valueType);
}
-
- // Make sure the type of our default value matches our declared type
- Status ret = checkValueType(_type, defaultValue);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "mismatch between declared type and type of default value: "
- << ret.toString();
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case Long: {
+ long valueType;
+ return value.get(&valueType);
}
-
- // It doesn't make sense to set a "default value" for switch options, so disallow it here
- if (_type == Switch) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "the default value of a Switch option is false and cannot be changed";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case String: {
+ std::string valueType;
+ return value.get(&valueType);
}
-
- _default = defaultValue;
- return *this;
- }
-
- OptionDescription& OptionDescription::setImplicit(Value implicitValue) {
-
- // Disallow registering an implicit value for a composing option since the interaction
- // between the two is unclear
- if (_isComposing) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot register an implicit value for a composing option";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case UnsignedLongLong: {
+ unsigned long long valueType;
+ return value.get(&valueType);
}
-
- // Make sure the type of our implicit value matches our declared type
- Status ret = checkValueType(_type, implicitValue);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "mismatch between declared type and type of implicit value: "
- << ret.toString();
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ case Unsigned: {
+ unsigned valueType;
+ return value.get(&valueType);
}
-
- // It doesn't make sense to set an "implicit value" for switch options since they can never
- // have an argument anyway, so disallow it here
- if (_type == Switch) {
+ case Switch: {
+ bool valueType;
+ return value.get(&valueType);
+ }
+ default: {
StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "the implicit value of a Switch option is true and cannot be changed";
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ sb << "Unrecognized option type: " << type;
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- _implicit = implicitValue;
- return *this;
+ }
+}
+} // namespace
+
+OptionDescription::OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description)
+ : _dottedName(dottedName),
+ _singleName(singleName),
+ _type(type),
+ _description(description),
+ _isVisible(true),
+ _default(Value()),
+ _implicit(Value()),
+ _isComposing(false),
+ _sources(SourceAll),
+ _positionalStart(-1),
+ _positionalEnd(-1),
+ _constraints(),
+ _deprecatedDottedNames() {}
+
+OptionDescription::OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames)
+ : _dottedName(dottedName),
+ _singleName(singleName),
+ _type(type),
+ _description(description),
+ _isVisible(true),
+ _default(Value()),
+ _implicit(Value()),
+ _isComposing(false),
+ _sources(SourceAll),
+ _positionalStart(-1),
+ _positionalEnd(-1),
+ _constraints(),
+ _deprecatedDottedNames(deprecatedDottedNames) {
+ // 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 deprecated dotted name";
+ throw DBException(sb.str(), ErrorCodes::BadValue);
+ }
+ // 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 deprecated "
+ << "dotted name: " << _dottedName;
+ throw DBException(sb.str(), ErrorCodes::BadValue);
+ }
+}
+
+OptionDescription& OptionDescription::hidden() {
+ _isVisible = false;
+ return *this;
+}
+
+OptionDescription& OptionDescription::setDefault(Value defaultValue) {
+ // Disallow registering a default for a composing option since the interaction between the
+ // two is unclear (for example, should we override or compose the default)
+ if (_isComposing) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot register a default value for a composing option";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::composing() {
-
- if (_type != StringVector && _type != StringMap) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "only options registered as StringVector or StringMap can be composing";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+ // Make sure the type of our default value matches our declared type
+ Status ret = checkValueType(_type, defaultValue);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "mismatch between declared type and type of default value: " << ret.toString();
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- // Disallow registering a default value for a composing option since the interaction
- // between the two is unclear
- if (!_default.isEmpty()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot make an option with an default value composing";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+ // It doesn't make sense to set a "default value" for switch options, so disallow it here
+ if (_type == Switch) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "the default value of a Switch option is false and cannot be changed";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- // Disallow registering an implicit value for a composing option since the interaction
- // between the two is unclear
- if (!_implicit.isEmpty()) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Cannot make an option with an implicit value composing";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+ _default = defaultValue;
+ return *this;
+}
+
+OptionDescription& OptionDescription::setImplicit(Value implicitValue) {
+ // Disallow registering an implicit value for a composing option since the interaction
+ // between the two is unclear
+ if (_isComposing) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot register an implicit value for a composing option";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- _isComposing = true;
- return *this;
+ // Make sure the type of our implicit value matches our declared type
+ Status ret = checkValueType(_type, implicitValue);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "mismatch between declared type and type of implicit value: " << ret.toString();
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::setSources(OptionSources sources) {
- _sources = sources;
- return *this;
+ // It doesn't make sense to set an "implicit value" for switch options since they can never
+ // have an argument anyway, so disallow it here
+ if (_type == Switch) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "the implicit value of a Switch option is true and cannot be changed";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::positional(int start, int end) {
+ _implicit = implicitValue;
+ return *this;
+}
- if (start < 1 || (end < 1 && end != -1) || (end != -1 && end < start)) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Invalid positional specification: \"start\": " << start << ", \"end\": " << end;
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
+OptionDescription& OptionDescription::composing() {
+ if (_type != StringVector && _type != StringMap) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "only options registered as StringVector or StringMap can be composing";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- if ((end - start) > 0) {
- if (_type != StringVector) {
- StringBuilder sb;
- sb << "Could not register option \"" << _dottedName << "\": "
- << "Positional range implies that multiple values are allowed, "
- << "but option is not registered as type StringVector";
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
- }
+ // Disallow registering a default value for a composing option since the interaction
+ // between the two is unclear
+ if (!_default.isEmpty()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot make an option with an default value composing";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
- _positionalStart = start;
- _positionalEnd = end;
- return *this;
+ // Disallow registering an implicit value for a composing option since the interaction
+ // between the two is unclear
+ if (!_implicit.isEmpty()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Cannot make an option with an implicit value composing";
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::addConstraint(Constraint* c) {
- _constraints.push_back(boost::shared_ptr<Constraint>(c));
- return *this;
+ _isComposing = true;
+ return *this;
+}
+
+OptionDescription& OptionDescription::setSources(OptionSources sources) {
+ _sources = sources;
+ return *this;
+}
+
+OptionDescription& OptionDescription::positional(int start, int end) {
+ if (start < 1 || (end < 1 && end != -1) || (end != -1 && end < start)) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << _dottedName << "\": "
+ << "Invalid positional specification: \"start\": " << start << ", \"end\": " << end;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
}
- OptionDescription& OptionDescription::validRange(long min, long max) {
- if (_type != Double &&
- _type != Int &&
- _type != Long &&
- _type != UnsignedLongLong &&
- _type != Unsigned) {
+ if ((end - start) > 0) {
+ if (_type != StringVector) {
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;
+ << "Positional range implies that multiple values are allowed, "
+ << "but option is not registered as type StringVector";
throw DBException(sb.str(), ErrorCodes::InternalError);
}
-
- return addConstraint(new NumericKeyConstraint(_dottedName, min, max));
}
- OptionDescription& OptionDescription::incompatibleWith(const std::string& otherDottedName) {
- return addConstraint(new MutuallyExclusiveKeyConstraint(_dottedName, otherDottedName));
+ _positionalStart = start;
+ _positionalEnd = end;
+ 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);
}
- OptionDescription& OptionDescription::requires(const std::string& otherDottedName) {
- return addConstraint(new RequiresOtherKeyConstraint(_dottedName, otherDottedName));
+ return addConstraint(new NumericKeyConstraint(_dottedName, min, max));
+}
+
+OptionDescription& OptionDescription::incompatibleWith(const std::string& otherDottedName) {
+ return addConstraint(new MutuallyExclusiveKeyConstraint(_dottedName, otherDottedName));
+}
+
+OptionDescription& OptionDescription::requires(const std::string& otherDottedName) {
+ 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);
}
- 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));
- }
+ return addConstraint(new StringFormatKeyConstraint(_dottedName, regexFormat, displayFormat));
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // 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 5bfe83c3a30..1dce8ea2980 100644
--- a/src/mongo/util/options_parser/option_description.h
+++ b/src/mongo/util/options_parser/option_description.h
@@ -37,200 +37,200 @@
namespace mongo {
namespace optionenvironment {
+/**
+ * An OptionType is an enum of all the types we support in the OptionsParser
+ *
+ * NOTE(sverch): The semantics of "Switch" options are completely identical to "Bool" options,
+ * except that on the command line they do not take a value.
+ */
+enum OptionType {
+ StringVector, // po::value< std::vector<std::string> >
+ StringMap, // po::value< std::vector<std::string> > (but in "key=value" format)
+ Bool, // po::value<bool>
+ Double, // po::value<double>
+ Int, // po::value<int>
+ Long, // po::value<long>
+ String, // po::value<std::string>
+ UnsignedLongLong, // po::value<unsigned long long>
+ Unsigned, // po::value<unsigned>
+ Switch // po::bool_switch
+};
+
+/**
+ * An OptionSources is an enum representing where an option can come from
+ */
+enum OptionSources {
+ SourceCommandLine = 1,
+ SourceINIConfig = 2,
+ SourceYAMLConfig = 4,
+ SourceAllConfig = SourceINIConfig | SourceYAMLConfig,
+ SourceAllLegacy = SourceINIConfig | SourceCommandLine,
+ SourceAll = SourceCommandLine | SourceINIConfig | SourceYAMLConfig
+};
+
+/**
+ * The OptionDescription class is a container for information about the options we are expecting
+ * either on the command line or in config files. These should be registered in an
+ * OptionSection instance and passed to an OptionsParser.
+ */
+class OptionDescription {
+public:
+ OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description);
+
+ OptionDescription(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames);
+
+ /*
+ * The following functions are part of the chaining interface for option registration. See
+ * comments below for what each of these attributes mean, and the OptionSection class for
+ * more details on the chaining interface.
+ */
+
/**
- * An OptionType is an enum of all the types we support in the OptionsParser
+ * 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
+ */
+ OptionDescription& hidden();
+
+ /*
+ * Add a default value for this option if it is not specified
+ *
+ * throws DBException on errors, such as trying to set a default that does not have the same
+ * type as the option, or trying to set a default for a composing option.
+ */
+ OptionDescription& setDefault(Value defaultValue);
+
+ /*
+ * Add an implicit value for this option if it is specified with no argument
+ *
+ * throws DBException on errors, such as trying to set an implicit value that does not have
+ * the same type as the option, or trying to set an implicit value for a composing option.
+ */
+ OptionDescription& setImplicit(Value implicitValue);
+
+ /*
+ * Make this option composing so that the different sources add their values instead of
+ * overriding (eg. setParameter values in the config file and on the command line all get
+ * aggregated together)
*
- * NOTE(sverch): The semantics of "Switch" options are completely identical to "Bool" options,
- * except that on the command line they do not take a value.
+ * throws DBException on errors, such as trying to make an option that is not a vector type
+ * composing, or or trying to set an implicit or default value for a composing option.
+ */
+ OptionDescription& composing();
+
+ /*
+ * Specify the allowed sources for this option, such as CommandLine, JSONConfig, or
+ * INIConfig. The default is SourceAll which means the option can be present in any source
+ */
+ OptionDescription& setSources(OptionSources sources);
+
+ /*
+ * Specify that this is a positional option. "start" should be the first position the
+ * option can be found in, and "end" is the last position, inclusive. The positions start
+ * at index 1 (after the executable name). If "start" is greater than "end", then the
+ * option must be able to support multiple values. Specifying -1 for the "end" means that
+ * the option can repeat forever. Any "holes" in the positional ranges will result in an
+ * error during parsing.
+ *
+ * Examples:
+ *
+ * .positional(1,1) // Single positional argument at position 1
+ * ...
+ * .positional(2,3) // More positional arguments at position 2 and 3 (multivalued option)
+ * ...
+ * .positional(4,-1) // Can repeat this positional option forever after position 4
+ *
+ *
+ * (sverch) TODO: When we can support it (i.e. when we can get rid of boost) add a
+ * "positionalOnly" attribute that specifies that it is not also a command line flag. In
+ * boost program options, the only way to have a positional argument is to register a flag
+ * and mark it as also being positional.
+ */
+ 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.
*/
- enum OptionType {
- StringVector, // po::value< std::vector<std::string> >
- StringMap, // po::value< std::vector<std::string> > (but in "key=value" format)
- Bool, // po::value<bool>
- Double, // po::value<double>
- Int, // po::value<int>
- Long, // po::value<long>
- String, // po::value<std::string>
- UnsignedLongLong, // po::value<unsigned long long>
- Unsigned, // po::value<unsigned>
- Switch // po::bool_switch
- };
/**
- * An OptionSources is an enum representing where an option can come from
+ * Specifies the range allowed for this option. Only allowed for options with numeric type.
*/
- enum OptionSources {
- SourceCommandLine = 1,
- SourceINIConfig = 2,
- SourceYAMLConfig = 4,
- SourceAllConfig = SourceINIConfig | SourceYAMLConfig,
- SourceAllLegacy = SourceINIConfig | SourceCommandLine,
- SourceAll = SourceCommandLine | SourceINIConfig | SourceYAMLConfig
- };
+ OptionDescription& validRange(long min, long max);
/**
- * The OptionDescription class is a container for information about the options we are expecting
- * either on the command line or in config files. These should be registered in an
- * OptionSection instance and passed to an OptionsParser.
+ * Specifies that this option is incompatible with another option. The std::string provided must
+ * be the dottedName, which is the name used to access the option in the result Environment.
+ *
+ * TODO: Find a way to check that that option actually exists in our section somewhere.
+ */
+ OptionDescription& incompatibleWith(const std::string& otherDottedName);
+
+ /**
+ * Specifies that this option is requires another option to be specified. The string
+ * provided must be the dottedName, which is the name used to access the option in the
+ * result Environment.
+ */
+ 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 std::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.
+ *
+ * WARNING: This function takes ownership of the Constraint pointer that is passed in.
*/
- class OptionDescription {
- public:
- OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description);
-
- OptionDescription(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames);
-
- /*
- * The following functions are part of the chaining interface for option registration. See
- * comments below for what each of these attributes mean, and the OptionSection class for
- * 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
- */
- OptionDescription& hidden();
-
- /*
- * Add a default value for this option if it is not specified
- *
- * throws DBException on errors, such as trying to set a default that does not have the same
- * type as the option, or trying to set a default for a composing option.
- */
- OptionDescription& setDefault(Value defaultValue);
-
- /*
- * Add an implicit value for this option if it is specified with no argument
- *
- * throws DBException on errors, such as trying to set an implicit value that does not have
- * the same type as the option, or trying to set an implicit value for a composing option.
- */
- OptionDescription& setImplicit(Value implicitValue);
-
- /*
- * Make this option composing so that the different sources add their values instead of
- * overriding (eg. setParameter values in the config file and on the command line all get
- * aggregated together)
- *
- * throws DBException on errors, such as trying to make an option that is not a vector type
- * composing, or or trying to set an implicit or default value for a composing option.
- */
- OptionDescription& composing();
-
- /*
- * Specify the allowed sources for this option, such as CommandLine, JSONConfig, or
- * INIConfig. The default is SourceAll which means the option can be present in any source
- */
- OptionDescription& setSources(OptionSources sources);
-
- /*
- * Specify that this is a positional option. "start" should be the first position the
- * option can be found in, and "end" is the last position, inclusive. The positions start
- * at index 1 (after the executable name). If "start" is greater than "end", then the
- * option must be able to support multiple values. Specifying -1 for the "end" means that
- * the option can repeat forever. Any "holes" in the positional ranges will result in an
- * error during parsing.
- *
- * Examples:
- *
- * .positional(1,1) // Single positional argument at position 1
- * ...
- * .positional(2,3) // More positional arguments at position 2 and 3 (multivalued option)
- * ...
- * .positional(4,-1) // Can repeat this positional option forever after position 4
- *
- *
- * (sverch) TODO: When we can support it (i.e. when we can get rid of boost) add a
- * "positionalOnly" attribute that specifies that it is not also a command line flag. In
- * boost program options, the only way to have a positional argument is to register a flag
- * and mark it as also being positional.
- */
- 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);
-
- /**
- * Specifies that this option is incompatible with another option. The std::string provided must
- * be the dottedName, which is the name used to access the option in the result Environment.
- *
- * TODO: Find a way to check that that option actually exists in our section somewhere.
- */
- OptionDescription& incompatibleWith(const std::string& otherDottedName);
-
- /**
- * Specifies that this option is requires another option to be specified. The string
- * provided must be the dottedName, which is the name used to access the option in the
- * result Environment.
- */
- 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 std::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.
- *
- * 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)
- // (required by boost)
- std::string _description; // Description of option printed in help output
- bool _isVisible; // Visible in help output
- Value _default; // Value if option is not specified
- Value _implicit; // Value if option is specified with no argument
- bool _isComposing; // Aggregate values from different sources instead of overriding
- OptionSources _sources; // Places where an option can be specified (current sources are
- // 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
-
- // Deprecated dotted names - aliases for '_dottedName'.
- std::vector<std::string> _deprecatedDottedNames;
- };
-
-} // namespace optionenvironment
-} // namespace mongo
+ 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)
+ // (required by boost)
+ std::string _description; // Description of option printed in help output
+ bool _isVisible; // Visible in help output
+ Value _default; // Value if option is not specified
+ Value _implicit; // Value if option is specified with no argument
+ bool _isComposing; // Aggregate values from different sources instead of overriding
+ OptionSources _sources; // Places where an option can be specified (current sources are
+ // 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
+
+ // Deprecated dotted names - aliases for '_dottedName'.
+ std::vector<std::string> _deprecatedDottedNames;
+};
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp
index 1e31ce44374..3a46c8a28d5 100644
--- a/src/mongo/util/options_parser/option_section.cpp
+++ b/src/mongo/util/options_parser/option_section.cpp
@@ -39,608 +39,579 @@
namespace mongo {
namespace optionenvironment {
- using boost::shared_ptr;
+using boost::shared_ptr;
- // Registration interface
+// Registration interface
- // TODO: Make sure the section we are adding does not have duplicate options
- Status OptionSection::addSection(const OptionSection& subSection) {
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = subSection._options.begin();
- oditerator != subSection._options.end(); oditerator++) {
- if (oditerator->_positionalStart != -1) {
+// TODO: Make sure the section we are adding does not have duplicate options
+Status OptionSection::addSection(const OptionSection& subSection) {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = subSection._options.begin(); oditerator != subSection._options.end();
+ oditerator++) {
+ if (oditerator->_positionalStart != -1) {
+ StringBuilder sb;
+ sb << "Attempted to add subsection with positional option: " << oditerator->_dottedName;
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ }
+ _subSections.push_back(subSection);
+ return Status::OK();
+}
+
+OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description) {
+ std::vector<std::string> v;
+ return addOptionChaining(dottedName, singleName, type, description, v);
+}
+
+OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::string& deprecatedDottedName) {
+ std::vector<std::string> v;
+ v.push_back(deprecatedDottedName);
+ return addOptionChaining(dottedName, singleName, type, description, v);
+}
+
+OptionDescription& OptionSection::addOptionChaining(
+ const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames) {
+ OptionDescription option(dottedName, singleName, type, description, deprecatedDottedNames);
+
+ // Verify that single name, the dotted name and deprecated dotted names for this option
+ // conflicts with the names for any options we have already registered.
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ if (option._dottedName == oditerator->_dottedName) {
+ StringBuilder sb;
+ sb << "Attempted to register option with duplicate dottedName: " << option._dottedName;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
+ // Allow options with empty singleName since some options are not allowed on the command
+ // line
+ if (!option._singleName.empty() && option._singleName == oditerator->_singleName) {
+ StringBuilder sb;
+ sb << "Attempted to register option with duplicate singleName: " << option._singleName;
+ throw DBException(sb.str(), ErrorCodes::InternalError);
+ }
+ // Deprecated dotted names should not conflict with dotted names or deprecated dotted
+ // names of any other options.
+ if (std::count(option._deprecatedDottedNames.begin(),
+ option._deprecatedDottedNames.end(),
+ oditerator->_dottedName)) {
+ StringBuilder sb;
+ sb << "Attempted to register option with duplicate deprecated dotted name "
+ << "(with another option's dotted name): " << option._dottedName;
+ throw DBException(sb.str(), ErrorCodes::BadValue);
+ }
+ for (std::vector<std::string>::const_iterator i =
+ oditerator->_deprecatedDottedNames.begin();
+ i != oditerator->_deprecatedDottedNames.end();
+ ++i) {
+ if (std::count(option._deprecatedDottedNames.begin(),
+ option._deprecatedDottedNames.end(),
+ *i)) {
StringBuilder sb;
- sb << "Attempted to add subsection with positional option: "
- << oditerator->_dottedName;
- return Status(ErrorCodes::InternalError, sb.str());
+ sb << "Attempted to register option with duplicate deprecated dotted name " << *i
+ << " (other option " << oditerator->_dottedName << ")";
+ throw DBException(sb.str(), ErrorCodes::BadValue);
}
}
- _subSections.push_back(subSection);
- return Status::OK();
}
- OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description) {
- std::vector<std::string> v;
- return addOptionChaining(dottedName, singleName, type, description, v);
+ _options.push_back(option);
+
+ return _options.back();
+}
+
+// Stuff for dealing with Boost
+
+namespace {
+
+/*
+ * Helper for option types that should be interpreted as a string by boost. We do this to
+ * take the responsibility away from boost for handling type conversions, since sometimes
+ * those conversions are inconsistent with our own. See SERVER-14110 For an example.
+ */
+template <typename Type>
+Status typeToBoostStringType(std::auto_ptr<po::value_semantic>* boostType,
+ const Value defaultValue = Value(),
+ const Value implicitValue = Value()) {
+ std::auto_ptr<po::typed_value<std::string>> boostTypeBuilder(po::value<std::string>());
+
+ if (!implicitValue.isEmpty()) {
+ Type implicitValueType;
+ Status ret = implicitValue.get(&implicitValueType);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting implicit value: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ StringBuilder sb;
+ sb << implicitValueType;
+ boostTypeBuilder->implicit_value(sb.str());
}
- OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::string& deprecatedDottedName) {
- std::vector<std::string> v;
- v.push_back(deprecatedDottedName);
- return addOptionChaining(dottedName, singleName, type, description, v);
+ if (!defaultValue.isEmpty()) {
+ Type defaultValueType;
+ Status ret = defaultValue.get(&defaultValueType);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting default value: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ StringBuilder sb;
+ sb << defaultValueType;
+ boostTypeBuilder->default_value(sb.str());
}
- OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames) {
- OptionDescription option(dottedName, singleName, type, description, deprecatedDottedNames);
-
- // Verify that single name, the dotted name and deprecated dotted names for this option
- // conflicts with the names for any options we have already registered.
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- if (option._dottedName == oditerator->_dottedName) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate dottedName: "
- << option._dottedName;
- throw DBException(sb.str(), ErrorCodes::InternalError);
- }
- // Allow options with empty singleName since some options are not allowed on the command
- // line
- if (!option._singleName.empty() && option._singleName == oditerator->_singleName) {
+ *boostType = boostTypeBuilder;
+
+ return Status::OK();
+}
+
+/** Helper function to convert the values of our OptionType enum into the classes that
+ * boost::program_option uses to pass around this information
+ */
+Status typeToBoostType(std::auto_ptr<po::value_semantic>* boostType,
+ OptionType type,
+ const Value defaultValue = Value(),
+ const Value implicitValue = Value(),
+ bool getSwitchAsBool = false) {
+ switch (type) {
+ case StringVector: {
+ *boostType = std::auto_ptr<po::value_semantic>(po::value<std::vector<std::string>>());
+
+ if (!implicitValue.isEmpty()) {
StringBuilder sb;
- sb << "Attempted to register option with duplicate singleName: "
- << option._singleName;
- throw DBException(sb.str(), ErrorCodes::InternalError);
+ sb << "Implicit value not supported for string vector";
+ return Status(ErrorCodes::InternalError, sb.str());
}
- // Deprecated dotted names should not conflict with dotted names or deprecated dotted
- // names of any other options.
- if (std::count(option._deprecatedDottedNames.begin(),
- option._deprecatedDottedNames.end(), oditerator->_dottedName)) {
+
+ if (!defaultValue.isEmpty()) {
StringBuilder sb;
- sb << "Attempted to register option with duplicate deprecated dotted name "
- << "(with another option's dotted name): "
- << option._dottedName;
- throw DBException(sb.str(), ErrorCodes::BadValue);
- }
- for (std::vector<std::string>::const_iterator i =
- oditerator->_deprecatedDottedNames.begin();
- i != oditerator->_deprecatedDottedNames.end(); ++i) {
- if (std::count(option._deprecatedDottedNames.begin(),
- option._deprecatedDottedNames.end(), *i)) {
- StringBuilder sb;
- sb << "Attempted to register option with duplicate deprecated dotted name "
- << *i << " (other option " << oditerator->_dottedName << ")";
- throw DBException(sb.str(), ErrorCodes::BadValue);
- }
+ sb << "Default value not supported for string vector";
+ return Status(ErrorCodes::InternalError, sb.str());
}
- }
-
- _options.push_back(option);
- return _options.back();
- }
+ return Status::OK();
+ }
+ case StringMap: {
+ // Boost doesn't support maps, so we just register a vector parameter and
+ // parse it as "key=value" strings
+ *boostType = std::auto_ptr<po::value_semantic>(po::value<std::vector<std::string>>());
- // Stuff for dealing with Boost
+ if (!implicitValue.isEmpty()) {
+ StringBuilder sb;
+ sb << "Implicit value not supported for string map";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
- namespace {
+ if (!defaultValue.isEmpty()) {
+ StringBuilder sb;
+ sb << "Default value not supported for string map";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
- /*
- * Helper for option types that should be interpreted as a string by boost. We do this to
- * take the responsibility away from boost for handling type conversions, since sometimes
- * those conversions are inconsistent with our own. See SERVER-14110 For an example.
- */
- template <typename Type>
- Status typeToBoostStringType(std::auto_ptr<po::value_semantic>* boostType,
- const Value defaultValue = Value(),
- const Value implicitValue = Value()) {
- std::auto_ptr<po::typed_value<std::string> >
- boostTypeBuilder(po::value<std::string>());
+ return Status::OK();
+ }
+ case Switch: {
+ // In boost, switches default to false which makes it impossible to tell if
+ // a switch in a config file is not present or was explicitly set to false.
+ //
+ // Because of this, and because of the fact that we use the same set of
+ // options for the legacy key=value config file, we need a way to control
+ // whether we are telling boost that an option is a switch type or that an
+ // option is a bool type.
+ if (!getSwitchAsBool) {
+ *boostType = std::auto_ptr<po::value_semantic>(po::bool_switch());
+ return Status::OK();
+ } else {
+ // Switches should be true if they are present with no explicit value.
+ *boostType =
+ std::auto_ptr<po::typed_value<bool>>(po::value<bool>()->implicit_value(true));
+ return Status::OK();
+ }
+ }
+ case Bool: {
+ std::auto_ptr<po::typed_value<bool>> boostTypeBuilder(po::value<bool>());
if (!implicitValue.isEmpty()) {
- Type implicitValueType;
+ bool implicitValueType;
Status ret = implicitValue.get(&implicitValueType);
- if(!ret.isOK()) {
+ if (!ret.isOK()) {
StringBuilder sb;
sb << "Error getting implicit value: " << ret.toString();
return Status(ErrorCodes::InternalError, sb.str());
}
- StringBuilder sb;
- sb << implicitValueType;
- boostTypeBuilder->implicit_value(sb.str());
+ boostTypeBuilder->implicit_value(implicitValueType);
}
if (!defaultValue.isEmpty()) {
- Type defaultValueType;
+ bool defaultValueType;
Status ret = defaultValue.get(&defaultValueType);
- if(!ret.isOK()) {
+ if (!ret.isOK()) {
StringBuilder sb;
sb << "Error getting default value: " << ret.toString();
return Status(ErrorCodes::InternalError, sb.str());
}
- StringBuilder sb;
- sb << defaultValueType;
- boostTypeBuilder->default_value(sb.str());
+ boostTypeBuilder->default_value(defaultValueType);
}
*boostType = boostTypeBuilder;
return Status::OK();
}
-
- /** Helper function to convert the values of our OptionType enum into the classes that
- * boost::program_option uses to pass around this information
- */
- Status typeToBoostType(std::auto_ptr<po::value_semantic>* boostType,
- OptionType type,
- const Value defaultValue = Value(),
- const Value implicitValue = Value(),
- bool getSwitchAsBool = false) {
- switch (type) {
- case StringVector:
- {
- *boostType = std::auto_ptr<po::value_semantic>(
- po::value< std::vector<std::string> >());
-
- if (!implicitValue.isEmpty()) {
- StringBuilder sb;
- sb << "Implicit value not supported for string vector";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (!defaultValue.isEmpty()) {
- StringBuilder sb;
- sb << "Default value not supported for string vector";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- return Status::OK();
- }
- case StringMap:
- {
- // Boost doesn't support maps, so we just register a vector parameter and
- // parse it as "key=value" strings
- *boostType = std::auto_ptr<po::value_semantic>(
- po::value< std::vector<std::string> >());
-
- if (!implicitValue.isEmpty()) {
- StringBuilder sb;
- sb << "Implicit value not supported for string map";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (!defaultValue.isEmpty()) {
- StringBuilder sb;
- sb << "Default value not supported for string map";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- return Status::OK();
- }
- case Switch:
- {
- // In boost, switches default to false which makes it impossible to tell if
- // a switch in a config file is not present or was explicitly set to false.
- //
- // Because of this, and because of the fact that we use the same set of
- // options for the legacy key=value config file, we need a way to control
- // whether we are telling boost that an option is a switch type or that an
- // option is a bool type.
- if (!getSwitchAsBool) {
- *boostType = std::auto_ptr<po::value_semantic>(po::bool_switch());
- return Status::OK();
- }
- else {
- // Switches should be true if they are present with no explicit value.
- *boostType = std::auto_ptr<po::typed_value<bool> >(po::value<bool>()
- ->implicit_value(true));
- return Status::OK();
- }
- }
- case Bool:
- {
- std::auto_ptr<po::typed_value<bool> > boostTypeBuilder(po::value<bool>());
-
- if (!implicitValue.isEmpty()) {
- bool implicitValueType;
- Status ret = implicitValue.get(&implicitValueType);
- if(!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting implicit value: " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- boostTypeBuilder->implicit_value(implicitValueType);
- }
-
- if (!defaultValue.isEmpty()) {
- bool defaultValueType;
- Status ret = defaultValue.get(&defaultValueType);
- if(!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting default value: " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- boostTypeBuilder->default_value(defaultValueType);
- }
-
- *boostType = boostTypeBuilder;
-
- return Status::OK();
- }
- case String:
- return typeToBoostStringType<std::string>(boostType, defaultValue,
- implicitValue);
- case Double:
- return typeToBoostStringType<double>(boostType, defaultValue, implicitValue);
- case Int:
- return typeToBoostStringType<int>(boostType, defaultValue, implicitValue);
- case Long:
- return typeToBoostStringType<long>(boostType, defaultValue, implicitValue);
- case UnsignedLongLong:
- return typeToBoostStringType<unsigned long long>(boostType, defaultValue,
- implicitValue);
- case Unsigned:
- return typeToBoostStringType<unsigned>(boostType, defaultValue, implicitValue);
- default:
- {
- StringBuilder sb;
- sb << "Unrecognized option type: " << type;
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
- }
- } // namespace
-
- Status OptionSection::getBoostOptions(po::options_description* boostOptions,
- bool visibleOnly,
- bool includeDefaults,
- OptionSources sources,
- bool getEmptySections) const {
-
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- // Only include this option if it matches the sources we specified and the option is
- // either visible or we are requesting hidden options
- if ((!visibleOnly || (oditerator->_isVisible)) &&
- (oditerator->_sources & sources)) {
- std::auto_ptr<po::value_semantic> boostType;
- Status ret = typeToBoostType(&boostType,
- oditerator->_type,
- includeDefaults ? oditerator->_default : Value(),
- oditerator->_implicit,
- !(sources & SourceCommandLine));
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error getting boost type for option \""
- << oditerator->_dottedName << "\": " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (oditerator->_singleName.empty()) {
- StringBuilder sb;
- sb << "Single name is empty for option \""
- << oditerator->_dottedName << "\", but trying to use it on the command line "
- << "or INI config file. Only options that are exclusive to the YAML config "
- << "file can have an empty single name";
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- boostOptions->add_options()(oditerator->_singleName.c_str(),
- boostType.release(),
- oditerator->_description.c_str());
- }
+ case String:
+ return typeToBoostStringType<std::string>(boostType, defaultValue, implicitValue);
+ case Double:
+ return typeToBoostStringType<double>(boostType, defaultValue, implicitValue);
+ case Int:
+ return typeToBoostStringType<int>(boostType, defaultValue, implicitValue);
+ case Long:
+ return typeToBoostStringType<long>(boostType, defaultValue, implicitValue);
+ case UnsignedLongLong:
+ return typeToBoostStringType<unsigned long long>(
+ boostType, defaultValue, implicitValue);
+ case Unsigned:
+ return typeToBoostStringType<unsigned>(boostType, defaultValue, implicitValue);
+ default: {
+ StringBuilder sb;
+ sb << "Unrecognized option type: " << type;
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- po::options_description subGroup = ositerator->_name.empty()
- ? po::options_description()
- : po::options_description(ositerator->_name.c_str());
-
- // Do not add empty sections to our option_description unless we specifically requested.
- int numOptions;
- Status ret = ositerator->countOptions(&numOptions, visibleOnly, sources);
+ }
+}
+} // namespace
+
+Status OptionSection::getBoostOptions(po::options_description* boostOptions,
+ bool visibleOnly,
+ bool includeDefaults,
+ OptionSources sources,
+ bool getEmptySections) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // Only include this option if it matches the sources we specified and the option is
+ // either visible or we are requesting hidden options
+ if ((!visibleOnly || (oditerator->_isVisible)) && (oditerator->_sources & sources)) {
+ std::auto_ptr<po::value_semantic> boostType;
+ Status ret = typeToBoostType(&boostType,
+ oditerator->_type,
+ includeDefaults ? oditerator->_default : Value(),
+ oditerator->_implicit,
+ !(sources & SourceCommandLine));
if (!ret.isOK()) {
- return ret;
- }
- if (numOptions == 0 && getEmptySections == false) {
- continue;
+ StringBuilder sb;
+ sb << "Error getting boost type for option \"" << oditerator->_dottedName
+ << "\": " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
- ret = ositerator->getBoostOptions(&subGroup, visibleOnly, includeDefaults,
- sources, getEmptySections);
- if (!ret.isOK()) {
- return ret;
+ if (oditerator->_singleName.empty()) {
+ StringBuilder sb;
+ sb << "Single name is empty for option \"" << oditerator->_dottedName
+ << "\", but trying to use it on the command line "
+ << "or INI config file. Only options that are exclusive to the YAML config "
+ << "file can have an empty single name";
+ return Status(ErrorCodes::InternalError, sb.str());
}
- boostOptions->add(subGroup);
- }
-
- return Status::OK();
- }
- /*
- * The way we specify positional options in our interface differs from the way boost does it, so
- * we have to convert them here.
- *
- * For example, to specify positionals such that you can run "./exec [pos1] [pos2] [pos2]":
- *
- * Our interface:
- *
- * options.addOptionChaining("pos2", "pos2", moe::StringVector, "Pos2")
- * .hidden() <- doesn't show up in help
- * .sources(moe::SourceCommandLine) <- only allowed on command line
- * .positional(2, <- start position
- * 3); <- end position
- * options.addOptionChaining("pos1", "pos1", moe::String, "Pos1")
- * .hidden() <- doesn't show up in help
- * .sources(moe::SourceCommandLine) <- only allowed on command line
- * .positional(1, <- start position
- * 1); <- end position
- * // Note that order doesn't matter
- *
- * Boost's interface:
- *
- * boostHiddenOptions->add_options()("pos1", po::value<std::string>(), "Pos1")
- * ("pos2", po::value<std::string>(), "Pos2")
- *
- * boostPositionalOptions->add("pos1", 1); <- count of option (number of times it appears)
- * boostPositionalOptions->add("pos2", 2); <- count of option (number of times it appears)
- * // Note that order does matter
- *
- * Because of this, we have to perform the conversion in this function. The tasks performed by
- * this function are:
- *
- * 1. Making sure the ranges are valid as a whole (no overlap or holes)
- * 2. Convert to the boost options and add them in the correct order
- */
- Status OptionSection::getBoostPositionalOptions(
- po::positional_options_description* boostPositionalOptions) const {
-
- std::list<OptionDescription> positionalOptions;
-
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- // Check if this is a positional option, and extract it if it is
- if (oditerator->_positionalStart != -1) {
- positionalOptions.push_back(*oditerator);
- }
+ boostOptions->add_options()(oditerator->_singleName.c_str(),
+ boostType.release(),
+ oditerator->_description.c_str());
}
+ }
- int nextPosition = 1;
- bool foundAtPosition = false;
- while (!positionalOptions.empty()) {
- foundAtPosition = false;
- std::list<OptionDescription>::iterator poditerator;
- for (poditerator = positionalOptions.begin(); poditerator != positionalOptions.end();) {
-
- if (poditerator->_positionalStart < nextPosition) {
- StringBuilder sb;
- sb << "Found option with overlapping positional range: "
- << " Expected next option at position: " << nextPosition
- << ", but \"" << poditerator->_dottedName << "\" starts at position: "
- << poditerator->_positionalStart;
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- if (poditerator->_positionalStart == nextPosition) {
- foundAtPosition = true;
-
- int count;
- if (poditerator->_positionalEnd == -1) {
- count = -1;
- if (positionalOptions.size() != 1) {
- StringBuilder sb;
- sb << "Found positional option with infinite count, but still have "
- << "more positional options registered";
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
- else {
- count = (poditerator->_positionalEnd + 1) - poditerator->_positionalStart;
- }
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ po::options_description subGroup = ositerator->_name.empty()
+ ? po::options_description()
+ : po::options_description(ositerator->_name.c_str());
- boostPositionalOptions->add(poditerator->_dottedName.c_str(), count);
- nextPosition += count;
- std::list<OptionDescription>::iterator old_poditerator = poditerator;
- poditerator++;
- positionalOptions.erase(old_poditerator);
- }
- else {
- poditerator++;
- }
- }
- if (!foundAtPosition) {
- StringBuilder sb;
- sb << "Did not find option at position: " << nextPosition;
- return Status(ErrorCodes::InternalError, sb.str());
- }
+ // Do not add empty sections to our option_description unless we specifically requested.
+ int numOptions;
+ Status ret = ositerator->countOptions(&numOptions, visibleOnly, sources);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ if (numOptions == 0 && getEmptySections == false) {
+ continue;
}
- // XXX: Right now only the top level section can have positional options
-
- return Status::OK();
+ ret = ositerator->getBoostOptions(
+ &subGroup, visibleOnly, includeDefaults, sources, getEmptySections);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ boostOptions->add(subGroup);
}
- // Get options for iterating
- // TODO: should I make this an iterator?
+ return Status::OK();
+}
- Status OptionSection::getAllOptions(std::vector<OptionDescription>* options) const {
-
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+/*
+ * The way we specify positional options in our interface differs from the way boost does it, so
+ * we have to convert them here.
+ *
+ * For example, to specify positionals such that you can run "./exec [pos1] [pos2] [pos2]":
+ *
+ * Our interface:
+ *
+ * options.addOptionChaining("pos2", "pos2", moe::StringVector, "Pos2")
+ * .hidden() <- doesn't show up in help
+ * .sources(moe::SourceCommandLine) <- only allowed on command line
+ * .positional(2, <- start position
+ * 3); <- end position
+ * options.addOptionChaining("pos1", "pos1", moe::String, "Pos1")
+ * .hidden() <- doesn't show up in help
+ * .sources(moe::SourceCommandLine) <- only allowed on command line
+ * .positional(1, <- start position
+ * 1); <- end position
+ * // Note that order doesn't matter
+ *
+ * Boost's interface:
+ *
+ * boostHiddenOptions->add_options()("pos1", po::value<std::string>(), "Pos1")
+ * ("pos2", po::value<std::string>(), "Pos2")
+ *
+ * boostPositionalOptions->add("pos1", 1); <- count of option (number of times it appears)
+ * boostPositionalOptions->add("pos2", 2); <- count of option (number of times it appears)
+ * // Note that order does matter
+ *
+ * Because of this, we have to perform the conversion in this function. The tasks performed by
+ * this function are:
+ *
+ * 1. Making sure the ranges are valid as a whole (no overlap or holes)
+ * 2. Convert to the boost options and add them in the correct order
+ */
+Status OptionSection::getBoostPositionalOptions(
+ po::positional_options_description* boostPositionalOptions) const {
+ std::list<OptionDescription> positionalOptions;
+
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // Check if this is a positional option, and extract it if it is
+ if (oditerator->_positionalStart != -1) {
+ positionalOptions.push_back(*oditerator);
+ }
+ }
- // We need to check here that we didn't register an option with an empty single name
- // that is allowed on the command line or in an old style config, since we don't have
- // this information available all at once when the option is registered
- if (oditerator->_singleName.empty() &&
- oditerator->_sources & SourceAllLegacy) {
+ int nextPosition = 1;
+ bool foundAtPosition = false;
+ while (!positionalOptions.empty()) {
+ foundAtPosition = false;
+ std::list<OptionDescription>::iterator poditerator;
+ for (poditerator = positionalOptions.begin(); poditerator != positionalOptions.end();) {
+ if (poditerator->_positionalStart < nextPosition) {
StringBuilder sb;
- sb << "Found option allowed on the command line with an empty singleName: "
- << oditerator->_dottedName;
+ sb << "Found option with overlapping positional range: "
+ << " Expected next option at position: " << nextPosition << ", but \""
+ << poditerator->_dottedName
+ << "\" starts at position: " << poditerator->_positionalStart;
return Status(ErrorCodes::InternalError, sb.str());
}
- options->push_back(*oditerator);
- }
-
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- ositerator->getAllOptions(options);
- }
-
- return Status::OK();
- }
+ if (poditerator->_positionalStart == nextPosition) {
+ foundAtPosition = true;
- Status OptionSection::getDefaults(std::map<Key, Value>* values) const {
+ int count;
+ if (poditerator->_positionalEnd == -1) {
+ count = -1;
+ if (positionalOptions.size() != 1) {
+ StringBuilder sb;
+ sb << "Found positional option with infinite count, but still have "
+ << "more positional options registered";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ } else {
+ count = (poditerator->_positionalEnd + 1) - poditerator->_positionalStart;
+ }
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- if (!oditerator->_default.isEmpty()) {
- (*values)[oditerator->_dottedName] = oditerator->_default;
+ boostPositionalOptions->add(poditerator->_dottedName.c_str(), count);
+ nextPosition += count;
+ std::list<OptionDescription>::iterator old_poditerator = poditerator;
+ poditerator++;
+ positionalOptions.erase(old_poditerator);
+ } else {
+ poditerator++;
}
}
-
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- ositerator->getDefaults(values);
+ if (!foundAtPosition) {
+ StringBuilder sb;
+ sb << "Did not find option at position: " << nextPosition;
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- return Status::OK();
}
- Status OptionSection::countOptions(int* numOptions,
- bool visibleOnly,
- OptionSources sources) const {
+ // XXX: Right now only the top level section can have positional options
- *numOptions = 0;
+ return Status::OK();
+}
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- // Only count this option if it matches the sources we specified and the option is
- // either visible or we are requesting hidden options
- if ((!visibleOnly || (oditerator->_isVisible)) &&
- (oditerator->_sources & sources)) {
- (*numOptions)++;
- }
- }
+// Get options for iterating
+// TODO: should I make this an iterator?
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- int numSubOptions = 0;
- ositerator->countOptions(&numSubOptions, visibleOnly, sources);
- *numOptions += numSubOptions;
+Status OptionSection::getAllOptions(std::vector<OptionDescription>* options) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // We need to check here that we didn't register an option with an empty single name
+ // that is allowed on the command line or in an old style config, since we don't have
+ // this information available all at once when the option is registered
+ if (oditerator->_singleName.empty() && oditerator->_sources & SourceAllLegacy) {
+ StringBuilder sb;
+ sb << "Found option allowed on the command line with an empty singleName: "
+ << oditerator->_dottedName;
+ return Status(ErrorCodes::InternalError, sb.str());
}
- return Status::OK();
+ options->push_back(*oditerator);
}
- Status OptionSection::getConstraints(
- std::vector<boost::shared_ptr<Constraint > >* constraints) const {
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getAllOptions(options);
+ }
- 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);
- }
- }
+ return Status::OK();
+}
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- ositerator->getConstraints(constraints);
+Status OptionSection::getDefaults(std::map<Key, Value>* values) const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ if (!oditerator->_default.isEmpty()) {
+ (*values)[oditerator->_dottedName] = oditerator->_default;
}
+ }
- return Status::OK();
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getDefaults(values);
}
- std::string OptionSection::positionalHelpString(const std::string& execName) const {
+ return Status::OK();
+}
- po::positional_options_description boostPositionalOptions;
- Status ret = getBoostPositionalOptions(&boostPositionalOptions);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error constructing help string: " << ret.toString();
- return sb.str();
+Status OptionSection::countOptions(int* numOptions, bool visibleOnly, OptionSources sources) const {
+ *numOptions = 0;
+
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ // Only count this option if it matches the sources we specified and the option is
+ // either visible or we are requesting hidden options
+ if ((!visibleOnly || (oditerator->_isVisible)) && (oditerator->_sources & sources)) {
+ (*numOptions)++;
}
+ }
- StringBuilder posHelpStringBuilder;
- posHelpStringBuilder << execName;
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ int numSubOptions = 0;
+ ositerator->countOptions(&numSubOptions, visibleOnly, sources);
+ *numOptions += numSubOptions;
+ }
- // If we can have unlimited positional options, this returns
- // std::numeric_limits<unsigned>::max(). Check here for that case and record what name to
- // look for.
- unsigned int numPositional = boostPositionalOptions.max_total_count();
- std::string trailingPositionName;
- if (numPositional == std::numeric_limits<unsigned>::max()) {
- trailingPositionName = boostPositionalOptions.name_for_position(numPositional - 1);
+ 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);
}
+ }
- unsigned int position;
- std::string positionName;
- for (position = 0; position < numPositional; position++) {
- positionName = boostPositionalOptions.name_for_position(position);
- if (!trailingPositionName.empty() && trailingPositionName == positionName) {
- // If we have a trailing position, we break when we see it the first time.
- posHelpStringBuilder << " [" << trailingPositionName << " ... ]";
- break;
- }
- posHelpStringBuilder << " [" << positionName << "]";
- }
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getConstraints(constraints);
+ }
- return posHelpStringBuilder.str();
+ return Status::OK();
+}
+
+std::string OptionSection::positionalHelpString(const std::string& execName) const {
+ po::positional_options_description boostPositionalOptions;
+ Status ret = getBoostPositionalOptions(&boostPositionalOptions);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error constructing help string: " << ret.toString();
+ return sb.str();
}
- std::string OptionSection::helpString() const {
+ StringBuilder posHelpStringBuilder;
+ posHelpStringBuilder << execName;
- po::options_description boostOptions = _name.empty()
- ? po::options_description()
- : po::options_description(_name.c_str());
- Status ret = getBoostOptions(&boostOptions,
- true, /* visibleOnly */
- true, /* includeDefaults */
- SourceAllLegacy,
- false); /* getEmptySections */
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error constructing help string: " << ret.toString();
- return sb.str();
- }
+ // If we can have unlimited positional options, this returns
+ // std::numeric_limits<unsigned>::max(). Check here for that case and record what name to
+ // look for.
+ unsigned int numPositional = boostPositionalOptions.max_total_count();
+ std::string trailingPositionName;
+ if (numPositional == std::numeric_limits<unsigned>::max()) {
+ trailingPositionName = boostPositionalOptions.name_for_position(numPositional - 1);
+ }
- // Can't use a StringBuilder here because boost::program_options only has functions that
- // output to std::ostream
- std::ostringstream os;
- os << boostOptions;
- return os.str();
+ unsigned int position;
+ std::string positionName;
+ for (position = 0; position < numPositional; position++) {
+ positionName = boostPositionalOptions.name_for_position(position);
+ if (!trailingPositionName.empty() && trailingPositionName == positionName) {
+ // If we have a trailing position, we break when we see it the first time.
+ posHelpStringBuilder << " [" << trailingPositionName << " ... ]";
+ break;
+ }
+ posHelpStringBuilder << " [" << positionName << "]";
}
- /* Debugging */
- void OptionSection::dump() const {
+ return posHelpStringBuilder.str();
+}
+
+std::string OptionSection::helpString() const {
+ po::options_description boostOptions =
+ _name.empty() ? po::options_description() : po::options_description(_name.c_str());
+ Status ret = getBoostOptions(&boostOptions,
+ true, /* visibleOnly */
+ true, /* includeDefaults */
+ SourceAllLegacy,
+ false); /* getEmptySections */
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error constructing help string: " << ret.toString();
+ return sb.str();
+ }
- std::list<OptionDescription>::const_iterator oditerator;
- for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
- std::cout << " _dottedName: " << oditerator->_dottedName
- << " _singleName: " << oditerator->_singleName
- << " _type: " << oditerator->_type
- << " _description: " << oditerator->_description
- << " _isVisible: " << oditerator->_isVisible << std::endl;
- }
+ // Can't use a StringBuilder here because boost::program_options only has functions that
+ // output to std::ostream
+ std::ostringstream os;
+ os << boostOptions;
+ return os.str();
+}
+
+/* Debugging */
+void OptionSection::dump() const {
+ std::list<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ std::cout << " _dottedName: " << oditerator->_dottedName
+ << " _singleName: " << oditerator->_singleName << " _type: " << oditerator->_type
+ << " _description: " << oditerator->_description
+ << " _isVisible: " << oditerator->_isVisible << std::endl;
+ }
- std::list<OptionSection>::const_iterator ositerator;
- for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
- std::cout << "Section Name: " << ositerator->_name << std::endl;
- ositerator->dump();
- }
+ std::list<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ std::cout << "Section Name: " << ositerator->_name << std::endl;
+ ositerator->dump();
}
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_section.h b/src/mongo/util/options_parser/option_section.h
index 572e2b60e0d..1377b4e9a98 100644
--- a/src/mongo/util/options_parser/option_section.h
+++ b/src/mongo/util/options_parser/option_section.h
@@ -37,137 +37,137 @@
namespace mongo {
namespace optionenvironment {
- namespace po = boost::program_options;
+namespace po = boost::program_options;
+
+/**
+ * A container for OptionDescription instances as well as other OptionSection instances.
+ * Provides a description of all options that are supported to be passed in to an
+ * OptionsParser. Has utility functions to support the various formats needed by the parsing
+ * process
+ *
+ * The sections and section names only matter in the help string. For sections in a JSON
+ * config, look at the dots in the dottedName of the relevant OptionDescription
+ *
+ * Usage:
+ *
+ * namespace moe = mongo::optionenvironment;
+ *
+ * moe::OptionsParser parser;
+ * moe::Environment environment;
+ * moe::OptionSection options;
+ * moe::OptionSection subSection("Section Name");
+ *
+ * // Register our allowed option flags with our OptionSection
+ * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
+ *
+ * // Register our positional options with our OptionSection
+ * options.addOptionChaining("command", "command", moe::String, "Command").positional(1, 1);
+ *
+ * // Add a subsection
+ * subSection.addOptionChaining("port", "port", moe::Int, "Port");
+ * options.addSection(subSection);
+ *
+ * // Run the parser
+ * Status ret = parser.run(options, argc, argv, envp, &environment);
+ * if (!ret.isOK()) {
+ * cerr << options.helpString() << std::endl;
+ * exit(EXIT_FAILURE);
+ * }
+ */
+
+class OptionSection {
+public:
+ OptionSection(const std::string& name) : _name(name) {}
+ OptionSection() {}
+
+ // Construction interface
/**
- * A container for OptionDescription instances as well as other OptionSection instances.
- * Provides a description of all options that are supported to be passed in to an
- * OptionsParser. Has utility functions to support the various formats needed by the parsing
- * process
- *
- * The sections and section names only matter in the help string. For sections in a JSON
- * config, look at the dots in the dottedName of the relevant OptionDescription
+ * Add a sub section to this section. Used mainly to keep track of section headers for when
+ * we need generate the help std::string for the command line
+ */
+ Status addSection(const OptionSection& subSection);
+
+ /**
+ * Add an option to this section, and returns a reference to an OptionDescription to allow
+ * for chaining.
*
- * Usage:
+ * Examples:
*
- * namespace moe = mongo::optionenvironment;
+ * options.addOptionChaining("option", "option", moe::String, "Chaining Registration")
+ * .hidden().setDefault(moe::Value("default"))
+ * .setImplicit(moe::Value("implicit"));
*
- * moe::OptionsParser parser;
- * moe::Environment environment;
- * moe::OptionSection options;
- * moe::OptionSection subSection("Section Name");
+ * This creates a hidden option that has default and implicit values.
*
- * // Register our allowed option flags with our OptionSection
- * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
+ * options.addOptionChaining("name", "name", moe::String, "Composing Option")
+ * .composing().sources(SourceAllConfig);
*
- * // Register our positional options with our OptionSection
- * options.addOptionChaining("command", "command", moe::String, "Command").positional(1, 1);
+ * This creates an option that is composing and can be specified only in config files.
*
- * // Add a subsection
- * subSection.addOptionChaining("port", "port", moe::Int, "Port");
- * options.addSection(subSection);
+ * See the OptionDescription class for details on the supported attributes.
*
- * // Run the parser
- * Status ret = parser.run(options, argc, argv, envp, &environment);
- * if (!ret.isOK()) {
- * cerr << options.helpString() << std::endl;
- * exit(EXIT_FAILURE);
- * }
+ * throws DBException on errors, such as attempting to register an option with the same name
+ * as another option. These represent programming errors that should not happen during
+ * normal operation.
+ */
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description);
+
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::string& deprecatedDottedName);
+
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description,
+ const std::vector<std::string>& deprecatedDottedNames);
+
+ // These functions are used by the OptionsParser to make calls into boost::program_options
+ Status getBoostOptions(po::options_description* boostOptions,
+ bool visibleOnly = false,
+ bool includeDefaults = false,
+ OptionSources = SourceAll,
+ bool getEmptySections = true) const;
+ Status getBoostPositionalOptions(
+ po::positional_options_description* boostPositionalOptions) const;
+
+ // This is needed so that the parser can iterate over all registered options to get the
+ // correct names when populating the Environment, as well as check that a parameter that was
+ // found has been registered and has the correct type
+ Status getAllOptions(std::vector<OptionDescription>* options) const;
+
+ // Count the number of options in this section and all subsections
+ Status countOptions(int* numOptions, bool visibleOnly, OptionSources sources) const;
+
+ /**
+ * Populates the given map with all the default values for any options in this option
+ * section and all sub sections.
*/
+ 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;
+
+ // Debugging
+ void dump() const;
+
+private:
+ std::string _name;
+ std::list<OptionSection> _subSections;
+ std::list<OptionDescription> _options;
+};
- class OptionSection {
- public:
- OptionSection(const std::string& name) : _name(name) { }
- OptionSection() { }
-
- // Construction interface
-
- /**
- * Add a sub section to this section. Used mainly to keep track of section headers for when
- * we need generate the help std::string for the command line
- */
- Status addSection(const OptionSection& subSection);
-
- /**
- * Add an option to this section, and returns a reference to an OptionDescription to allow
- * for chaining.
- *
- * Examples:
- *
- * options.addOptionChaining("option", "option", moe::String, "Chaining Registration")
- * .hidden().setDefault(moe::Value("default"))
- * .setImplicit(moe::Value("implicit"));
- *
- * This creates a hidden option that has default and implicit values.
- *
- * options.addOptionChaining("name", "name", moe::String, "Composing Option")
- * .composing().sources(SourceAllConfig);
- *
- * This creates an option that is composing and can be specified only in config files.
- *
- * See the OptionDescription class for details on the supported attributes.
- *
- * throws DBException on errors, such as attempting to register an option with the same name
- * as another option. These represent programming errors that should not happen during
- * normal operation.
- */
- OptionDescription& addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description);
-
- OptionDescription& addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::string& deprecatedDottedName);
-
- OptionDescription& addOptionChaining(const std::string& dottedName,
- const std::string& singleName,
- const OptionType type,
- const std::string& description,
- const std::vector<std::string>& deprecatedDottedNames);
-
- // These functions are used by the OptionsParser to make calls into boost::program_options
- Status getBoostOptions(po::options_description* boostOptions,
- bool visibleOnly = false,
- bool includeDefaults = false,
- OptionSources = SourceAll,
- bool getEmptySections = true) const;
- Status getBoostPositionalOptions(
- po::positional_options_description* boostPositionalOptions) const;
-
- // This is needed so that the parser can iterate over all registered options to get the
- // correct names when populating the Environment, as well as check that a parameter that was
- // found has been registered and has the correct type
- Status getAllOptions(std::vector<OptionDescription>* options) const;
-
- // Count the number of options in this section and all subsections
- Status countOptions(int* numOptions, bool visibleOnly, OptionSources sources) const;
-
- /**
- * Populates the given map with all the default values for any options in this option
- * section and all sub sections.
- */
- 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;
-
- // Debugging
- void dump() const;
-
- private:
- std::string _name;
- std::list<OptionSection> _subSections;
- std::list<OptionDescription> _options;
- };
-
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser.cpp b/src/mongo/util/options_parser/options_parser.cpp
index e4d4817f546..10ad484a3b3 100644
--- a/src/mongo/util/options_parser/options_parser.cpp
+++ b/src/mongo/util/options_parser/options_parser.cpp
@@ -52,997 +52,954 @@
namespace mongo {
namespace optionenvironment {
- using namespace std;
- using boost::shared_ptr;
-
- namespace po = boost::program_options;
-
- namespace {
-
- // The following section contains utility functions that convert between the various objects
- // we need to deal with while parsing command line options.
- //
- // These conversions are different depending on the data source because our current
- // implementation uses boost::program_options for the command line and INI files and the
- // yaml-cpp YAML parser for YAML config files. Our destination storage in both cases is an
- // Environment which stores Value objects.
- //
- // 1. YAML Config Files
- // The YAML parser parses a YAML config file into a YAML::Node. Therefore, we need:
- // a. A function to convert a YAML::Node to a Value (YAMLNodeToValue)
- // b. A function to iterate a YAML::Node, convert the leaf Nodes to Values, and add
- // them to our Environment (addYAMLNodesToEnvironment)
- //
- // 2. INI Config Files and command line
- // The boost::program_options parsers store their output in a
- // boost::program_options::variables_map. Therefore, we need:
- // a. A function to convert a boost::any to a Value (boostAnyToValue)
- // b. A function to iterate a variables_map, convert the boost::any elements to
- // Values, and add them to our Environment (addBoostVariablesToEnvironment)
-
- // Attempts to convert a string to a value of the given type.
- Status stringToValue(const std::string& stringVal,
- const OptionType& type,
- const Key& key, Value* value) {
-
- Status ret = Status::OK();
- switch (type) {
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
- case Switch:
- if (stringVal == "true") {
- *value = Value(true);
- return Status::OK();
- }
- else if (stringVal == "false") {
- *value = Value(false);
- return Status::OK();
- }
- else {
- StringBuilder sb;
- sb << "Expected boolean switch but found string: " << stringVal
- << " for option: " << key;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- case Bool:
- if (stringVal == "true") {
- *value = Value(true);
- return Status::OK();
- }
- else if (stringVal == "false") {
- *value = Value(false);
- return Status::OK();
- }
- else {
- StringBuilder sb;
- sb << "Expected boolean but found string: " << stringVal
- << " for option: " << key;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- case Double:
- ret = parseNumberFromString(stringVal, &doubleVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as double in: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(doubleVal);
- return Status::OK();
- case Int:
- ret = parseNumberFromString(stringVal, &intVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as int: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(intVal);
- return Status::OK();
- case Long:
- ret = parseNumberFromString(stringVal, &longVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as long: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(longVal);
- return Status::OK();
- case String:
- *value = Value(stringVal);
- return Status::OK();
- case UnsignedLongLong:
- ret = parseNumberFromString(stringVal, &unsignedLongLongVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as unsigned long long: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(unsignedLongLongVal);
- return Status::OK();
- case Unsigned:
- ret = parseNumberFromString(stringVal, &unsignedVal);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error parsing option \"" << key
- << "\" as unsigned int: " << ret.reason();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- *value = Value(unsignedVal);
- return Status::OK();
- default: /* XXX: should not get here */
- return Status(ErrorCodes::InternalError, "Unrecognized option type");
- }
- }
+using namespace std;
+using boost::shared_ptr;
- // Convert a boost::any to a Value. See comments at the beginning of this section.
- Status boostAnyToValue(const boost::any& anyValue,
- const OptionType& type,
- const Key& key, Value* value) {
- try {
- if (anyValue.type() == typeid(StringVector_t)) {
- *value = Value(boost::any_cast<StringVector_t>(anyValue));
- }
- else if (anyValue.type() == typeid(bool)) {
- *value = Value(boost::any_cast<bool>(anyValue));
- }
- else if (anyValue.type() == typeid(std::string)) {
- return stringToValue(boost::any_cast<std::string>(anyValue), type, key, value);
- }
- // We should not be telling boost about numerical type information. Instead, for
- // any numerical type we tell boost to read a string value and parse it manually,
- // since boost's parsing is not consistent with ours. See SERVER-14110.
- else if (anyValue.type() == typeid(double) || anyValue.type() == typeid(int) ||
- anyValue.type() == typeid(long) || anyValue.type() == typeid(unsigned) ||
- anyValue.type() == typeid(unsigned long long)) {
- StringBuilder sb;
- sb << "Found int type: " << anyValue.type().name() <<
- " in any to Value conversion, which is not supported";
- return Status(ErrorCodes::InternalError, sb.str());
- }
- else {
- StringBuilder sb;
- sb << "Unrecognized type: " << anyValue.type().name() <<
- " in any to Value conversion";
- return Status(ErrorCodes::InternalError, sb.str());
- }
+namespace po = boost::program_options;
+
+namespace {
+
+// The following section contains utility functions that convert between the various objects
+// we need to deal with while parsing command line options.
+//
+// These conversions are different depending on the data source because our current
+// implementation uses boost::program_options for the command line and INI files and the
+// yaml-cpp YAML parser for YAML config files. Our destination storage in both cases is an
+// Environment which stores Value objects.
+//
+// 1. YAML Config Files
+// The YAML parser parses a YAML config file into a YAML::Node. Therefore, we need:
+// a. A function to convert a YAML::Node to a Value (YAMLNodeToValue)
+// b. A function to iterate a YAML::Node, convert the leaf Nodes to Values, and add
+// them to our Environment (addYAMLNodesToEnvironment)
+//
+// 2. INI Config Files and command line
+// The boost::program_options parsers store their output in a
+// boost::program_options::variables_map. Therefore, we need:
+// a. A function to convert a boost::any to a Value (boostAnyToValue)
+// b. A function to iterate a variables_map, convert the boost::any elements to
+// Values, and add them to our Environment (addBoostVariablesToEnvironment)
+
+// Attempts to convert a string to a value of the given type.
+Status stringToValue(const std::string& stringVal,
+ const OptionType& type,
+ const Key& key,
+ Value* value) {
+ Status ret = Status::OK();
+ switch (type) {
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+ case Switch:
+ if (stringVal == "true") {
+ *value = Value(true);
+ return Status::OK();
+ } else if (stringVal == "false") {
+ *value = Value(false);
+ return Status::OK();
+ } else {
+ StringBuilder sb;
+ sb << "Expected boolean switch but found string: " << stringVal
+ << " for option: " << key;
+ return Status(ErrorCodes::BadValue, sb.str());
}
- catch(const boost::bad_any_cast& e) {
+ case Bool:
+ if (stringVal == "true") {
+ *value = Value(true);
+ return Status::OK();
+ } else if (stringVal == "false") {
+ *value = Value(false);
+ return Status::OK();
+ } else {
StringBuilder sb;
- // We already checked the type, so this is just a sanity check
- sb << "boost::any_cast threw exception: " << e.what();
- return Status(ErrorCodes::InternalError, sb.str());
+ sb << "Expected boolean but found string: " << stringVal << " for option: " << key;
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ case Double:
+ ret = parseNumberFromString(stringVal, &doubleVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as double in: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(doubleVal);
+ return Status::OK();
+ case Int:
+ ret = parseNumberFromString(stringVal, &intVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as int: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(intVal);
+ return Status::OK();
+ case Long:
+ ret = parseNumberFromString(stringVal, &longVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as long: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(longVal);
return Status::OK();
+ case String:
+ *value = Value(stringVal);
+ return Status::OK();
+ case UnsignedLongLong:
+ ret = parseNumberFromString(stringVal, &unsignedLongLongVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key
+ << "\" as unsigned long long: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(unsignedLongLongVal);
+ return Status::OK();
+ case Unsigned:
+ ret = parseNumberFromString(stringVal, &unsignedVal);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error parsing option \"" << key << "\" as unsigned int: " << ret.reason();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ *value = Value(unsignedVal);
+ return Status::OK();
+ default: /* XXX: should not get here */
+ return Status(ErrorCodes::InternalError, "Unrecognized option type");
+ }
+}
+
+// Convert a boost::any to a Value. See comments at the beginning of this section.
+Status boostAnyToValue(const boost::any& anyValue,
+ const OptionType& type,
+ const Key& key,
+ Value* value) {
+ try {
+ if (anyValue.type() == typeid(StringVector_t)) {
+ *value = Value(boost::any_cast<StringVector_t>(anyValue));
+ } else if (anyValue.type() == typeid(bool)) {
+ *value = Value(boost::any_cast<bool>(anyValue));
+ } else if (anyValue.type() == typeid(std::string)) {
+ return stringToValue(boost::any_cast<std::string>(anyValue), type, key, value);
+ }
+ // We should not be telling boost about numerical type information. Instead, for
+ // any numerical type we tell boost to read a string value and parse it manually,
+ // since boost's parsing is not consistent with ours. See SERVER-14110.
+ else if (anyValue.type() == typeid(double) || anyValue.type() == typeid(int) ||
+ anyValue.type() == typeid(long) || anyValue.type() == typeid(unsigned) ||
+ anyValue.type() == typeid(unsigned long long)) {
+ StringBuilder sb;
+ sb << "Found int type: " << anyValue.type().name()
+ << " in any to Value conversion, which is not supported";
+ return Status(ErrorCodes::InternalError, sb.str());
+ } else {
+ StringBuilder sb;
+ sb << "Unrecognized type: " << anyValue.type().name() << " in any to Value conversion";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ } catch (const boost::bad_any_cast& e) {
+ StringBuilder sb;
+ // We already checked the type, so this is just a sanity check
+ sb << "boost::any_cast threw exception: " << e.what();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ return Status::OK();
+}
+
+// Returns true if the option for the given key is a StringMap option, and false otherwise
+bool OptionIsStringMap(const std::vector<OptionDescription>& options_vector, const Key& key) {
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (key == iterator->_dottedName && (iterator->_sources & SourceYAMLConfig)) {
+ if (iterator->_type == StringMap) {
+ return true;
+ }
}
+ }
- // Returns true if the option for the given key is a StringMap option, and false otherwise
- bool OptionIsStringMap(const std::vector<OptionDescription>& options_vector,
- const Key& key) {
+ return false;
+}
+
+// Convert a YAML::Node to a Value. See comments at the beginning of this section.
+// 'canonicalKey' holds the dotted name that should be used in the result Environment.
+// This ensures that both canonical and deprecated dotted names in the configuration
+// are mapped to the canonical name.
+Status YAMLNodeToValue(const YAML::Node& YAMLNode,
+ const std::vector<OptionDescription>& options_vector,
+ const Key& key,
+ Key* canonicalKey,
+ Value* value) {
+ bool isRegistered = false;
+
+ // The logic below should ensure that we don't use this uninitialized, but we need to
+ // initialize it here to avoid a compiler warning. Initializing it to a "Bool" since
+ // that's the most restricted type we have and is most likely to result in an early
+ // failure if we have a logic error.
+ OptionType type = Bool;
+
+ // The config file had a ":" as the first non whitespace character on a line
+ if (key.empty()) {
+ StringBuilder sb;
+ sb << "Found empty key in YAML config file";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
- if (key == iterator->_dottedName && (iterator->_sources & SourceYAMLConfig)) {
- if (iterator->_type == StringMap) {
- return true;
- }
- }
+ // Get expected type
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (!(iterator->_sources & SourceYAMLConfig)) {
+ continue;
+ }
+
+ bool isDeprecated = std::count(iterator->_deprecatedDottedNames.begin(),
+ iterator->_deprecatedDottedNames.end(),
+ key) > 0;
+ if (key == iterator->_dottedName || isDeprecated) {
+ isRegistered = true;
+ type = iterator->_type;
+ *canonicalKey = iterator->_dottedName;
+ if (isDeprecated) {
+ warning() << "Option: " << key << " is deprecated. Please use "
+ << iterator->_dottedName << " instead.";
}
-
- return false;
}
+ }
+
+ if (!isRegistered) {
+ StringBuilder sb;
+ sb << "Unrecognized option: " << key;
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // Convert a YAML::Node to a Value. See comments at the beginning of this section.
- // 'canonicalKey' holds the dotted name that should be used in the result Environment.
- // This ensures that both canonical and deprecated dotted names in the configuration
- // are mapped to the canonical name.
- Status YAMLNodeToValue(const YAML::Node& YAMLNode,
- const std::vector<OptionDescription>& options_vector,
- const Key& key,
- Key* canonicalKey,
- Value* value) {
-
- bool isRegistered = false;
-
- // The logic below should ensure that we don't use this uninitialized, but we need to
- // initialize it here to avoid a compiler warning. Initializing it to a "Bool" since
- // that's the most restricted type we have and is most likely to result in an early
- // failure if we have a logic error.
- OptionType type = Bool;
-
- // The config file had a ":" as the first non whitespace character on a line
- if (key.empty()) {
+ // Handle multi keys
+ if (type == StringVector) {
+ if (!YAMLNode.IsSequence()) {
+ StringBuilder sb;
+ sb << "Option: " << key
+ << " is of type StringVector, but value in YAML config is not a list type";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ StringVector_t stringVector;
+ for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
+ if (it->IsSequence()) {
StringBuilder sb;
- sb << "Found empty key in YAML config file";
+ sb << "Option: " << key << " has nested lists, which is not allowed";
return Status(ErrorCodes::BadValue, sb.str());
}
+ stringVector.push_back(it->Scalar());
+ }
+ *value = Value(stringVector);
+ return Status::OK();
+ }
- // Get expected type
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
- if (!(iterator->_sources & SourceYAMLConfig)) {
- continue;
- }
-
- bool isDeprecated = std::count(iterator->_deprecatedDottedNames.begin(),
- iterator->_deprecatedDottedNames.end(), key) > 0;
- if (key == iterator->_dottedName || isDeprecated) {
- isRegistered = true;
- type = iterator->_type;
- *canonicalKey = iterator->_dottedName;
- if (isDeprecated) {
- warning() << "Option: " << key << " is deprecated. Please use "
- << iterator->_dottedName << " instead.";
- }
- }
+ // Handle a sub map as a value
+ if (type == StringMap) {
+ if (!YAMLNode.IsMap()) {
+ StringBuilder sb;
+ sb << "Option: " << key
+ << " is of type StringMap, but value in YAML config is not a map type";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ StringMap_t stringMap;
+ for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
+ if (it->second.IsSequence() || it->second.IsMap()) {
+ StringBuilder sb;
+ sb << "Option: " << key
+ << " has a map with non scalar values, which is not allowed";
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ if (stringMap.count(it->first.Scalar()) > 0) {
+ StringBuilder sb;
+ sb << "String Map Option: " << key
+ << " has duplicate keys in YAML Config: " << it->first.Scalar();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
+ stringMap[it->first.Scalar()] = it->second.Scalar();
+ }
+ *value = Value(stringMap);
+ return Status::OK();
+ }
- if (!isRegistered) {
+ // Our YAML parser reads everything as a string, so we need to parse it ourselves.
+ std::string stringVal = YAMLNode.Scalar();
+ return stringToValue(stringVal, type, key, value);
+}
+
+// Add all the values in the given variables_map to our environment. See comments at the
+// beginning of this section.
+Status addBoostVariablesToEnvironment(const po::variables_map& vm,
+ const OptionSection& options,
+ Environment* environment) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ // Trim off the short option from our name so we can look it up correctly in our map
+ std::string long_name;
+ std::string::size_type commaOffset = iterator->_singleName.find(',');
+ if (commaOffset != string::npos) {
+ if (commaOffset != iterator->_singleName.size() - 2) {
StringBuilder sb;
- sb << "Unrecognized option: " << key;
+ sb << "Unexpected comma in option name: \"" << iterator->_singleName << "\""
+ << ": option name must be in the format \"option,o\" or \"option\", "
+ << "where \"option\" is the long name and \"o\" is the optional one "
+ << "character short alias";
return Status(ErrorCodes::BadValue, sb.str());
}
+ long_name = iterator->_singleName.substr(0, commaOffset);
+ } else {
+ long_name = iterator->_singleName;
+ }
- // Handle multi keys
- if (type == StringVector) {
- if (!YAMLNode.IsSequence()) {
- StringBuilder sb;
- sb << "Option: " << key
- << " is of type StringVector, but value in YAML config is not a list type";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- StringVector_t stringVector;
- for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
- if (it->IsSequence()) {
- StringBuilder sb;
- sb << "Option: " << key
- << " has nested lists, which is not allowed";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- stringVector.push_back(it->Scalar());
- }
- *value = Value(stringVector);
- return Status::OK();
+ if (vm.count(long_name)) {
+ Value optionValue;
+ Status ret =
+ boostAnyToValue(vm[long_name].value(), iterator->_type, long_name, &optionValue);
+ if (!ret.isOK()) {
+ return ret;
}
- // Handle a sub map as a value
- if (type == StringMap) {
- if (!YAMLNode.IsMap()) {
- StringBuilder sb;
- sb << "Option: " << key
- << " is of type StringMap, but value in YAML config is not a map type";
- return Status(ErrorCodes::BadValue, sb.str());
+ // If this is really a StringMap, try to split on "key=value" for each element
+ // in our StringVector
+ if (iterator->_type == StringMap) {
+ StringVector_t keyValueVector;
+ ret = optionValue.get(&keyValueVector);
+ if (!ret.isOK()) {
+ return ret;
}
- StringMap_t stringMap;
- for (YAML::const_iterator it = YAMLNode.begin(); it != YAMLNode.end(); ++it) {
- if (it->second.IsSequence() || it->second.IsMap()) {
+ StringMap_t mapValue;
+ for (StringVector_t::iterator keyValueVectorIt = keyValueVector.begin();
+ keyValueVectorIt != keyValueVector.end();
+ ++keyValueVectorIt) {
+ std::string key;
+ std::string value;
+ if (!mongoutils::str::splitOn(*keyValueVectorIt, '=', key, value)) {
StringBuilder sb;
- sb << "Option: " << key
- << " has a map with non scalar values, which is not allowed";
+ sb << "Illegal option assignment: \"" << *keyValueVectorIt << "\"";
return Status(ErrorCodes::BadValue, sb.str());
}
- if (stringMap.count(it->first.Scalar()) > 0) {
+ // Make sure we aren't setting an option to two different values
+ if (mapValue.count(key) > 0 && mapValue[key] != value) {
StringBuilder sb;
- sb << "String Map Option: " << key
- << " has duplicate keys in YAML Config: " << it->first.Scalar();
+ sb << "Key Value Option: " << iterator->_dottedName
+ << " has a duplicate key from the same source: " << key;
return Status(ErrorCodes::BadValue, sb.str());
}
- stringMap[it->first.Scalar()] = it->second.Scalar();
+ mapValue[key] = value;
}
- *value = Value(stringMap);
- return Status::OK();
+ optionValue = Value(mapValue);
}
- // Our YAML parser reads everything as a string, so we need to parse it ourselves.
- std::string stringVal = YAMLNode.Scalar();
- return stringToValue(stringVal, type, key, value);
+ environment->set(iterator->_dottedName, optionValue);
}
+ }
+ return Status::OK();
+}
+
+// Add all the values in the given YAML Node to our environment. See comments at the
+// beginning of this section.
+Status addYAMLNodesToEnvironment(const YAML::Node& root,
+ const OptionSection& options,
+ const std::string parentPath,
+ Environment* environment) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add all the values in the given variables_map to our environment. See comments at the
- // beginning of this section.
- Status addBoostVariablesToEnvironment(const po::variables_map& vm,
- const OptionSection& options,
- Environment* environment) {
-
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
- if (!ret.isOK()) {
- return ret;
- }
-
- for(std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- // Trim off the short option from our name so we can look it up correctly in our map
- std::string long_name;
- std::string::size_type commaOffset = iterator->_singleName.find(',');
- if (commaOffset != string::npos) {
- if (commaOffset != iterator->_singleName.size() - 2) {
- StringBuilder sb;
- sb << "Unexpected comma in option name: \"" << iterator->_singleName << "\""
- << ": option name must be in the format \"option,o\" or \"option\", "
- << "where \"option\" is the long name and \"o\" is the optional one "
- << "character short alias";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- long_name = iterator->_singleName.substr(0, commaOffset);
- } else {
- long_name = iterator->_singleName;
- }
+ // Don't return an error on empty config files
+ if (root.IsNull()) {
+ return Status::OK();
+ }
- if (vm.count(long_name)) {
- Value optionValue;
- Status ret = boostAnyToValue(vm[long_name].value(), iterator->_type, long_name,
- &optionValue);
- if (!ret.isOK()) {
- return ret;
- }
+ if (!root.IsMap() && parentPath.empty()) {
+ StringBuilder sb;
+ sb << "No map found at top level of YAML config";
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- // If this is really a StringMap, try to split on "key=value" for each element
- // in our StringVector
- if (iterator->_type == StringMap) {
- StringVector_t keyValueVector;
- ret = optionValue.get(&keyValueVector);
- if (!ret.isOK()) {
- return ret;
- }
- StringMap_t mapValue;
- for (StringVector_t::iterator keyValueVectorIt = keyValueVector.begin();
- keyValueVectorIt != keyValueVector.end(); ++keyValueVectorIt) {
- std::string key;
- std::string value;
- if (!mongoutils::str::splitOn(*keyValueVectorIt, '=', key, value)) {
- StringBuilder sb;
- sb << "Illegal option assignment: \"" << *keyValueVectorIt << "\"";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- // Make sure we aren't setting an option to two different values
- if (mapValue.count(key) > 0 && mapValue[key] != value) {
- StringBuilder sb;
- sb << "Key Value Option: " << iterator->_dottedName
- << " has a duplicate key from the same source: " << key;
- return Status(ErrorCodes::BadValue, sb.str());
- }
- mapValue[key] = value;
- }
- optionValue = Value(mapValue);
- }
+ for (YAML::const_iterator it = root.begin(); it != root.end(); ++it) {
+ std::string fieldName = it->first.Scalar();
+ YAML::Node YAMLNode = it->second;
+
+ std::string dottedName;
+ if (parentPath.empty()) {
+ // We are at the top level, so the full specifier is just the current field name
+ dottedName = fieldName;
+ } else {
+ // If our field name is "value", assume this contains the value for the parent
+ if (fieldName == "value") {
+ dottedName = parentPath;
+ }
- environment->set(iterator->_dottedName, optionValue);
- }
+ // If this is not a special field name, and we are in a sub object, append our
+ // current fieldName to the selector for the sub object we are traversing
+ else {
+ dottedName = parentPath + '.' + fieldName;
}
- return Status::OK();
}
- // Add all the values in the given YAML Node to our environment. See comments at the
- // beginning of this section.
- Status addYAMLNodesToEnvironment(const YAML::Node& root,
- const OptionSection& options,
- const std::string parentPath,
- Environment* environment) {
-
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
+ if (YAMLNode.IsMap() && !OptionIsStringMap(options_vector, dottedName)) {
+ Status ret = addYAMLNodesToEnvironment(YAMLNode, options, dottedName, environment);
if (!ret.isOK()) {
return ret;
}
-
- // Don't return an error on empty config files
- if (root.IsNull()) {
- return Status::OK();
+ } else {
+ Key canonicalKey;
+ Value optionValue;
+ Status ret =
+ YAMLNodeToValue(YAMLNode, options_vector, dottedName, &canonicalKey, &optionValue);
+ if (!ret.isOK()) {
+ return ret;
}
- if (!root.IsMap() && parentPath.empty()) {
+ Value dummyVal;
+ if (environment->get(canonicalKey, &dummyVal).isOK()) {
StringBuilder sb;
- sb << "No map found at top level of YAML config";
+ sb << "Error parsing YAML config: duplicate key: " << dottedName
+ << "(canonical key: " << canonicalKey << ")";
return Status(ErrorCodes::BadValue, sb.str());
}
- for (YAML::const_iterator it = root.begin(); it != root.end(); ++it) {
- std::string fieldName = it->first.Scalar();
- YAML::Node YAMLNode = it->second;
-
- std::string dottedName;
- if (parentPath.empty()) {
-
- // We are at the top level, so the full specifier is just the current field name
- dottedName = fieldName;
+ // Only add the value if it is not empty. YAMLNodeToValue will set the
+ // optionValue to an empty Value if we should not set it in the Environment.
+ if (!optionValue.isEmpty()) {
+ ret = environment->set(canonicalKey, optionValue);
+ if (!ret.isOK()) {
+ return ret;
}
- else {
+ }
+ }
+ }
- // If our field name is "value", assume this contains the value for the parent
- if (fieldName == "value") {
- dottedName = parentPath;
- }
+ return Status::OK();
+}
+
+/**
+* For all options that we registered as composable, combine the values from source and dest
+* and set the result in dest. Note that this only works for options that are registered as
+* vectors of strings.
+*/
+Status addCompositions(const OptionSection& options, const Environment& source, Environment* dest) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // If this is not a special field name, and we are in a sub object, append our
- // current fieldName to the selector for the sub object we are traversing
- else {
- dottedName = parentPath + '.' + fieldName;
- }
- }
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (!iterator->_isComposing) {
+ continue;
+ }
- if (YAMLNode.IsMap() && !OptionIsStringMap(options_vector, dottedName)) {
- Status ret = addYAMLNodesToEnvironment(YAMLNode, options, dottedName,
- environment);
- if (!ret.isOK()) {
- return ret;
- }
+ if (iterator->_type == StringVector) {
+ StringVector_t sourceValue;
+ ret = source.get(iterator->_dottedName, &sourceValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable vector value from source: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ // Only do something if our source environment has something to add
+ else if (ret.isOK()) {
+ StringVector_t destValue;
+ ret = dest->get(iterator->_dottedName, &destValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable vector value from dest: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
- else {
- Key canonicalKey;
- Value optionValue;
- Status ret = YAMLNodeToValue(YAMLNode, options_vector, dottedName,
- &canonicalKey, &optionValue);
- if (!ret.isOK()) {
- return ret;
- }
- Value dummyVal;
- if (environment->get(canonicalKey, &dummyVal).isOK()) {
- StringBuilder sb;
- sb << "Error parsing YAML config: duplicate key: " << dottedName
- << "(canonical key: " << canonicalKey << ")";
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ // Append sourceValue on the end of destValue
+ destValue.insert(destValue.end(), sourceValue.begin(), sourceValue.end());
- // Only add the value if it is not empty. YAMLNodeToValue will set the
- // optionValue to an empty Value if we should not set it in the Environment.
- if (!optionValue.isEmpty()) {
- ret = environment->set(canonicalKey, optionValue);
- if (!ret.isOK()) {
- return ret;
- }
- }
+ // Set the resulting value in our output environment
+ ret = dest->set(Key(iterator->_dottedName), Value(destValue));
+ if (!ret.isOK()) {
+ return ret;
}
}
-
- return Status::OK();
- }
-
- /**
- * For all options that we registered as composable, combine the values from source and dest
- * and set the result in dest. Note that this only works for options that are registered as
- * vectors of strings.
- */
- Status addCompositions(const OptionSection& options,
- const Environment& source,
- Environment* dest) {
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
- if (!ret.isOK()) {
- return ret;
+ } else if (iterator->_type == StringMap) {
+ StringMap_t sourceValue;
+ ret = source.get(iterator->_dottedName, &sourceValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable map value from source: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
-
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (!iterator->_isComposing) {
- continue;
+ // Only do something if our source environment has something to add
+ else if (ret.isOK()) {
+ StringMap_t destValue;
+ ret = dest->get(iterator->_dottedName, &destValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting composable map value from dest: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
- if (iterator->_type == StringVector) {
- StringVector_t sourceValue;
- ret = source.get(iterator->_dottedName, &sourceValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable vector value from source: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- // Only do something if our source environment has something to add
- else if (ret.isOK()) {
- StringVector_t destValue;
- ret = dest->get(iterator->_dottedName, &destValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable vector value from dest: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- // Append sourceValue on the end of destValue
- destValue.insert(destValue.end(),
- sourceValue.begin(),
- sourceValue.end());
-
- // Set the resulting value in our output environment
- ret = dest->set(Key(iterator->_dottedName), Value(destValue));
- if (!ret.isOK()) {
- return ret;
- }
- }
+ // Iterate sourceValue and add elements to destValue
+ for (StringMap_t::iterator sourceValueIt = sourceValue.begin();
+ sourceValueIt != sourceValue.end();
+ sourceValueIt++) {
+ destValue[sourceValueIt->first] = sourceValueIt->second;
}
- else if (iterator->_type == StringMap) {
- StringMap_t sourceValue;
- ret = source.get(iterator->_dottedName, &sourceValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable map value from source: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- // Only do something if our source environment has something to add
- else if (ret.isOK()) {
- StringMap_t destValue;
- ret = dest->get(iterator->_dottedName, &destValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting composable map value from dest: "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
-
- // Iterate sourceValue and add elements to destValue
- for (StringMap_t::iterator sourceValueIt = sourceValue.begin();
- sourceValueIt != sourceValue.end(); sourceValueIt++) {
- destValue[sourceValueIt->first] = sourceValueIt->second;
- }
-
- // Set the resulting value in our output environment
- ret = dest->set(Key(iterator->_dottedName), Value(destValue));
- if (!ret.isOK()) {
- return ret;
- }
- }
- } else {
- StringBuilder sb;
- sb << "Found composable option that is not of StringVector or "
- << "StringMap Type: " << iterator->_dottedName;
- return Status(ErrorCodes::InternalError, sb.str());
+
+ // Set the resulting value in our output environment
+ ret = dest->set(Key(iterator->_dottedName), Value(destValue));
+ if (!ret.isOK()) {
+ return ret;
}
}
-
- return Status::OK();
+ } else {
+ StringBuilder sb;
+ sb << "Found composable option that is not of StringVector or "
+ << "StringMap Type: " << iterator->_dottedName;
+ return Status(ErrorCodes::InternalError, sb.str());
}
+ }
- /**
- * 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;
+ return Status::OK();
+}
- Status ret = options.getConstraints(&constraints_vector);
- if (!ret.isOK()) {
- return ret;
- }
+/**
+* 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;
- std::vector<boost::shared_ptr<Constraint> >::const_iterator citerator;
- for (citerator = constraints_vector.begin();
- citerator != constraints_vector.end(); citerator++) {
- dest->addConstraint(citerator->get());
- }
+ Status ret = options.getConstraints(&constraints_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- return Status::OK();
- }
+ std::vector<boost::shared_ptr<Constraint>>::const_iterator citerator;
+ for (citerator = constraints_vector.begin(); citerator != constraints_vector.end();
+ citerator++) {
+ dest->addConstraint(citerator->get());
+ }
- /**
- * Remove any options of type "Switch" that are set to false. This is needed because boost
- * defaults switches to false, and we need to be able to tell the difference between
- * whether an option is set explicitly to false in config files or not present at all.
- */
- Status removeFalseSwitches(const OptionSection& options, Environment* environment) {
- std::vector<OptionDescription> options_vector;
- Status ret = options.getAllOptions(&options_vector);
- if (!ret.isOK()) {
- return ret;
- }
+ return Status::OK();
+}
- for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
+/**
+ * Remove any options of type "Switch" that are set to false. This is needed because boost
+ * defaults switches to false, and we need to be able to tell the difference between
+ * whether an option is set explicitly to false in config files or not present at all.
+ */
+Status removeFalseSwitches(const OptionSection& options, Environment* environment) {
+ std::vector<OptionDescription> options_vector;
+ Status ret = options.getAllOptions(&options_vector);
+ if (!ret.isOK()) {
+ return ret;
+ }
- if (iterator->_type == Switch) {
- bool switchValue;
- Status ret = environment->get(iterator->_dottedName, &switchValue);
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
- StringBuilder sb;
- sb << "Error getting switch value for option: " << iterator->_dottedName
- << " from source: " << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- else if (ret.isOK() && switchValue == false) {
- Status ret = environment->remove(iterator->_dottedName);
- if (!ret.isOK()) {
- StringBuilder sb;
- sb << "Error removing false flag: " << iterator->_dottedName << ": "
- << ret.toString();
- return Status(ErrorCodes::InternalError, sb.str());
- }
- }
+ for (std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_type == Switch) {
+ bool switchValue;
+ Status ret = environment->get(iterator->_dottedName, &switchValue);
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ StringBuilder sb;
+ sb << "Error getting switch value for option: " << iterator->_dottedName
+ << " from source: " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ } else if (ret.isOK() && switchValue == false) {
+ Status ret = environment->remove(iterator->_dottedName);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error removing false flag: " << iterator->_dottedName << ": "
+ << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
}
}
-
- return Status::OK();
}
+ }
+
+ return Status::OK();
+}
+
+} // namespace
- } // namespace
+/**
+ * This function delegates the command line parsing to boost program_options.
+ *
+ * 1. Extract the boost readable option descriptions and positional option descriptions from the
+ * OptionSection
+ * 2. Passes them to the boost command line parser
+ * 3. Copy everything from the variables map returned by boost into the Environment
+ */
+Status OptionsParser::parseCommandLine(const OptionSection& options,
+ const std::vector<std::string>& argv,
+ Environment* environment) {
+ po::options_description boostOptions;
+ po::positional_options_description boostPositionalOptions;
+ po::variables_map vm;
+
+ // Need to convert to an argc and a vector of char* since that is what
+ // boost::program_options expects as input to its command line parser
+ int argc = 0;
+ std::vector<const char*> argv_buffer;
+ for (std::vector<std::string>::const_iterator iterator = argv.begin(); iterator != argv.end();
+ iterator++) {
+ argv_buffer.push_back(iterator->c_str());
+ argc++;
+ }
/**
- * This function delegates the command line parsing to boost program_options.
+ * Style options for boost command line parser
*
- * 1. Extract the boost readable option descriptions and positional option descriptions from the
- * OptionSection
- * 2. Passes them to the boost command line parser
- * 3. Copy everything from the variables map returned by boost into the Environment
+ * unix_style is an alias for a group of basic style options. We are deviating from that
+ * base style in the following ways:
+ *
+ * 1. Don't allow guessing - '--dbpat' != '--dbpath'
+ * 2. Don't allow sticky - '-hf' != '-h -f'
+ * 3. Allow long disguises - '--dbpath' == '-dbpath'
+ *
+ * In some executables, we are using multiple 'v' options to set the verbosity (e.g. '-vvv')
+ * To make this work, we need to allow long disguises and disallow guessing.
*/
- Status OptionsParser::parseCommandLine(const OptionSection& options,
- const std::vector<std::string>& argv,
- Environment* environment) {
- po::options_description boostOptions;
- po::positional_options_description boostPositionalOptions;
- po::variables_map vm;
-
- // Need to convert to an argc and a vector of char* since that is what
- // boost::program_options expects as input to its command line parser
- int argc = 0;
- std::vector<const char*> argv_buffer;
- for (std::vector<std::string>::const_iterator iterator = argv.begin();
- iterator != argv.end(); iterator++) {
- argv_buffer.push_back(iterator->c_str());
- argc++;
- }
+ int style = (((po::command_line_style::unix_style ^ po::command_line_style::allow_guessing) |
+ po::command_line_style::allow_long_disguise) ^
+ po::command_line_style::allow_sticky);
- /**
- * Style options for boost command line parser
- *
- * unix_style is an alias for a group of basic style options. We are deviating from that
- * base style in the following ways:
- *
- * 1. Don't allow guessing - '--dbpat' != '--dbpath'
- * 2. Don't allow sticky - '-hf' != '-h -f'
- * 3. Allow long disguises - '--dbpath' == '-dbpath'
- *
- * In some executables, we are using multiple 'v' options to set the verbosity (e.g. '-vvv')
- * To make this work, we need to allow long disguises and disallow guessing.
- */
- int style = (((po::command_line_style::unix_style ^
- po::command_line_style::allow_guessing) |
- po::command_line_style::allow_long_disguise) ^
- po::command_line_style::allow_sticky);
-
- Status ret = options.getBoostOptions(&boostOptions, false, false, SourceCommandLine);
- if (!ret.isOK()) {
- return ret;
- }
-
- ret = options.getBoostPositionalOptions(&boostPositionalOptions);
- if (!ret.isOK()) {
- return ret;
- }
+ Status ret = options.getBoostOptions(&boostOptions, false, false, SourceCommandLine);
+ if (!ret.isOK()) {
+ return ret;
+ }
- try {
- po::store(po::command_line_parser(argc, (argc > 0 ? &argv_buffer[0] : NULL)).
- options(boostOptions).
- positional(boostPositionalOptions).
- style(style).
- run(), vm);
+ ret = options.getBoostPositionalOptions(&boostPositionalOptions);
+ if (!ret.isOK()) {
+ return ret;
+ }
- ret = addBoostVariablesToEnvironment(vm, options, environment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- catch (po::multiple_occurrences& e) {
- StringBuilder sb;
- sb << "Error parsing command line: Multiple occurrences of option \"--"
- << e.get_option_name() << "\"";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- catch (po::error& e) {
- StringBuilder sb;
- sb << "Error parsing command line: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- }
+ try {
+ po::store(po::command_line_parser(argc, (argc > 0 ? &argv_buffer[0] : NULL))
+ .options(boostOptions)
+ .positional(boostPositionalOptions)
+ .style(style)
+ .run(),
+ vm);
- // This is needed because "switches" default to false in boost, and we don't want to
- // erroneously think that they were present but set to false in a config file.
- ret = removeFalseSwitches(options, environment);
+ ret = addBoostVariablesToEnvironment(vm, options, environment);
if (!ret.isOK()) {
return ret;
}
+ } catch (po::multiple_occurrences& e) {
+ StringBuilder sb;
+ sb << "Error parsing command line: Multiple occurrences of option \"--"
+ << e.get_option_name() << "\"";
+ return Status(ErrorCodes::BadValue, sb.str());
+ } catch (po::error& e) {
+ StringBuilder sb;
+ sb << "Error parsing command line: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
+ }
- return Status::OK();
+ // This is needed because "switches" default to false in boost, and we don't want to
+ // erroneously think that they were present but set to false in a config file.
+ ret = removeFalseSwitches(options, environment);
+ if (!ret.isOK()) {
+ return ret;
}
- /**
- * This function delegates the INI config parsing to boost program_options.
- *
- * 1. Extract the boost readable option descriptions from the OptionSection
- * 2. Passes them to the boost config file parser
- * 3. Copy everything from the variables map returned by boost into the Environment
- */
- Status OptionsParser::parseINIConfigFile(const OptionSection& options,
- const std::string& config,
- Environment* environment) {
- po::options_description boostOptions;
- po::variables_map vm;
+ return Status::OK();
+}
+
+/**
+ * This function delegates the INI config parsing to boost program_options.
+ *
+ * 1. Extract the boost readable option descriptions from the OptionSection
+ * 2. Passes them to the boost config file parser
+ * 3. Copy everything from the variables map returned by boost into the Environment
+ */
+Status OptionsParser::parseINIConfigFile(const OptionSection& options,
+ const std::string& config,
+ Environment* environment) {
+ po::options_description boostOptions;
+ po::variables_map vm;
+
+ Status ret = options.getBoostOptions(&boostOptions, false, false, SourceINIConfig);
+ if (!ret.isOK()) {
+ return ret;
+ }
- Status ret = options.getBoostOptions(&boostOptions, false, false, SourceINIConfig);
+ std::istringstream is(config);
+ try {
+ po::store(po::parse_config_file(is, boostOptions), vm);
+ ret = addBoostVariablesToEnvironment(vm, options, environment);
if (!ret.isOK()) {
return ret;
}
-
- std::istringstream is(config);
- try {
- po::store(po::parse_config_file(is, boostOptions), vm);
- ret = addBoostVariablesToEnvironment(vm, options, environment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- catch (po::multiple_occurrences& e) {
- StringBuilder sb;
- sb << "Error parsing INI config file: Multiple occurrences of option \""
- << e.get_option_name() << "\"";
- return Status(ErrorCodes::BadValue, sb.str());
- }
- catch (po::error& e) {
- StringBuilder sb;
- sb << "Error parsing INI config file: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- }
- return Status::OK();
+ } catch (po::multiple_occurrences& e) {
+ StringBuilder sb;
+ sb << "Error parsing INI config file: Multiple occurrences of option \""
+ << e.get_option_name() << "\"";
+ return Status(ErrorCodes::BadValue, sb.str());
+ } catch (po::error& e) {
+ StringBuilder sb;
+ sb << "Error parsing INI config file: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
}
+ return Status::OK();
+}
namespace {
- /**
- * This function delegates the YAML config parsing to the third party YAML parser. It does no
- * error checking other than the parse error checking done by the YAML parser.
- */
- Status parseYAMLConfigFile(const std::string& config,
- YAML::Node* YAMLConfig) {
-
- try {
- *YAMLConfig = YAML::Load(config);
- } catch (const YAML::Exception &e) {
- StringBuilder sb;
- sb << "Error parsing YAML config file: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- } catch (const std::runtime_error &e) {
- StringBuilder sb;
- sb << "Unexpected exception parsing YAML config file: " << e.what();
- return Status(ErrorCodes::BadValue, sb.str());
- }
-
- return Status::OK();
+/**
+ * This function delegates the YAML config parsing to the third party YAML parser. It does no
+ * error checking other than the parse error checking done by the YAML parser.
+ */
+Status parseYAMLConfigFile(const std::string& config, YAML::Node* YAMLConfig) {
+ try {
+ *YAMLConfig = YAML::Load(config);
+ } catch (const YAML::Exception& e) {
+ StringBuilder sb;
+ sb << "Error parsing YAML config file: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
+ } catch (const std::runtime_error& e) {
+ StringBuilder sb;
+ sb << "Unexpected exception parsing YAML config file: " << e.what();
+ return Status(ErrorCodes::BadValue, sb.str());
}
- bool isYAMLConfig(const YAML::Node& config) {
- // The YAML parser is very forgiving, and for the INI config files we've parsed so far using
- // the YAML parser, the YAML parser just slurps the entire config file into a single string
- // rather than erroring out. Thus, we assume that having a scalar (string) as the root node
- // means that this is not meant to be a YAML config file, since even a very simple YAML
- // config file should be parsed as a Map, and thus "config.IsScalar()" would return false.
- //
- // This requires more testing, both to ensure that all INI style files get parsed as a
- // single string, and to ensure that the user experience does not suffer (in terms of this
- // causing confusing error messages for users writing a brand new YAML config file that
- // incorrectly triggers this check).
- if (config.IsScalar()) {
- return false;
- }
- else {
- return true;
- }
+ return Status::OK();
+}
+
+bool isYAMLConfig(const YAML::Node& config) {
+ // The YAML parser is very forgiving, and for the INI config files we've parsed so far using
+ // the YAML parser, the YAML parser just slurps the entire config file into a single string
+ // rather than erroring out. Thus, we assume that having a scalar (string) as the root node
+ // means that this is not meant to be a YAML config file, since even a very simple YAML
+ // config file should be parsed as a Map, and thus "config.IsScalar()" would return false.
+ //
+ // This requires more testing, both to ensure that all INI style files get parsed as a
+ // single string, and to ensure that the user experience does not suffer (in terms of this
+ // causing confusing error messages for users writing a brand new YAML config file that
+ // incorrectly triggers this check).
+ if (config.IsScalar()) {
+ return false;
+ } else {
+ return true;
}
+}
-} // namespace
+} // namespace
- /**
- * Add default values from the given OptionSection to the given Environment
- */
- Status OptionsParser::addDefaultValues(const OptionSection& options,
- Environment* environment) {
- std::map <Key, Value> defaultOptions;
+/**
+ * Add default values from the given OptionSection to the given Environment
+ */
+Status OptionsParser::addDefaultValues(const OptionSection& options, Environment* environment) {
+ std::map<Key, Value> defaultOptions;
- Status ret = options.getDefaults(&defaultOptions);
+ Status ret = options.getDefaults(&defaultOptions);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ typedef std::map<Key, Value>::iterator it_type;
+ for (it_type iterator = defaultOptions.begin(); iterator != defaultOptions.end(); iterator++) {
+ ret = environment->setDefault(iterator->first, iterator->second);
if (!ret.isOK()) {
return ret;
}
-
- typedef std::map<Key, Value>::iterator it_type;
- for(it_type iterator = defaultOptions.begin();
- iterator != defaultOptions.end(); iterator++) {
- ret = environment->setDefault(iterator->first, iterator->second);
- if (!ret.isOK()) {
- return ret;
- }
- }
-
- return Status::OK();
}
- /**
- * Reads the entire config file into the output string. This was done this way because the JSON
- * parser only takes complete strings, and we were using that to parse the config file before.
- * We could redesign the parser to use some kind of streaming interface, but for now this is
- * simple and works for the current use case of config files which should be limited in size.
- */
- Status OptionsParser::readConfigFile(const std::string& filename, std::string* contents) {
-
- FILE* config;
- config = fopen(filename.c_str(), "r");
- if (config == NULL) {
- const int current_errno = errno;
- StringBuilder sb;
- sb << "Error reading config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
- ON_BLOCK_EXIT(fclose, config);
+ return Status::OK();
+}
- // Get length of config file by seeking to the end and getting the cursor position
- if (fseek(config, 0L, SEEK_END) != 0) {
- const int current_errno = errno;
- // TODO: Make sure errno is the correct way to do this
- // Confirmed that errno gets set in Mac OSX, but not documented
- StringBuilder sb;
- sb << "Error seeking in config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
- long configSize = ftell(config);
-
- // Seek back to the beginning of the file for reading
- if (fseek(config, 0L, SEEK_SET) != 0) {
- const int current_errno = errno;
- // TODO: Make sure errno is the correct way to do this
- // Confirmed that errno gets set in Mac OSX, but not documented
- StringBuilder sb;
- sb << "Error seeking in config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
+/**
+ * Reads the entire config file into the output string. This was done this way because the JSON
+ * parser only takes complete strings, and we were using that to parse the config file before.
+ * We could redesign the parser to use some kind of streaming interface, but for now this is
+ * simple and works for the current use case of config files which should be limited in size.
+ */
+Status OptionsParser::readConfigFile(const std::string& filename, std::string* contents) {
+ FILE* config;
+ config = fopen(filename.c_str(), "r");
+ if (config == NULL) {
+ const int current_errno = errno;
+ StringBuilder sb;
+ sb << "Error reading config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ ON_BLOCK_EXIT(fclose, config);
+
+ // Get length of config file by seeking to the end and getting the cursor position
+ if (fseek(config, 0L, SEEK_END) != 0) {
+ const int current_errno = errno;
+ // TODO: Make sure errno is the correct way to do this
+ // Confirmed that errno gets set in Mac OSX, but not documented
+ StringBuilder sb;
+ sb << "Error seeking in config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+ long configSize = ftell(config);
+
+ // Seek back to the beginning of the file for reading
+ if (fseek(config, 0L, SEEK_SET) != 0) {
+ const int current_errno = errno;
+ // TODO: Make sure errno is the correct way to do this
+ // Confirmed that errno gets set in Mac OSX, but not documented
+ StringBuilder sb;
+ sb << "Error seeking in config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
- // Read into a vector first since it's guaranteed to have contiguous storage
- std::vector<char> configVector;
- configVector.resize(configSize);
-
- if (configSize > 0) {
- long nread = 0;
- while (!feof(config) && nread < configSize) {
- nread = nread + fread(&configVector[nread], sizeof(char),
- configSize - nread, config);
- if (ferror(config)) {
- const int current_errno = errno;
- // TODO: Make sure errno is the correct way to do this
- StringBuilder sb;
- sb << "Error reading in config file: " << strerror(current_errno);
- return Status(ErrorCodes::InternalError, sb.str());
- }
+ // Read into a vector first since it's guaranteed to have contiguous storage
+ std::vector<char> configVector;
+ configVector.resize(configSize);
+
+ if (configSize > 0) {
+ long nread = 0;
+ while (!feof(config) && nread < configSize) {
+ nread = nread + fread(&configVector[nread], sizeof(char), configSize - nread, config);
+ if (ferror(config)) {
+ const int current_errno = errno;
+ // TODO: Make sure errno is the correct way to do this
+ StringBuilder sb;
+ sb << "Error reading in config file: " << strerror(current_errno);
+ return Status(ErrorCodes::InternalError, sb.str());
}
- // Resize our config vector to the number of bytes we actually read
- configVector.resize(nread);
}
-
- // Copy the vector contents into our result string
- *contents = std::string(configVector.begin(), configVector.end());
-
- return Status::OK();
+ // Resize our config vector to the number of bytes we actually read
+ configVector.resize(nread);
}
- /**
- * Run the OptionsParser
- *
- * Overview:
- *
- * 1. Parse argc and argv using the given OptionSection as a description of expected options
- * 2. Check for a "config" argument
- * 3. If "config" found, read config file
- * 4. Detect config file type (YAML or INI)
- * 5. Parse config file using the given OptionSection as a description of expected options
- * 6. Add the results to the output Environment in the proper order to ensure correct precedence
- */
- Status OptionsParser::run(const OptionSection& options,
- const std::vector<std::string>& argv,
- const std::map<std::string, std::string>& env, // XXX: Currently unused
- Environment* environment) {
+ // Copy the vector contents into our result string
+ *contents = std::string(configVector.begin(), configVector.end());
+
+ return Status::OK();
+}
- Environment commandLineEnvironment;
- Environment configEnvironment;
- Environment composedEnvironment;
+/**
+ * Run the OptionsParser
+ *
+ * Overview:
+ *
+ * 1. Parse argc and argv using the given OptionSection as a description of expected options
+ * 2. Check for a "config" argument
+ * 3. If "config" found, read config file
+ * 4. Detect config file type (YAML or INI)
+ * 5. Parse config file using the given OptionSection as a description of expected options
+ * 6. Add the results to the output Environment in the proper order to ensure correct precedence
+ */
+Status OptionsParser::run(const OptionSection& options,
+ const std::vector<std::string>& argv,
+ const std::map<std::string, std::string>& env, // XXX: Currently unused
+ Environment* environment) {
+ Environment commandLineEnvironment;
+ Environment configEnvironment;
+ Environment composedEnvironment;
+
+ Status ret = parseCommandLine(options, argv, &commandLineEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- Status ret = parseCommandLine(options, argv, &commandLineEnvironment);
+ Value config_value;
+ ret = commandLineEnvironment.get(Key("config"), &config_value);
+ // We had an error other than "config" not existing in our environment
+ if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ return ret;
+ }
+ // "config" exists in our environment
+ else if (ret.isOK()) {
+ // Environment::get returns a bad status if config was not set
+ std::string config_filename;
+ ret = config_value.get(&config_filename);
if (!ret.isOK()) {
return ret;
}
- Value config_value;
- ret = commandLineEnvironment.get(Key("config"), &config_value);
- // We had an error other than "config" not existing in our environment
- if (!ret.isOK() && ret != ErrorCodes::NoSuchKey) {
+ std::string config_file;
+ ret = readConfigFile(config_filename, &config_file);
+ if (!ret.isOK()) {
return ret;
}
- // "config" exists in our environment
- else if (ret.isOK()) {
- // Environment::get returns a bad status if config was not set
- std::string config_filename;
- ret = config_value.get(&config_filename);
- if (!ret.isOK()) {
- return ret;
- }
+ YAML::Node YAMLConfig;
+ ret = parseYAMLConfigFile(config_file, &YAMLConfig);
+ if (!ret.isOK()) {
+ return ret;
+ }
- std::string config_file;
- ret = readConfigFile(config_filename, &config_file);
+ if (isYAMLConfig(YAMLConfig)) {
+ ret = addYAMLNodesToEnvironment(YAMLConfig, options, "", &configEnvironment);
if (!ret.isOK()) {
return ret;
}
-
- YAML::Node YAMLConfig;
- ret = parseYAMLConfigFile(config_file, &YAMLConfig);
+ } else {
+ ret = parseINIConfigFile(options, config_file, &configEnvironment);
if (!ret.isOK()) {
return ret;
}
-
- if (isYAMLConfig(YAMLConfig)) {
- ret = addYAMLNodesToEnvironment(YAMLConfig, options, "", &configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- else {
- ret = parseINIConfigFile(options, config_file, &configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- }
- }
-
- // Adds the values for all our options that were registered as composable to the composed
- // environment. addCompositions doesn't override the values like "setAll" on our
- // environment. Instead it aggregates the values in the result environment.
- // NOTE: We must add our configEnvironment compositions first since we have a StringMap type
- // in which some options can be overridden by the command line.
- ret = addCompositions(options, configEnvironment, &composedEnvironment);
- if (!ret.isOK()) {
- return ret;
}
+ }
- ret = addCompositions(options, commandLineEnvironment, &composedEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Adds the values for all our options that were registered as composable to the composed
+ // environment. addCompositions doesn't override the values like "setAll" on our
+ // environment. Instead it aggregates the values in the result environment.
+ // NOTE: We must add our configEnvironment compositions first since we have a StringMap type
+ // in which some options can be overridden by the command line.
+ ret = addCompositions(options, configEnvironment, &composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add the default values to our resulting environment
- ret = addDefaultValues(options, environment);
- if (!ret.isOK()) {
- return ret;
- }
+ ret = addCompositions(options, commandLineEnvironment, &composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add the values to our result in the order of override
- // NOTE: This should not fail validation as we haven't called environment->validate() yet
- ret = environment->setAll(configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- ret = environment->setAll(commandLineEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Add the default values to our resulting environment
+ ret = addDefaultValues(options, environment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add this last because it has all the composable options aggregated over different
- // sources. For example, if we have a StringMap type with some values set on the command
- // line and some values set in config files, we want to make sure to get them all. This
- // should not override any non composable options, since composedEnvironment should not have
- // them set. See the addCompositions function for more details.
- ret = environment->setAll(composedEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Add the values to our result in the order of override
+ // NOTE: This should not fail validation as we haven't called environment->validate() yet
+ ret = environment->setAll(configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ ret = environment->setAll(commandLineEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- // Add the constraints from our options to the result environment
- ret = addConstraints(options, environment);
- if (!ret.isOK()) {
- return ret;
- }
+ // Add this last because it has all the composable options aggregated over different
+ // sources. For example, if we have a StringMap type with some values set on the command
+ // line and some values set in config files, we want to make sure to get them all. This
+ // should not override any non composable options, since composedEnvironment should not have
+ // them set. See the addCompositions function for more details.
+ ret = environment->setAll(composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
- return Status::OK();
+ // Add the constraints from our options to the result environment
+ ret = addConstraints(options, environment);
+ if (!ret.isOK()) {
+ return ret;
}
-} // namespace optionenvironment
-} // namespace mongo
+ return Status::OK();
+}
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser.h b/src/mongo/util/options_parser/options_parser.h
index 8e277f25352..9c3752f1660 100644
--- a/src/mongo/util/options_parser/options_parser.h
+++ b/src/mongo/util/options_parser/options_parser.h
@@ -36,87 +36,88 @@
namespace mongo {
namespace optionenvironment {
- class Environment;
- class OptionSection;
- class Value;
+class Environment;
+class OptionSection;
+class Value;
- /** Handles parsing of the command line as well as YAML and INI config files. Takes an
- * OptionSection instance that describes the allowed options, parses argv (env not yet
- * supported), and populates an Environment with the results.
- *
- * Usage:
- *
- * namespace moe = mongo::optionenvironment;
- *
- * moe::OptionsParser parser;
- * moe::Environment environment;
- * moe::OptionSection options;
- *
- * // Register our allowed options with our OptionSection
- * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
- * options.addOptionChaining("port", "port", moe::Int, "Port");
- *
- * // Run the parser
- * Status ret = parser.run(options, argv, env, &environment);
- * if (!ret.isOK()) {
- * cerr << options.helpString() << std::endl;
- * exit(EXIT_FAILURE);
- * }
- *
- * bool displayHelp;
- * ret = environment.get(moe::Key("help"), &displayHelp);
- * if (!ret.isOK()) {
- * // Help is a switch, so it should always be set
- * cout << "Should not get here" << std::endl;
- * exit(EXIT_FAILURE);
- * }
- * if (displayHelp) {
- * cout << options.helpString() << std::endl;
- * exit(EXIT_SUCCESS);
- * }
+/** Handles parsing of the command line as well as YAML and INI config files. Takes an
+ * OptionSection instance that describes the allowed options, parses argv (env not yet
+ * supported), and populates an Environment with the results.
+ *
+ * Usage:
+ *
+ * namespace moe = mongo::optionenvironment;
+ *
+ * moe::OptionsParser parser;
+ * moe::Environment environment;
+ * moe::OptionSection options;
+ *
+ * // Register our allowed options with our OptionSection
+ * options.addOptionChaining("help", "help", moe::Switch, "Display Help");
+ * options.addOptionChaining("port", "port", moe::Int, "Port");
+ *
+ * // Run the parser
+ * Status ret = parser.run(options, argv, env, &environment);
+ * if (!ret.isOK()) {
+ * cerr << options.helpString() << std::endl;
+ * exit(EXIT_FAILURE);
+ * }
+ *
+ * bool displayHelp;
+ * ret = environment.get(moe::Key("help"), &displayHelp);
+ * if (!ret.isOK()) {
+ * // Help is a switch, so it should always be set
+ * cout << "Should not get here" << std::endl;
+ * exit(EXIT_FAILURE);
+ * }
+ * if (displayHelp) {
+ * cout << options.helpString() << std::endl;
+ * exit(EXIT_SUCCESS);
+ * }
+ *
+ * // Get the value of port from the environment
+ * int port = 27017;
+ * ret = environment.get(moe::Key("port"), &port);
+ * if (ret.isOK()) {
+ * // We have overridden port here, otherwise it stays as the default.
+ * }
+ */
+class OptionsParser {
+public:
+ OptionsParser() {}
+ virtual ~OptionsParser() {}
+
+ /** Handles parsing of the command line as well as YAML and INI config files. The
+ * OptionSection be a description of the allowed options. This function populates the
+ * given Environment with the results of parsing the command line and or config files but
+ * does not call validate on the Environment.
*
- * // Get the value of port from the environment
- * int port = 27017;
- * ret = environment.get(moe::Key("port"), &port);
- * if (ret.isOK()) {
- * // We have overridden port here, otherwise it stays as the default.
- * }
+ * The only special option is the "config" option. This function will check if the
+ * "config" option was set on the command line and if so attempt to read the given config
+ * file. For binaries that do not support config files, the "config" option should not be
+ * registered in the OptionSection.
*/
- class OptionsParser {
- public:
- OptionsParser() { }
- virtual ~OptionsParser() { }
-
- /** Handles parsing of the command line as well as YAML and INI config files. The
- * OptionSection be a description of the allowed options. This function populates the
- * given Environment with the results of parsing the command line and or config files but
- * does not call validate on the Environment.
- *
- * The only special option is the "config" option. This function will check if the
- * "config" option was set on the command line and if so attempt to read the given config
- * file. For binaries that do not support config files, the "config" option should not be
- * registered in the OptionSection.
- */
- Status run(const OptionSection&,
- const std::vector<std::string>& argv,
- const std::map<std::string, std::string>& env,
- Environment*);
+ Status run(const OptionSection&,
+ const std::vector<std::string>& argv,
+ const std::map<std::string, std::string>& env,
+ Environment*);
- private:
- /** Handles parsing of the command line and adds the results to the given Environment */
- Status parseCommandLine(const OptionSection&,
- const std::vector<std::string>& argv, Environment*);
+private:
+ /** Handles parsing of the command line and adds the results to the given Environment */
+ Status parseCommandLine(const OptionSection&,
+ const std::vector<std::string>& argv,
+ Environment*);
- /** Handles parsing of an INI config std::string and adds the results to the given Environment */
- Status parseINIConfigFile(const OptionSection&, const std::string& config, Environment*);
+ /** Handles parsing of an INI config std::string and adds the results to the given Environment */
+ Status parseINIConfigFile(const OptionSection&, const std::string& config, Environment*);
- /** Gets defaults from the OptionSection and adds them to the given Environment */
- Status addDefaultValues(const OptionSection&, Environment*);
+ /** Gets defaults from the OptionSection and adds them to the given Environment */
+ Status addDefaultValues(const OptionSection&, Environment*);
- /** Reads the given config file into the output string. This function is virtual for
- * testing purposes only. */
- virtual Status readConfigFile(const std::string& filename, std::string*);
- };
+ /** Reads the given config file into the output string. This function is virtual for
+ * testing purposes only. */
+ virtual Status readConfigFile(const std::string& filename, std::string*);
+};
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser_init.cpp b/src/mongo/util/options_parser/options_parser_init.cpp
index e703d3bdd49..f75c98c603a 100644
--- a/src/mongo/util/options_parser/options_parser_init.cpp
+++ b/src/mongo/util/options_parser/options_parser_init.cpp
@@ -42,17 +42,15 @@ namespace optionenvironment {
MONGO_STARTUP_OPTIONS_PARSE(StartupOptions)(InitializerContext* context) {
OptionsParser parser;
- Status ret = parser.run(startupOptions, context->args(), context->env(),
- &startupOptionsParsed);
+ Status ret = parser.run(startupOptions, context->args(), context->env(), &startupOptionsParsed);
if (!ret.isOK()) {
std::cerr << ret.reason() << std::endl;
// TODO: Figure out if there's a use case for this help message ever being different
- std::cerr << "try '" << context->args()[0]
- << " --help' for more information" << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information" << std::endl;
quickExit(EXIT_BADOPTIONS);
}
return Status::OK();
}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index cde7f4b2896..738bcb90d21 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -39,3651 +39,3707 @@
namespace {
- using mongo::ErrorCodes;
- using mongo::Status;
+using mongo::ErrorCodes;
+using mongo::Status;
- namespace moe = mongo::optionenvironment;
+namespace moe = mongo::optionenvironment;
#define TEST_CONFIG_PATH(x) "src/mongo/util/options_parser/test_config_files/" x
- class OptionsParserTester : public moe::OptionsParser {
- public:
- Status readConfigFile(const std::string& filename, std::string* config) {
- if (filename != _filename) {
- ::mongo::StringBuilder sb;
- sb << "Parser using filename: " << filename <<
- " which does not match expected filename: " << _filename;
- return Status(ErrorCodes::InternalError, sb.str());
- }
- *config = _config;
- return Status::OK();
- }
- void setConfig(const std::string& filename, const std::string& config) {
- _filename = filename;
- _config = config;
- }
- private:
- std::string _filename;
- std::string _config;
- };
-
- TEST(Registration, EmptySingleName) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("dup", "", moe::Switch, "dup");
- testOpts.addOptionChaining("new", "", moe::Switch, "dup");
- }
- catch (::mongo::DBException &e) {
- ::mongo::StringBuilder sb;
- sb << "Was not able to register two options with empty single name: " << e.what();
- FAIL(sb.str());
- }
-
- // This should fail now, because we didn't specify that these options were not valid in the
- // INI config or on the command line
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- moe::OptionsParser parser;
- moe::Environment environment;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- moe::OptionSection testOptsValid;
- try {
- testOptsValid.addOptionChaining("dup", "", moe::Switch, "dup")
- .setSources(moe::SourceYAMLConfig);
- testOptsValid.addOptionChaining("new", "", moe::Switch, "dup")
- .setSources(moe::SourceYAMLConfig);
- }
- catch (::mongo::DBException &e) {
+class OptionsParserTester : public moe::OptionsParser {
+public:
+ Status readConfigFile(const std::string& filename, std::string* config) {
+ if (filename != _filename) {
::mongo::StringBuilder sb;
- sb << "Was not able to register two options with empty single name" << e.what();
- FAIL(sb.str());
- }
-
- // This should pass now, because we specified that these options were not valid in the INI
- // config or on the command line
- ASSERT_OK(parser.run(testOptsValid, argv, env_map, &environment));
- }
-
- TEST(Registration, DuplicateSingleName) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
- testOpts.addOptionChaining("new", "dup", moe::Switch, "dup");
- FAIL("Was able to register duplicate single name");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, DuplicateDottedName) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
- testOpts.addOptionChaining("dup", "new", moe::Switch, "dup");
- FAIL("Was able to register duplicate single name");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, DuplicatePositional) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
- .positional(1, 1);
- FAIL("Was able to register duplicate positional option");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, BadRangesPositional) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(-1, 1);
- FAIL("Was able to register positional with negative start for range");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(2, 1);
- FAIL("Was able to register positional with start of range larger than end");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, -2);
- FAIL("Was able to register positional with bad end of range");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(0, 1);
- FAIL("Was able to register positional with bad start of range");
- }
- catch (::mongo::DBException&) {
- }
- try {
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 2);
- FAIL("Was able to register multi valued positional with non StringVector type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, DefaultValueWrongType) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value("String"));
- FAIL("Was able to register default value with wrong type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ImplicitValueWrongType) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setImplicit(moe::Value("String"));
- FAIL("Was able to register implicit value with wrong type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ComposableNotVectorOrMap) {
- moe::OptionSection testOpts;
- try {
- testOpts.addOptionChaining("setParameter", "setParameter", moe::String,
- "Multiple Values").composing();
- FAIL("Was able to register composable option with wrong type");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ComposableWithImplicit) {
- moe::OptionSection testOpts;
- try {
- std::vector<std::string> implicitVal;
- implicitVal.push_back("implicit");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .setImplicit(moe::Value(implicitVal))
- .composing();
- FAIL("Was able to register composable option with implicit value");
- }
- catch (::mongo::DBException&) {
- }
-
- try {
- std::vector<std::string> implicitVal;
- implicitVal.push_back("implicit");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .composing()
- .setImplicit(moe::Value(implicitVal));
- FAIL("Was able to set implicit value on composable option");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Registration, ComposableWithDefault) {
- moe::OptionSection testOpts;
- try {
- std::vector<std::string> defaultVal;
- defaultVal.push_back("default");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .setDefault(moe::Value(defaultVal))
- .composing();
- FAIL("Was able to register composable option with default value");
- }
- catch (::mongo::DBException&) {
- }
-
- try {
- std::vector<std::string> defaultVal;
- defaultVal.push_back("default");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values")
- .composing()
- .setDefault(moe::Value(defaultVal));
- FAIL("Was able to set default value on composable option");
- }
- catch (::mongo::DBException&) {
- }
- }
-
- 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&) {
- }
- }
-
- 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");
+ sb << "Parser using filename: " << filename
+ << " which does not match expected filename: " << _filename;
+ return Status(ErrorCodes::InternalError, sb.str());
}
- catch (::mongo::DBException&) {
- }
- }
-
- TEST(Parsing, Good) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("--help");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("help"), &value));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, SubSection) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- moe::OptionSection subSection("Section Name");
-
- subSection.addOptionChaining("port", "port", moe::Int, "Port");
- testOpts.addSection(subSection);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, StringVector) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--multival");
- argv.push_back("val1");
- argv.push_back("--multival");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(Parsing, StringMap) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--multival");
- argv.push_back("key1=value1");
- argv.push_back("--multival");
- argv.push_back("key2=value2");
- argv.push_back("--multival");
- argv.push_back("key3=");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(Parsing, StringMapDuplicateKey) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--multival");
- argv.push_back("key1=value1");
- argv.push_back("--multival");
- argv.push_back("key1=value2");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, Positional) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- }
-
- TEST(Parsing, PositionalTooMany) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("extrapositional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, PositionalAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, PositionalMultiple) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- }
-
- TEST(Parsing, PositionalMultipleExtra) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, PositionalMultipleUnlimited) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, -1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional3");
- argv.push_back("positional4");
- argv.push_back("positional5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional3");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional4");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional5");
- }
-
- TEST(Parsing, PositionalMultipleAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, NeedArg) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, BadArg) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("string");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Parsing, ExtraArg) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--help");
- argv.push_back("string");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ *config = _config;
+ return Status::OK();
+ }
+ void setConfig(const std::string& filename, const std::string& config) {
+ _filename = filename;
+ _config = config;
+ }
+
+private:
+ std::string _filename;
+ std::string _config;
+};
+
+TEST(Registration, EmptySingleName) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("dup", "", moe::Switch, "dup");
+ testOpts.addOptionChaining("new", "", moe::Switch, "dup");
+ } catch (::mongo::DBException& e) {
+ ::mongo::StringBuilder sb;
+ sb << "Was not able to register two options with empty single name: " << e.what();
+ FAIL(sb.str());
+ }
+
+ // This should fail now, because we didn't specify that these options were not valid in the
+ // INI config or on the command line
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ moe::OptionsParser parser;
+ moe::Environment environment;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ moe::OptionSection testOptsValid;
+ try {
+ testOptsValid.addOptionChaining("dup", "", moe::Switch, "dup")
+ .setSources(moe::SourceYAMLConfig);
+ testOptsValid.addOptionChaining("new", "", moe::Switch, "dup")
+ .setSources(moe::SourceYAMLConfig);
+ } catch (::mongo::DBException& e) {
+ ::mongo::StringBuilder sb;
+ sb << "Was not able to register two options with empty single name" << e.what();
+ FAIL(sb.str());
+ }
+
+ // This should pass now, because we specified that these options were not valid in the INI
+ // config or on the command line
+ ASSERT_OK(parser.run(testOptsValid, argv, env_map, &environment));
+}
+
+TEST(Registration, DuplicateSingleName) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
+ testOpts.addOptionChaining("new", "dup", moe::Switch, "dup");
+ FAIL("Was able to register duplicate single name");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, DuplicateDottedName) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("dup", "dup", moe::Switch, "dup");
+ testOpts.addOptionChaining("dup", "new", moe::Switch, "dup");
+ FAIL("Was able to register duplicate single name");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, DuplicatePositional) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional", "positional", moe::Int, "Positional")
+ .positional(1, 1);
+ FAIL("Was able to register duplicate positional option");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, BadRangesPositional) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(-1, 1);
+ FAIL("Was able to register positional with negative start for range");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, DefaultValue) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(2, 1);
+ FAIL("Was able to register positional with start of range larger than end");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, DefaultValueOverride) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, -2);
+ FAIL("Was able to register positional with bad end of range");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, DefaultValuesNotInBSON) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("val1", "val1", moe::Int, "Val1").setDefault(moe::Value(5));
- testOpts.addOptionChaining("val2", "val2", moe::Int, "Val2").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--val1");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- mongo::BSONObj expected = BSON("val1" << 6);
- ASSERT_EQUALS(expected, environment.toBSON());
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(0, 1);
+ FAIL("Was able to register positional with bad start of range");
+ } catch (::mongo::DBException&) {
}
-
- TEST(Parsing, ImplicitValue) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value(6)).setImplicit(moe::Value(7));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 7);
+ try {
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 2);
+ FAIL("Was able to register multi valued positional with non StringVector type");
+ } catch (::mongo::DBException&) {
}
+}
- TEST(Parsing, ImplicitValueDefault) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+TEST(Registration, DefaultValueWrongType) {
+ moe::OptionSection testOpts;
+ try {
testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value(6)).setImplicit(moe::Value(7));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
+ .setDefault(moe::Value("String"));
+ FAIL("Was able to register default value with wrong type");
+ } catch (::mongo::DBException&) {
}
+}
- TEST(Parsing, ImplicitValueOverride) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+TEST(Registration, ImplicitValueWrongType) {
+ moe::OptionSection testOpts;
+ try {
testOpts.addOptionChaining("port", "port", moe::Int, "Port")
- .setDefault(moe::Value(6)).setImplicit(moe::Value(7));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Parsing, ShortName) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help,h", moe::Switch, "Display help");
- testOpts.addOptionChaining("port", "port,p", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-p");
- argv.push_back("5");
- argv.push_back("-h");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("help"), &value));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(Style, NoSticky) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("opt", "opt,o", moe::Switch, "first opt");
- testOpts.addOptionChaining("arg", "arg,a", moe::Switch, "first arg");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-oa");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Style, NoGuessing) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--hel");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(Style, LongDisguises) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-help");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("help"), &value));
- bool help;
- ASSERT_OK(value.get(&help));
- ASSERT_EQUALS(help, true);
- }
-
- TEST(Style, Verbosity) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("v", "verbose,v", moe::Switch,
- "be more verbose (include multiple times for more verbosity e.g. -vvvvv)");
-
- /* support for -vv -vvvv etc. */
- for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
- testOpts.addOptionChaining(s.c_str(), s.c_str(), moe::Switch,
- "higher verbosity levels (hidden)").hidden();
- }
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("-vvvvvv");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- moe::Value value;
- for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
- if (s.length() == 6) {
- ASSERT_OK(environment.get(moe::Key(s), &value));
- bool verbose;
- ASSERT_OK(value.get(&verbose));
- ASSERT_EQUALS(verbose, true);
- }
- else {
- ASSERT_NOT_OK(environment.get(moe::Key(s), &value));
- }
+ .setImplicit(moe::Value("String"));
+ FAIL("Was able to register implicit value with wrong type");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, ComposableNotVectorOrMap) {
+ moe::OptionSection testOpts;
+ try {
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::String, "Multiple Values")
+ .composing();
+ FAIL("Was able to register composable option with wrong type");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, ComposableWithImplicit) {
+ moe::OptionSection testOpts;
+ try {
+ std::vector<std::string> implicitVal;
+ implicitVal.push_back("implicit");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .setImplicit(moe::Value(implicitVal))
+ .composing();
+ FAIL("Was able to register composable option with implicit value");
+ } catch (::mongo::DBException&) {
+ }
+
+ try {
+ std::vector<std::string> implicitVal;
+ implicitVal.push_back("implicit");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing()
+ .setImplicit(moe::Value(implicitVal));
+ FAIL("Was able to set implicit value on composable option");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+TEST(Registration, ComposableWithDefault) {
+ moe::OptionSection testOpts;
+ try {
+ std::vector<std::string> defaultVal;
+ defaultVal.push_back("default");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .setDefault(moe::Value(defaultVal))
+ .composing();
+ FAIL("Was able to register composable option with default value");
+ } catch (::mongo::DBException&) {
+ }
+
+ try {
+ std::vector<std::string> defaultVal;
+ defaultVal.push_back("default");
+ testOpts.addOptionChaining(
+ "setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing()
+ .setDefault(moe::Value(defaultVal));
+ FAIL("Was able to set default value on composable option");
+ } catch (::mongo::DBException&) {
+ }
+}
+
+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&) {
+ }
+}
+
+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&) {
+ }
+}
+
+TEST(Parsing, Good) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("--help");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("help"), &value));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, SubSection) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ moe::OptionSection subSection("Section Name");
+
+ subSection.addOptionChaining("port", "port", moe::Int, "Port");
+ testOpts.addSection(subSection);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, StringVector) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--multival");
+ argv.push_back("val1");
+ argv.push_back("--multival");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(Parsing, StringMap) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--multival");
+ argv.push_back("key1=value1");
+ argv.push_back("--multival");
+ argv.push_back("key2=value2");
+ argv.push_back("--multival");
+ argv.push_back("key3=");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(Parsing, StringMapDuplicateKey) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--multival");
+ argv.push_back("key1=value1");
+ argv.push_back("--multival");
+ argv.push_back("key1=value2");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, Positional) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+}
+
+TEST(Parsing, PositionalTooMany) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("extrapositional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, PositionalAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, PositionalMultiple) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+}
+
+TEST(Parsing, PositionalMultipleExtra) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, PositionalMultipleUnlimited) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, -1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional3");
+ argv.push_back("positional4");
+ argv.push_back("positional5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional3");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional4");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional5");
+}
+
+TEST(Parsing, PositionalMultipleAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, NeedArg) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, BadArg) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("string");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, ExtraArg) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--help");
+ argv.push_back("string");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Parsing, DefaultValue) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, DefaultValueOverride) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(Parsing, DefaultValuesNotInBSON) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("val1", "val1", moe::Int, "Val1").setDefault(moe::Value(5));
+ testOpts.addOptionChaining("val2", "val2", moe::Int, "Val2").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--val1");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ mongo::BSONObj expected = BSON("val1" << 6);
+ ASSERT_EQUALS(expected, environment.toBSON());
+}
+
+TEST(Parsing, ImplicitValue) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .setDefault(moe::Value(6))
+ .setImplicit(moe::Value(7));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 7);
+}
+
+TEST(Parsing, ImplicitValueDefault) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .setDefault(moe::Value(6))
+ .setImplicit(moe::Value(7));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(Parsing, ImplicitValueOverride) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port")
+ .setDefault(moe::Value(6))
+ .setImplicit(moe::Value(7));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Parsing, ShortName) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help,h", moe::Switch, "Display help");
+ testOpts.addOptionChaining("port", "port,p", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-p");
+ argv.push_back("5");
+ argv.push_back("-h");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("help"), &value));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(Style, NoSticky) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("opt", "opt,o", moe::Switch, "first opt");
+ testOpts.addOptionChaining("arg", "arg,a", moe::Switch, "first arg");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-oa");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Style, NoGuessing) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--hel");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(Style, LongDisguises) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("help", "help", moe::Switch, "Display help");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-help");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("help"), &value));
+ bool help;
+ ASSERT_OK(value.get(&help));
+ ASSERT_EQUALS(help, true);
+}
+
+TEST(Style, Verbosity) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining(
+ "v",
+ "verbose,v",
+ moe::Switch,
+ "be more verbose (include multiple times for more verbosity e.g. -vvvvv)");
+
+ /* support for -vv -vvvv etc. */
+ for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
+ testOpts.addOptionChaining(
+ s.c_str(), s.c_str(), moe::Switch, "higher verbosity levels (hidden)")
+ .hidden();
+ }
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("-vvvvvv");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ moe::Value value;
+ for (std::string s = "vv"; s.length() <= 12; s.append("v")) {
+ if (s.length() == 6) {
+ ASSERT_OK(environment.get(moe::Key(s), &value));
+ bool verbose;
+ ASSERT_OK(value.get(&verbose));
+ ASSERT_EQUALS(verbose, true);
+ } else {
+ ASSERT_NOT_OK(environment.get(moe::Key(s), &value));
}
}
-
- TEST(INIConfigFile, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "port=5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
+}
+
+TEST(INIConfigFile, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "port=5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(INIConfigFile, Empty) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(INIConfigFile, Override) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "port=5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(INIConfigFile, Comments) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+ testOpts.addOptionChaining("str", "str", moe::String, "String");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "# port=5\nstr=NotCommented");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_NOT_OK(environment.get(moe::Key("port"), &value));
+ ASSERT_OK(environment.get(moe::Key("str"), &value));
+ std::string str;
+ ASSERT_OK(value.get(&str));
+ ASSERT_EQUALS(str, "NotCommented");
+}
+
+// Ensure switches in INI config files have the correct semantics.
+//
+// Switches have the following semantics:
+// - Present on the command line -> set to true
+// - Present in the config file -> set to value in config file
+// - Present in the config file with no value (INI only) -> set to true
+// - Not present -> not set to any value
+TEST(INIConfigFile, Switches) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("switch1", "switch1", moe::Switch, "switch1");
+ testOpts.addOptionChaining("switch2", "switch2", moe::Switch, "switch2");
+ testOpts.addOptionChaining("switch3", "switch3", moe::Switch, "switch3");
+ testOpts.addOptionChaining("switch4", "switch4", moe::Switch, "switch4");
+ testOpts.addOptionChaining("switch5", "switch5", moe::Switch, "switch5");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ argv.push_back("--switch1");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "switch2=true\nswitch3=false\nswitch5=");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ bool switch1;
+ ASSERT_OK(environment.get(moe::Key("switch1"), &switch1));
+ ASSERT_TRUE(switch1);
+ bool switch2;
+ ASSERT_OK(environment.get(moe::Key("switch2"), &switch2));
+ ASSERT_TRUE(switch2);
+ bool switch3;
+ ASSERT_OK(environment.get(moe::Key("switch3"), &switch3));
+ ASSERT_FALSE(switch3);
+ bool switch4;
+ ASSERT_NOT_OK(environment.get(moe::Key("switch4"), &switch4));
+ bool switch5;
+ ASSERT_OK(environment.get(moe::Key("switch5"), &switch5));
+ ASSERT_TRUE(switch5);
+}
+
+TEST(INIConfigFile, Monkeys) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("this", "this", moe::Switch, "This");
+ testOpts.addOptionChaining("that", "that", moe::Switch, "That");
+ testOpts.addOptionChaining("another", "another", moe::String, "Another");
+ testOpts.addOptionChaining("other", "other", moe::String, "Other");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf",
+ "\t this = false \n#that = true\n #another = whocares"
+ "\n\n other = monkeys ");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("this"), &value));
+ bool thisValue;
+ ASSERT_OK(value.get(&thisValue));
+ ASSERT_FALSE(thisValue);
+ ASSERT_NOT_OK(environment.get(moe::Key("that"), &value));
+ ASSERT_NOT_OK(environment.get(moe::Key("another"), &value));
+ ASSERT_OK(environment.get(moe::Key("other"), &value));
+ std::string str;
+ ASSERT_OK(value.get(&str));
+ ASSERT_EQUALS(str, "monkeys");
+}
+
+TEST(INIConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "port=6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(INIConfigFile, StringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini", "multival = val1\nmultival = val2");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(INIConfigFile, StringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini",
+ "multival = key1=value1\n"
+ "multival = key2=value2\n"
+ "multival = key3=");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(INIConfigFile, StringMapDuplicateKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini",
+ "multival = key1=value1\n"
+ "multival = key1=value2");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 5 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(JSONConfigFile, Empty) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, EmptyObject) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{}");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, Override) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+
+ parser.setConfig("config.json", "{ port : 5 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(JSONConfigFile, UnregisteredOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 5 }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, DuplicateOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 5, port : 5 }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, TypeChecking) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining(
+ "stringVectorVal", "stringVectorVal", moe::StringVector, "StringVectorVal");
+ testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+ testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ // Test StringVector type
+ std::vector<std::string> stringVectorVal;
+
+ parser.setConfig("config.json", "{ stringVectorVal : \"scalar\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : \"true\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : \"5\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ] }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string vector type and treat it as an array of strings, even if the
+ // elements are not surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVectorVal : [ \"string\", bare, true, 1, 1.0 ] }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
+ std::vector<std::string>::iterator stringVectorValIt;
+ ASSERT_OK(value.get(&stringVectorVal));
+ stringVectorValIt = stringVectorVal.begin();
+ ASSERT_EQUALS(*stringVectorValIt, "string");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "bare");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "true");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1.0");
+
+ // Test Bool type
+ bool boolVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : \"lies\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : truth }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : 1 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a bool type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : \"true\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ boolVal : false }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, false);
+
+ // Test Double type
+ double doubleVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : \"double the monkeys\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a double type and try to convert it to a double, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : 1.5 }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : -1.5 }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : \"3.14\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 3.14);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ doubleVal : \"-3.14\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -3.14);
+
+ // Test Int type
+ int intVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : \"hungry hippos\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an int type and try to convert it to a int, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ intVal : \"-5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, -5);
+
+ // Test Long type
+ long longVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : \"in an eating race\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a long type and try to convert it to a long, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ longVal : \"-5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, -5);
+
+ // Test String type
+ std::string stringVal;
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string type and treat it as a string, even if the element is not
+ // surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : \"1000\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "1000");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : wat man }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "wat man");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ stringVal : true 1 string 1.0 }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "true 1 string 1.0");
+
+ // Test UnsignedLongLong type
+ unsigned long long unsignedLongLongVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : \"unsigned hungry hippos\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : \"-5\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned long long type and try to convert it to an unsigned long long,
+ // even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedLongLongVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
+
+ // Test Unsigned type
+ unsigned unsignedVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : \"unsigned hungry hippos\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : 1.5 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : 18446744073709551617 }"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : true }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : \"-5\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ unsignedVal : \"5\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 5U);
+
+ // Test Switch type
+ bool switchVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : \"lies\" }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : truth }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : 1 }");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a switch type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : \"true\" }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
+ ASSERT_OK(value.get(&switchVal));
+ ASSERT_EQUALS(switchVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "{ switchVal : false }");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
+ ASSERT_FALSE(switchVal);
+}
+
+TEST(JSONConfigFile, Nested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ nested : { port : 5 } }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(JSONConfigFile, Dotted) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ \"dotted.port\" : 5 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(JSONConfigFile, DottedAndNested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
+ testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ \"dottednested.var1\" : 5, dottednested : { var2 : 6 } }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
+ int var1;
+ ASSERT_OK(value.get(&var1));
+ ASSERT_EQUALS(var1, 5);
+ ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
+ int var2;
+ ASSERT_OK(value.get(&var2));
+ ASSERT_EQUALS(var2, 6);
+}
+
+TEST(JSONConfigFile, StringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ multival : [ \"val1\", \"val2\" ] }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(JSONConfigFile, StringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ "{ multival : { key1 : \"value1\", key2 : \"value2\", key3 : \"\" } }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(JSONConfigFile, StringMapDuplicateKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ multival : { key1 : \"value1\", key1 : \"value2\" } }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, StringVectorNonString) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ // NOTE: The yaml config file just reads things as strings, and it's up to us to decide what
+ // the type should be later. This means that we can't tell the difference between when a
+ // user provides a non string value or a string value in some cases.
+ parser.setConfig("config.json", "{ multival : [ 1, true ] }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "true");
+}
+
+TEST(JSONConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ port : 6 }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(Parsing, BadConfigFileOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+
+ // TODO: Should the error be in here?
+ testOpts.addOptionChaining("config", "config", moe::Int, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("1");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ConfigFromFilesystem, JSONGood) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back(TEST_CONFIG_PATH("good.json"));
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ConfigFromFilesystem, INIGood) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back(TEST_CONFIG_PATH("good.conf"));
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ConfigFromFilesystem, Empty) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back(TEST_CONFIG_PATH("empty.json"));
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(JSONConfigFile, ComposingStringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ argv.push_back("--setParameter");
+ argv.push_back("val1");
+ argv.push_back("--setParameter");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "{ setParameter : [ \"val3\", \"val4\" ] }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::vector<std::string> setParameter;
+ std::vector<std::string>::iterator setParameterit;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
+ setParameterit = setParameter.begin();
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+}
+
+TEST(JSONConfigFile, ComposingStringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ argv.push_back("--setParameter");
+ argv.push_back("key1=value1");
+ argv.push_back("--setParameter");
+ argv.push_back("key2=value2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ "{ setParameter : { key2 : \"overridden_value2\", key3 : \"value3\" } }");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::map<std::string, std::string> setParameter;
+ std::map<std::string, std::string>::iterator setParameterIt;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
+ setParameterIt = setParameter.begin();
+ ASSERT_EQUALS(setParameterIt->first, "key1");
+ ASSERT_EQUALS(setParameterIt->second, "value1");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key2");
+ ASSERT_EQUALS(setParameterIt->second, "value2");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key3");
+ ASSERT_EQUALS(setParameterIt->second, "value3");
+}
+
+TEST(INIConfigFile, ComposingStringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("default.conf");
+ argv.push_back("--setParameter");
+ argv.push_back("val1");
+ argv.push_back("--setParameter");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("default.conf", "setParameter=val3\nsetParameter=val4");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::vector<std::string> setParameter;
+ std::vector<std::string>::iterator setParameterit;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
+ setParameterit = setParameter.begin();
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+}
+
+TEST(INIConfigFile, ComposingStringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ argv.push_back("--setParameter");
+ argv.push_back("key1=value1");
+ argv.push_back("--setParameter");
+ argv.push_back("key2=value2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.ini", "setParameter=key2=overridden_value2\nsetParameter=key3=value3");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::map<std::string, std::string> setParameter;
+ std::map<std::string, std::string>::iterator setParameterIt;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
+ setParameterIt = setParameter.begin();
+ ASSERT_EQUALS(setParameterIt->first, "key1");
+ ASSERT_EQUALS(setParameterIt->second, "value1");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key2");
+ ASSERT_EQUALS(setParameterIt->second, "value2");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key3");
+ ASSERT_EQUALS(setParameterIt->second, "value3");
+}
+
+TEST(YAMLConfigFile, ComposingStringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ argv.push_back("--setParameter");
+ argv.push_back("val1");
+ argv.push_back("--setParameter");
+ argv.push_back("val2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "setParameter : \n - \"val3\"\n - \"val4\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::vector<std::string> setParameter;
+ std::vector<std::string>::iterator setParameterit;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
+ setParameterit = setParameter.begin();
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+}
+
+TEST(YAMLConfigFile, ComposingStringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap, "Multiple Values")
+ .composing();
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ argv.push_back("--setParameter");
+ argv.push_back("key1=value1");
+ argv.push_back("--setParameter");
+ argv.push_back("key2=value2");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml",
+ // NOTE: Indentation is used to determine whether an option is in a sub
+ // category, so the spaces after the newlines before key2 and key3 is
+ // significant
+ "setParameter:\n key2: \"overridden_value2\"\n key3: \"value3\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
+ std::map<std::string, std::string> setParameter;
+ std::map<std::string, std::string>::iterator setParameterIt;
+ ASSERT_OK(value.get(&setParameter));
+ ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
+ setParameterIt = setParameter.begin();
+ ASSERT_EQUALS(setParameterIt->first, "key1");
+ ASSERT_EQUALS(setParameterIt->second, "value1");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key2");
+ ASSERT_EQUALS(setParameterIt->second, "value2");
+ setParameterIt++;
+ ASSERT_EQUALS(setParameterIt->first, "key3");
+ ASSERT_EQUALS(setParameterIt->second, "value3");
+}
+
+TEST(LegacyInterface, Good) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_TRUE(environment.count("port"));
+ try {
int port;
- ASSERT_OK(value.get(&port));
+ port = environment["port"].as<int>();
ASSERT_EQUALS(port, 5);
- }
-
- TEST(INIConfigFile, Empty) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(INIConfigFile, Override) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "port=5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(INIConfigFile, Comments) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
- testOpts.addOptionChaining("str", "str", moe::String, "String");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "# port=5\nstr=NotCommented");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_NOT_OK(environment.get(moe::Key("port"), &value));
- ASSERT_OK(environment.get(moe::Key("str"), &value));
- std::string str;
- ASSERT_OK(value.get(&str));
- ASSERT_EQUALS(str, "NotCommented");
- }
-
- // Ensure switches in INI config files have the correct semantics.
- //
- // Switches have the following semantics:
- // - Present on the command line -> set to true
- // - Present in the config file -> set to value in config file
- // - Present in the config file with no value (INI only) -> set to true
- // - Not present -> not set to any value
- TEST(INIConfigFile, Switches) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("switch1", "switch1", moe::Switch, "switch1");
- testOpts.addOptionChaining("switch2", "switch2", moe::Switch, "switch2");
- testOpts.addOptionChaining("switch3", "switch3", moe::Switch, "switch3");
- testOpts.addOptionChaining("switch4", "switch4", moe::Switch, "switch4");
- testOpts.addOptionChaining("switch5", "switch5", moe::Switch, "switch5");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- argv.push_back("--switch1");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "switch2=true\nswitch3=false\nswitch5=");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- bool switch1;
- ASSERT_OK(environment.get(moe::Key("switch1"), &switch1));
- ASSERT_TRUE(switch1);
- bool switch2;
- ASSERT_OK(environment.get(moe::Key("switch2"), &switch2));
- ASSERT_TRUE(switch2);
- bool switch3;
- ASSERT_OK(environment.get(moe::Key("switch3"), &switch3));
- ASSERT_FALSE(switch3);
- bool switch4;
- ASSERT_NOT_OK(environment.get(moe::Key("switch4"), &switch4));
- bool switch5;
- ASSERT_OK(environment.get(moe::Key("switch5"), &switch5));
- ASSERT_TRUE(switch5);
- }
-
- TEST(INIConfigFile, Monkeys) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("this", "this", moe::Switch, "This");
- testOpts.addOptionChaining("that", "that", moe::Switch, "That");
- testOpts.addOptionChaining("another", "another", moe::String, "Another");
- testOpts.addOptionChaining("other", "other", moe::String, "Other");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf",
- "\t this = false \n#that = true\n #another = whocares"
- "\n\n other = monkeys ");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("this"), &value));
- bool thisValue;
- ASSERT_OK(value.get(&thisValue));
- ASSERT_FALSE(thisValue);
- ASSERT_NOT_OK(environment.get(moe::Key("that"), &value));
- ASSERT_NOT_OK(environment.get(moe::Key("another"), &value));
- ASSERT_OK(environment.get(moe::Key("other"), &value));
- std::string str;
- ASSERT_OK(value.get(&str));
- ASSERT_EQUALS(str, "monkeys");
- }
-
- TEST(INIConfigFile, DefaultValueOverride) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "port=6");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(INIConfigFile, StringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini", "multival = val1\nmultival = val2");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(INIConfigFile, StringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini",
- "multival = key1=value1\n"
- "multival = key2=value2\n"
- "multival = key3=");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(INIConfigFile, StringMapDuplicateKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini",
- "multival = key1=value1\n"
- "multival = key1=value2");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 5 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(JSONConfigFile, Empty) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, EmptyObject) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{}");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, Override) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
-
- parser.setConfig("config.json", "{ port : 5 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(JSONConfigFile, UnregisteredOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 5 }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, DuplicateOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 5, port : 5 }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, TypeChecking) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("stringVectorVal", "stringVectorVal", moe::StringVector,
- "StringVectorVal");
- testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
- testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- // Test StringVector type
- std::vector<std::string> stringVectorVal;
-
- parser.setConfig("config.json", "{ stringVectorVal : \"scalar\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : \"true\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : \"5\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ] }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string vector type and treat it as an array of strings, even if the
- // elements are not surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVectorVal : [ \"string\", bare, true, 1, 1.0 ] }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
- std::vector<std::string>::iterator stringVectorValIt;
- ASSERT_OK(value.get(&stringVectorVal));
- stringVectorValIt = stringVectorVal.begin();
- ASSERT_EQUALS(*stringVectorValIt, "string");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "bare");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "true");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1.0");
-
- // Test Bool type
- bool boolVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : \"lies\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : truth }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : 1 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a bool type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : \"true\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ boolVal : false }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, false);
-
- // Test Double type
- double doubleVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : \"double the monkeys\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a double type and try to convert it to a double, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : 1.5 }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : -1.5 }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : \"3.14\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 3.14);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ doubleVal : \"-3.14\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -3.14);
-
- // Test Int type
- int intVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : \"hungry hippos\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an int type and try to convert it to a int, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ intVal : \"-5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, -5);
-
- // Test Long type
- long longVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : \"in an eating race\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a long type and try to convert it to a long, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ longVal : \"-5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, -5);
-
- // Test String type
- std::string stringVal;
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string type and treat it as a string, even if the element is not
- // surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : \"1000\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "1000");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : wat man }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "wat man");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "{ stringVal : true 1 string 1.0 }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "true 1 string 1.0");
-
- // Test UnsignedLongLong type
- unsigned long long unsignedLongLongVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : \"unsigned hungry hippos\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json",
- "{ unsignedLongLongVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : \"-5\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned long long type and try to convert it to an unsigned long long,
- // even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedLongLongVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
-
- // Test Unsigned type
- unsigned unsignedVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : \"unsigned hungry hippos\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : 1.5 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : 18446744073709551617 }"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : true }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : \"-5\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ unsignedVal : \"5\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 5U);
-
- // Test Switch type
- bool switchVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : \"lies\" }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : truth }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : 1 }");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a switch type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : \"true\" }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
- ASSERT_OK(value.get(&switchVal));
- ASSERT_EQUALS(switchVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "{ switchVal : false }");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
- ASSERT_FALSE(switchVal);
- }
-
- TEST(JSONConfigFile, Nested) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ nested : { port : 5 } }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(JSONConfigFile, Dotted) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ \"dotted.port\" : 5 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(JSONConfigFile, DottedAndNested) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
- testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ \"dottednested.var1\" : 5, dottednested : { var2 : 6 } }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
- int var1;
- ASSERT_OK(value.get(&var1));
- ASSERT_EQUALS(var1, 5);
- ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
- int var2;
- ASSERT_OK(value.get(&var2));
- ASSERT_EQUALS(var2, 6);
- }
-
- TEST(JSONConfigFile, StringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ multival : [ \"val1\", \"val2\" ] }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(JSONConfigFile, StringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ multival : { key1 : \"value1\", key2 : \"value2\", key3 : \"\" } }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(JSONConfigFile, StringMapDuplicateKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ multival : { key1 : \"value1\", key1 : \"value2\" } }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, StringVectorNonString) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- // NOTE: The yaml config file just reads things as strings, and it's up to us to decide what
- // the type should be later. This means that we can't tell the difference between when a
- // user provides a non string value or a string value in some cases.
- parser.setConfig("config.json", "{ multival : [ 1, true ] }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "true");
- }
-
- TEST(JSONConfigFile, DefaultValueOverride) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ port : 6 }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(Parsing, BadConfigFileOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
-
- // TODO: Should the error be in here?
- testOpts.addOptionChaining("config", "config", moe::Int, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("1");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ConfigFromFilesystem, JSONGood) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back(TEST_CONFIG_PATH("good.json"));
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ConfigFromFilesystem, INIGood) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back(TEST_CONFIG_PATH("good.conf"));
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ConfigFromFilesystem, Empty) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back(TEST_CONFIG_PATH("empty.json"));
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(JSONConfigFile, ComposingStringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- argv.push_back("--setParameter");
- argv.push_back("val1");
- argv.push_back("--setParameter");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "{ setParameter : [ \"val3\", \"val4\" ] }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::vector<std::string> setParameter;
- std::vector<std::string>::iterator setParameterit;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
- setParameterit = setParameter.begin();
- ASSERT_EQUALS(*setParameterit, "val3");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val4");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val1");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val2");
- }
-
- TEST(JSONConfigFile, ComposingStringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- argv.push_back("--setParameter");
- argv.push_back("key1=value1");
- argv.push_back("--setParameter");
- argv.push_back("key2=value2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- "{ setParameter : { key2 : \"overridden_value2\", key3 : \"value3\" } }");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::map<std::string, std::string> setParameter;
- std::map<std::string, std::string>::iterator setParameterIt;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
- setParameterIt = setParameter.begin();
- ASSERT_EQUALS(setParameterIt->first, "key1");
- ASSERT_EQUALS(setParameterIt->second, "value1");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key2");
- ASSERT_EQUALS(setParameterIt->second, "value2");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key3");
- ASSERT_EQUALS(setParameterIt->second, "value3");
- }
-
- TEST(INIConfigFile, ComposingStringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("default.conf");
- argv.push_back("--setParameter");
- argv.push_back("val1");
- argv.push_back("--setParameter");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("default.conf", "setParameter=val3\nsetParameter=val4");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::vector<std::string> setParameter;
- std::vector<std::string>::iterator setParameterit;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
- setParameterit = setParameter.begin();
- ASSERT_EQUALS(*setParameterit, "val3");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val4");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val1");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val2");
- }
-
- TEST(INIConfigFile, ComposingStringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- argv.push_back("--setParameter");
- argv.push_back("key1=value1");
- argv.push_back("--setParameter");
- argv.push_back("key2=value2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.ini",
- "setParameter=key2=overridden_value2\nsetParameter=key3=value3");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::map<std::string, std::string> setParameter;
- std::map<std::string, std::string>::iterator setParameterIt;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
- setParameterIt = setParameter.begin();
- ASSERT_EQUALS(setParameterIt->first, "key1");
- ASSERT_EQUALS(setParameterIt->second, "value1");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key2");
- ASSERT_EQUALS(setParameterIt->second, "value2");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key3");
- ASSERT_EQUALS(setParameterIt->second, "value3");
- }
-
- TEST(YAMLConfigFile, ComposingStringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- argv.push_back("--setParameter");
- argv.push_back("val1");
- argv.push_back("--setParameter");
- argv.push_back("val2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "setParameter : \n - \"val3\"\n - \"val4\"");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::vector<std::string> setParameter;
- std::vector<std::string>::iterator setParameterit;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(4));
- setParameterit = setParameter.begin();
- ASSERT_EQUALS(*setParameterit, "val3");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val4");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val1");
- setParameterit++;
- ASSERT_EQUALS(*setParameterit, "val2");
- }
-
- TEST(YAMLConfigFile, ComposingStringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("setParameter", "setParameter", moe::StringMap,
- "Multiple Values").composing();
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- argv.push_back("--setParameter");
- argv.push_back("key1=value1");
- argv.push_back("--setParameter");
- argv.push_back("key2=value2");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- // NOTE: Indentation is used to determine whether an option is in a sub
- // category, so the spaces after the newlines before key2 and key3 is
- // significant
- "setParameter:\n key2: \"overridden_value2\"\n key3: \"value3\"");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("setParameter"), &value));
- std::map<std::string, std::string> setParameter;
- std::map<std::string, std::string>::iterator setParameterIt;
- ASSERT_OK(value.get(&setParameter));
- ASSERT_EQUALS(setParameter.size(), static_cast<size_t>(3));
- setParameterIt = setParameter.begin();
- ASSERT_EQUALS(setParameterIt->first, "key1");
- ASSERT_EQUALS(setParameterIt->second, "value1");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key2");
- ASSERT_EQUALS(setParameterIt->second, "value2");
- setParameterIt++;
- ASSERT_EQUALS(setParameterIt->first, "key3");
- ASSERT_EQUALS(setParameterIt->second, "value3");
- }
-
- TEST(LegacyInterface, Good) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_TRUE(environment.count("port"));
- try {
- int port;
- port = environment["port"].as<int>();
- ASSERT_EQUALS(port, 5);
- }
- catch ( std::exception &e ) {
- FAIL(e.what());
+ } catch (std::exception& e) {
+ FAIL(e.what());
+ }
+}
+
+TEST(LegacyInterface, NotSpecified) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_FALSE(environment.count("port"));
+}
+
+TEST(LegacyInterface, BadType) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_TRUE(environment.count("port"));
+ std::string port;
+ try {
+ port = environment["port"].as<std::string>();
+ FAIL("Expected exception trying to convert int to type string");
+ } catch (std::exception& e) {
+ }
+}
+
+TEST(ChainingInterface, GoodReference) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ // This test is to make sure our reference stays good even after we add more options. This
+ // would not be true if we were using a std::vector in our option section which may need to
+ // be moved and resized.
+ moe::OptionDescription& optionRef =
+ testOpts.addOptionChaining("ref", "ref", moe::String, "Save this Reference");
+ int i;
+ for (i = 0; i < 100; i++) {
+ ::mongo::StringBuilder sb;
+ sb << "filler" << i;
+ testOpts.addOptionChaining(sb.str(), sb.str(), moe::String, "Filler Option");
+ }
+ moe::Value defaultVal(std::string("default"));
+ moe::Value implicitVal(std::string("implicit"));
+ optionRef.hidden().setDefault(defaultVal);
+ optionRef.setImplicit(implicitVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ bool foundRef = false;
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "ref") {
+ ASSERT_EQUALS(iterator->_singleName, "ref");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Save this Reference");
+ ASSERT_EQUALS(iterator->_isVisible, false);
+ ASSERT_TRUE(iterator->_default.equal(defaultVal));
+ ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ foundRef = true;
}
}
-
- TEST(LegacyInterface, NotSpecified) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_FALSE(environment.count("port"));
- }
-
- TEST(LegacyInterface, BadType) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_TRUE(environment.count("port"));
- std::string port;
- try {
- port = environment["port"].as<std::string>();
- FAIL("Expected exception trying to convert int to type string");
- }
- catch ( std::exception &e ) {
- }
- }
-
- TEST(ChainingInterface, GoodReference) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- // This test is to make sure our reference stays good even after we add more options. This
- // would not be true if we were using a std::vector in our option section which may need to
- // be moved and resized.
- moe::OptionDescription& optionRef = testOpts.addOptionChaining("ref", "ref", moe::String,
- "Save this Reference");
- int i;
- for (i = 0; i < 100; i++) {
+ if (!foundRef) {
+ FAIL("Could not find \"ref\" options that we registered");
+ }
+}
+
+TEST(ChainingInterface, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("basic", "basic", moe::String, "Default Option");
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "basic") {
+ ASSERT_EQUALS(iterator->_singleName, "basic");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Default Option");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
::mongo::StringBuilder sb;
- sb << "filler" << i;
- testOpts.addOptionChaining(sb.str(), sb.str(), moe::String, "Filler Option");
- }
- moe::Value defaultVal(std::string("default"));
- moe::Value implicitVal(std::string("implicit"));
- optionRef.hidden().setDefault(defaultVal);
- optionRef.setImplicit(implicitVal);
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- bool foundRef = false;
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "ref") {
- ASSERT_EQUALS(iterator->_singleName, "ref");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Save this Reference");
- ASSERT_EQUALS(iterator->_isVisible, false);
- ASSERT_TRUE(iterator->_default.equal(defaultVal));
- ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
- ASSERT_EQUALS(iterator->_isComposing, false);
- foundRef = true;
- }
- }
- if (!foundRef) {
- FAIL("Could not find \"ref\" options that we registered");
- }
- }
-
- TEST(ChainingInterface, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("basic",
- "basic",
- moe::String,
- "Default Option");
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "basic") {
- ASSERT_EQUALS(iterator->_singleName, "basic");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Default Option");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, Hidden) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("hidden",
- "hidden",
- moe::String,
- "Hidden Option").hidden();
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "hidden") {
- ASSERT_EQUALS(iterator->_singleName, "hidden");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Hidden Option");
- ASSERT_EQUALS(iterator->_isVisible, false);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, Hidden) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("hidden", "hidden", moe::String, "Hidden Option").hidden();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "hidden") {
+ ASSERT_EQUALS(iterator->_singleName, "hidden");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Hidden Option");
+ ASSERT_EQUALS(iterator->_isVisible, false);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, DefaultValue) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::Value defaultVal(std::string("default"));
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("default",
- "default",
- moe::String,
- "Option With Default Value").setDefault(defaultVal);
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "default") {
- ASSERT_EQUALS(iterator->_singleName, "default");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Option With Default Value");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.equal(defaultVal));
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, DefaultValue) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::Value defaultVal(std::string("default"));
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("default", "default", moe::String, "Option With Default Value")
+ .setDefault(defaultVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "default") {
+ ASSERT_EQUALS(iterator->_singleName, "default");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Option With Default Value");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.equal(defaultVal));
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, ImplicitValue) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::Value implicitVal(std::string("implicit"));
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("implicit",
- "implicit",
- moe::String,
- "Option With Implicit Value").setImplicit(implicitVal);
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "implicit") {
- ASSERT_EQUALS(iterator->_singleName, "implicit");
- ASSERT_EQUALS(iterator->_type, moe::String);
- ASSERT_EQUALS(iterator->_description, "Option With Implicit Value");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
- ASSERT_EQUALS(iterator->_isComposing, false);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, ImplicitValue) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::Value implicitVal(std::string("implicit"));
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("implicit", "implicit", moe::String, "Option With Implicit Value")
+ .setImplicit(implicitVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "implicit") {
+ ASSERT_EQUALS(iterator->_singleName, "implicit");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Option With Implicit Value");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, Composing) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("setParameter",
- "setParameter",
- moe::StringVector,
- "Multiple Values").composing();
-
- std::vector<moe::OptionDescription> options_vector;
- ASSERT_OK(testOpts.getAllOptions(&options_vector));
-
- for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
- iterator != options_vector.end(); iterator++) {
-
- if (iterator->_dottedName == "setParameter") {
- ASSERT_EQUALS(iterator->_singleName, "setParameter");
- ASSERT_EQUALS(iterator->_type, moe::StringVector);
- ASSERT_EQUALS(iterator->_description, "Multiple Values");
- ASSERT_EQUALS(iterator->_isVisible, true);
- ASSERT_TRUE(iterator->_default.isEmpty());
- ASSERT_TRUE(iterator->_implicit.isEmpty());
- ASSERT_EQUALS(iterator->_isComposing, true);
- }
- else {
- ::mongo::StringBuilder sb;
- sb << "Found extra option: " << iterator->_dottedName <<
- " which we did not register";
- FAIL(sb.str());
- }
+}
+
+TEST(ChainingInterface, Composing) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("setParameter", "setParameter", moe::StringVector, "Multiple Values")
+ .composing();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for (std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end();
+ iterator++) {
+ if (iterator->_dottedName == "setParameter") {
+ ASSERT_EQUALS(iterator->_singleName, "setParameter");
+ ASSERT_EQUALS(iterator->_type, moe::StringVector);
+ ASSERT_EQUALS(iterator->_description, "Multiple Values");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, true);
+ } else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName << " which we did not register";
+ FAIL(sb.str());
}
}
-
- TEST(ChainingInterface, Positional) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- }
-
- TEST(ChainingInterface, PositionalTooMany) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("extrapositional");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional");
- argv.push_back("--port");
- argv.push_back("5");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::string positional;
- ASSERT_OK(value.get(&positional));
- ASSERT_EQUALS(positional, "positional");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ChainingInterface, PositionalMultiple) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- }
-
- TEST(ChainingInterface, PositionalMultipleExtra) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalMultipleUnlimited) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, -1);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional3");
- argv.push_back("positional4");
- argv.push_back("positional5");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional3");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional4");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional5");
- }
-
- TEST(ChainingInterface, PositionalMultipleAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
- .positional(1, 2);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("positional2");
- std::map<std::string, std::string> env_map;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("positional"), &value));
- std::vector<std::string> positional;
- ASSERT_OK(value.get(&positional));
- std::vector<std::string>::iterator positionalit = positional.begin();
- ASSERT_EQUALS(*positionalit, "positional1");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional2");
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ChainingInterface, PositionalSingleMultipleUnlimitedAndFlag) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional2", "positional2", moe::StringVector, "Positional")
- .positional(2, 3);
- testOpts.addOptionChaining("positional3", "positional3", moe::StringVector, "Positional")
- .positional(4, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("positional1");
- argv.push_back("positional2");
- argv.push_back("positional3");
- argv.push_back("positional4");
- argv.push_back("positional5");
- argv.push_back("positional6");
- argv.push_back("--port");
- argv.push_back("5");
- argv.push_back("positional7");
- argv.push_back("positional8");
- argv.push_back("positional9");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("positional1"), &value));
- std::string positionalSingle;
- ASSERT_OK(value.get(&positionalSingle));
- ASSERT_EQUALS(positionalSingle, "positional1");
-
- ASSERT_OK(environment.get(moe::Key("positional2"), &value));
- std::vector<std::string> positionalMultiple;
- ASSERT_OK(value.get(&positionalMultiple));
- positionalit = positionalMultiple.begin();
- ASSERT_EQUALS(*positionalit, "positional2");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional3");
-
- ASSERT_OK(environment.get(moe::Key("positional3"), &value));
- std::vector<std::string> positionalUnlimited;
- ASSERT_OK(value.get(&positionalUnlimited));
- positionalit = positionalUnlimited.begin();
- ASSERT_EQUALS(*positionalit, "positional4");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional5");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional6");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional7");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional8");
- positionalit++;
- ASSERT_EQUALS(*positionalit, "positional9");
-
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(ChainingInterface, PositionalHoleInRange) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(3, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalOverlappingRange) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(1, 2);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalOverlappingRangeInfinite) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, 1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(1, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(ChainingInterface, PositionalMultipleInfinite) {
- moe::OptionsParser parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
- .positional(1, -1);
- testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
- .positional(3, -1);
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- std::map<std::string, std::string> env_map;
-
- moe::Value value;
- std::vector<std::string>::iterator positionalit;
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(OptionSources, SourceCommandLine) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceCommandLine);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(OptionSources, SourceINIConfig) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceINIConfig);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- }
-
- TEST(OptionSources, SourceYAMLConfig) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceYAMLConfig);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"allowed\" }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(OptionSources, SourceAllConfig) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceAllConfig);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("disallowed");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"allowed\" }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
- }
-
- TEST(OptionSources, SourceAllLegacy) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceAllLegacy);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
- }
-
- TEST(OptionSources, SourceAll) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
- std::vector<std::string> argv;
- std::map<std::string, std::string> env_map;
- std::string parameter;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
- .setSources(moe::SourceAll);
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--parameter");
- argv.push_back("allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
-
- parser.setConfig("config.json", "{ parameter : \"allowed\" }");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- ASSERT_OK(value.get(&parameter));
- ASSERT_EQUALS(parameter, "allowed");
-
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "parameter=allowed");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("parameter"), &value));
- 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("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);
- }
-
- TEST(Constraints, MutuallyExclusiveConstraint) {
- 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("option1", "option1", moe::Switch, "Option1")
- .incompatibleWith("section.option2");
- testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option1");
- argv.push_back("--option2");
-
- 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("--option1");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("option1"), &value));
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
- }
-
- TEST(Constraints, RequiresOtherConstraint) {
- 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("option1", "option1", moe::Switch, "Option1")
- .requires("section.option2");
- testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option1");
-
- 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("--option1");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- ASSERT_OK(environment.get(moe::Key("option1"), &value));
- ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
-
- environment = moe::Environment();
- argv.clear();
- argv.push_back("binaryname");
- argv.push_back("--option2");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.validate());;
- 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;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(YAMLConfigFile, Empty) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, Override) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- argv.push_back("--port");
- argv.push_back("6");
- std::map<std::string, std::string> env_map;
-
-
- parser.setConfig("config.yaml", "port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(YAMLConfigFile, UnregisteredOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 5");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, DuplicateOption) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 5\nport: 5");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, TypeChecking) {
- OptionsParserTester parser;
- moe::Environment environment;
- moe::Value value;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("stringVectorVal", "stringVectorVal", moe::StringVector,
- "StringVectorVal");
- testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
- testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- // Test StringVector type
- std::vector<std::string> stringVectorVal;
-
- parser.setConfig("config.json", "stringVectorVal : \"scalar\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : \"true\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : \"5\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ]");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string vector type and treat it as an array of strings, even if the
- // elements are not surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVectorVal : [ \"string\", bare, true, 1, 1.0 ]");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
- std::vector<std::string>::iterator stringVectorValIt;
- ASSERT_OK(value.get(&stringVectorVal));
- stringVectorValIt = stringVectorVal.begin();
- ASSERT_EQUALS(*stringVectorValIt, "string");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "bare");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "true");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1");
- stringVectorValIt++;
- ASSERT_EQUALS(*stringVectorValIt, "1.0");
-
- // Test Bool type
- bool boolVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : \"lies\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : truth");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : 1");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a bool type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : \"true\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "boolVal : false");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
- ASSERT_OK(value.get(&boolVal));
- ASSERT_EQUALS(boolVal, false);
-
- // Test Double type
- double doubleVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : \"double the monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a double type and try to convert it to a double, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : 1.5");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : -1.5");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -1.5);
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : \"3.14\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 3.14);
- environment = moe::Environment();
- parser.setConfig("config.json", "doubleVal : \"-3.14\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, -3.14);
-
- // Test Int type
- int intVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : \"hungry hippos\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an int type and try to convert it to a int, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "intVal : \"-5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, -5);
-
- // Test Long type
- long longVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : \"in an eating race\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a long type and try to convert it to a long, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 5);
-
- environment = moe::Environment();
- parser.setConfig("config.json", "longVal : \"-5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, -5);
-
- // Test String type
- std::string stringVal;
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a string type and treat it as a string, even if the element is not
- // surrounded by quotes
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal :");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal : \"1000\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "1000");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal : wat man");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "wat man");
-
- environment = moe::Environment();
- parser.setConfig("config.json", "stringVal : true 1 string 1.0");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
- ASSERT_OK(value.get(&stringVal));
- ASSERT_EQUALS(stringVal, "true 1 string 1.0");
-
- // Test UnsignedLongLong type
- unsigned long long unsignedLongLongVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : \"unsigned hungry hippos\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json",
- "unsignedLongLongVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : \"-5\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned long long type and try to convert it to an unsigned long long,
- // even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedLongLongVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
-
- // Test Unsigned type
- unsigned unsignedVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : \"unsigned hungry hippos\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : 1.5");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : 18446744073709551617"); // 2^64 + 1
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : true");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : \"-5\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "unsignedVal : \"5\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 5U);
-
- // Test Switch type
- bool switchVal;
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : \"lies\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : truth");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : 1");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // The YAML parser treats everything as a string, so we just take anything that was
- // specified as a switch type and try to convert it to a bool, even if it was quoted
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : \"true\"");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
- ASSERT_OK(value.get(&switchVal));
- ASSERT_EQUALS(switchVal, true);
- environment = moe::Environment();
- parser.setConfig("config.json", "switchVal : false");
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
- ASSERT_FALSE(switchVal);
- }
-
- TEST(YAMLConfigFile, Nested) {
+}
+
+TEST(ChainingInterface, Positional) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+}
+
+TEST(ChainingInterface, PositionalTooMany) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("extrapositional");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional");
+ argv.push_back("--port");
+ argv.push_back("5");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::string positional;
+ ASSERT_OK(value.get(&positional));
+ ASSERT_EQUALS(positional, "positional");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ChainingInterface, PositionalMultiple) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+}
+
+TEST(ChainingInterface, PositionalMultipleExtra) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalMultipleUnlimited) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, -1);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional3");
+ argv.push_back("positional4");
+ argv.push_back("positional5");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional3");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional4");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional5");
+}
+
+TEST(ChainingInterface, PositionalMultipleAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional", "positional", moe::StringVector, "Positional")
+ .positional(1, 2);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("positional2");
+ std::map<std::string, std::string> env_map;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("positional"), &value));
+ std::vector<std::string> positional;
+ ASSERT_OK(value.get(&positional));
+ std::vector<std::string>::iterator positionalit = positional.begin();
+ ASSERT_EQUALS(*positionalit, "positional1");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional2");
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ChainingInterface, PositionalSingleMultipleUnlimitedAndFlag) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional2", "positional2", moe::StringVector, "Positional")
+ .positional(2, 3);
+ testOpts.addOptionChaining("positional3", "positional3", moe::StringVector, "Positional")
+ .positional(4, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("positional1");
+ argv.push_back("positional2");
+ argv.push_back("positional3");
+ argv.push_back("positional4");
+ argv.push_back("positional5");
+ argv.push_back("positional6");
+ argv.push_back("--port");
+ argv.push_back("5");
+ argv.push_back("positional7");
+ argv.push_back("positional8");
+ argv.push_back("positional9");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("positional1"), &value));
+ std::string positionalSingle;
+ ASSERT_OK(value.get(&positionalSingle));
+ ASSERT_EQUALS(positionalSingle, "positional1");
+
+ ASSERT_OK(environment.get(moe::Key("positional2"), &value));
+ std::vector<std::string> positionalMultiple;
+ ASSERT_OK(value.get(&positionalMultiple));
+ positionalit = positionalMultiple.begin();
+ ASSERT_EQUALS(*positionalit, "positional2");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional3");
+
+ ASSERT_OK(environment.get(moe::Key("positional3"), &value));
+ std::vector<std::string> positionalUnlimited;
+ ASSERT_OK(value.get(&positionalUnlimited));
+ positionalit = positionalUnlimited.begin();
+ ASSERT_EQUALS(*positionalit, "positional4");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional5");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional6");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional7");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional8");
+ positionalit++;
+ ASSERT_EQUALS(*positionalit, "positional9");
+
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(ChainingInterface, PositionalHoleInRange) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(3, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalOverlappingRange) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(1, 2);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalOverlappingRangeInfinite) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, 1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(1, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(ChainingInterface, PositionalMultipleInfinite) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("positional1", "positional1", moe::String, "Positional")
+ .positional(1, -1);
+ testOpts.addOptionChaining("positional3", "positional2", moe::StringVector, "Positional")
+ .positional(3, -1);
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ std::map<std::string, std::string> env_map;
+
+ moe::Value value;
+ std::vector<std::string>::iterator positionalit;
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionSources, SourceCommandLine) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceCommandLine);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionSources, SourceINIConfig) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceINIConfig);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(OptionSources, SourceYAMLConfig) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceYAMLConfig);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"allowed\" }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionSources, SourceAllConfig) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceAllConfig);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("disallowed");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"allowed\" }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(OptionSources, SourceAllLegacy) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceAllLegacy);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"disallowed\" }");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+}
+
+TEST(OptionSources, SourceAll) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+ std::vector<std::string> argv;
+ std::map<std::string, std::string> env_map;
+ std::string parameter;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("parameter", "parameter", moe::String, "Parameter")
+ .setSources(moe::SourceAll);
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--parameter");
+ argv.push_back("allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+
+ parser.setConfig("config.json", "{ parameter : \"allowed\" }");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ ASSERT_OK(value.get(&parameter));
+ ASSERT_EQUALS(parameter, "allowed");
+
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "parameter=allowed");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("parameter"), &value));
+ 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("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);
+}
+
+TEST(Constraints, MutuallyExclusiveConstraint) {
+ 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("option1", "option1", moe::Switch, "Option1")
+ .incompatibleWith("section.option2");
+ testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option1");
+ argv.push_back("--option2");
+
+ 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("--option1");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("option1"), &value));
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
+}
+
+TEST(Constraints, RequiresOtherConstraint) {
+ 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("option1", "option1", moe::Switch, "Option1")
+ .requires("section.option2");
+ testOpts.addOptionChaining("section.option2", "option2", moe::Switch, "Option2");
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option1");
+
+ 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("--option1");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ ASSERT_OK(environment.get(moe::Key("option1"), &value));
+ ASSERT_OK(environment.get(moe::Key("section.option2"), &value));
+
+ environment = moe::Environment();
+ argv.clear();
+ argv.push_back("binaryname");
+ argv.push_back("--option2");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.validate());
+ ;
+ 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;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(YAMLConfigFile, Empty) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, Override) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ argv.push_back("--port");
+ argv.push_back("6");
+ std::map<std::string, std::string> env_map;
+
+
+ parser.setConfig("config.yaml", "port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(YAMLConfigFile, UnregisteredOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 5");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, DuplicateOption) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 5\nport: 5");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, TypeChecking) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+ moe::Value value;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining(
+ "stringVectorVal", "stringVectorVal", moe::StringVector, "StringVectorVal");
+ testOpts.addOptionChaining("boolVal", "boolVal", moe::Bool, "BoolVal");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining("stringVal", "stringVal", moe::String, "StringVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+ testOpts.addOptionChaining("switchVal", "switchVal", moe::Switch, "SwitchVal");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ // Test StringVector type
+ std::vector<std::string> stringVectorVal;
+
+ parser.setConfig("config.json", "stringVectorVal : \"scalar\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : \"true\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : \"5\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : [ [ \"string\" ], true, 1, 1.0 ]");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string vector type and treat it as an array of strings, even if the
+ // elements are not surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVectorVal : [ \"string\", bare, true, 1, 1.0 ]");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVectorVal"), &value));
+ std::vector<std::string>::iterator stringVectorValIt;
+ ASSERT_OK(value.get(&stringVectorVal));
+ stringVectorValIt = stringVectorVal.begin();
+ ASSERT_EQUALS(*stringVectorValIt, "string");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "bare");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "true");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1");
+ stringVectorValIt++;
+ ASSERT_EQUALS(*stringVectorValIt, "1.0");
+
+ // Test Bool type
+ bool boolVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : \"lies\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : truth");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : 1");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a bool type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : \"true\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "boolVal : false");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("boolVal"), &value));
+ ASSERT_OK(value.get(&boolVal));
+ ASSERT_EQUALS(boolVal, false);
+
+ // Test Double type
+ double doubleVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : \"double the monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a double type and try to convert it to a double, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : 1.5");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : -1.5");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -1.5);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : \"3.14\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 3.14);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "doubleVal : \"-3.14\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, -3.14);
+
+ // Test Int type
+ int intVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : \"hungry hippos\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an int type and try to convert it to a int, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "intVal : \"-5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, -5);
+
+ // Test Long type
+ long longVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : \"in an eating race\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a long type and try to convert it to a long, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 5);
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "longVal : \"-5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, -5);
+
+ // Test String type
+ std::string stringVal;
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a string type and treat it as a string, even if the element is not
+ // surrounded by quotes
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal :");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal : \"1000\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "1000");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal : wat man");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "wat man");
+
+ environment = moe::Environment();
+ parser.setConfig("config.json", "stringVal : true 1 string 1.0");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("stringVal"), &value));
+ ASSERT_OK(value.get(&stringVal));
+ ASSERT_EQUALS(stringVal, "true 1 string 1.0");
+
+ // Test UnsignedLongLong type
+ unsigned long long unsignedLongLongVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : \"unsigned hungry hippos\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : \"-5\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned long long type and try to convert it to an unsigned long long,
+ // even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedLongLongVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 5ULL);
+
+ // Test Unsigned type
+ unsigned unsignedVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : \"unsigned hungry hippos\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : 1.5");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : 18446744073709551617"); // 2^64 + 1
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : true");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : \"-5\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as an unsigned type and try to convert it to an unsigned, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "unsignedVal : \"5\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 5U);
+
+ // Test Switch type
+ bool switchVal;
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : \"lies\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : truth");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : 1");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // The YAML parser treats everything as a string, so we just take anything that was
+ // specified as a switch type and try to convert it to a bool, even if it was quoted
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : \"true\"");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &value));
+ ASSERT_OK(value.get(&switchVal));
+ ASSERT_EQUALS(switchVal, true);
+ environment = moe::Environment();
+ parser.setConfig("config.json", "switchVal : false");
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("switchVal"), &switchVal));
+ ASSERT_FALSE(switchVal);
+}
+
+TEST(YAMLConfigFile, Nested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "nested:\n port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(YAMLConfigFile, Dotted) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "dotted.port: 5");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+}
+
+TEST(YAMLConfigFile, DottedAndNested) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
+ testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "dottednested.var1: 5\ndottednested:\n var2: 6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
+ int var1;
+ ASSERT_OK(value.get(&var1));
+ ASSERT_EQUALS(var1, 5);
+ ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
+ int var2;
+ ASSERT_OK(value.get(&var2));
+ ASSERT_EQUALS(var2, 6);
+}
+
+// If configuration file contains a deprecated dotted name, value will be set in the
+// environment with the canonical name as the key. Deprecated dotted name will not appear
+// in result environment.
+TEST(YAMLConfigFile, DeprecatedDottedNameDeprecatedOnly) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", "dotted.deprecated");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "dotted.deprecated: 6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("dotted.canonical"), &value));
+ int var1;
+ ASSERT_OK(value.get(&var1));
+ ASSERT_EQUALS(var1, 6);
+ ASSERT_FALSE(environment.count(moe::Key("dotted.deprecated")));
+}
+
+// Deprecated dotted name cannot be the same as the canonical name.
+TEST(YAMLConfigFile, DeprecatedDottedNameSameAsCanonicalDottedName) {
+ moe::OptionSection testOpts;
+ ASSERT_THROWS(testOpts.addOptionChaining(
+ "dotted.canonical", "var1", moe::Int, "Var1", "dotted.canonical"),
+ ::mongo::DBException);
+}
+
+// Deprecated dotted name cannot be the empty string.
+TEST(YAMLConfigFile, DeprecatedDottedNameEmptyString) {
+ moe::OptionSection testOpts;
+ ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", ""),
+ ::mongo::DBException);
+}
+
+// Deprecated dotted name cannot be the same as another option's dotted name.
+TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDottedName) {
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1");
+ ASSERT_THROWS(testOpts.addOptionChaining(
+ "dotted.canonical2", "var2", moe::Int, "Var2", "dotted.canonical1"),
+ ::mongo::DBException);
+}
+
+// Deprecated dotted name cannot be the same as another option's deprecated dotted name.
+TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDeprecatedDottedName) {
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1", "dotted.deprecated1");
+ ASSERT_THROWS(testOpts.addOptionChaining(
+ "dotted.canonical2", "var2", moe::Int, "Var2", "dotted.deprecated1"),
+ ::mongo::DBException);
+}
+
+// It is an error to have both canonical and deprecated dotted names in the same
+// configuration file.
+TEST(YAMLConfigFile, DeprecatedDottedNameCanonicalAndDeprecated) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", "dotted.deprecated");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml",
+ "dotted.canonical: 5\n"
+ "dotted.deprecated: 6");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+// An option can have multiple deprecated dotted names.
+TEST(YAMLConfigFile, DeprecatedDottedNameMultipleDeprecated) {
+ std::vector<std::string> deprecatedDottedNames;
+ deprecatedDottedNames.push_back("dotted.deprecated1");
+ deprecatedDottedNames.push_back("dotted.deprecated2");
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", deprecatedDottedNames);
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+
+ // Parse 2 files - each containing a different deprecated dotted name.
+ for (std::vector<std::string>::const_iterator i = deprecatedDottedNames.begin();
+ i != deprecatedDottedNames.end();
+ ++i) {
OptionsParserTester parser;
moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("nested.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
std::map<std::string, std::string> env_map;
- parser.setConfig("config.yaml", "nested:\n port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("nested.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(YAMLConfigFile, Dotted) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "dotted.port: 5");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dotted.port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- }
-
- TEST(YAMLConfigFile, DottedAndNested) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dottednested.var1", "var1", moe::Int, "Var1");
- testOpts.addOptionChaining("dottednested.var2", "var2", moe::Int, "Var2");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "dottednested.var1: 5\ndottednested:\n var2: 6");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dottednested.var1"), &value));
- int var1;
- ASSERT_OK(value.get(&var1));
- ASSERT_EQUALS(var1, 5);
- ASSERT_OK(environment.get(moe::Key("dottednested.var2"), &value));
- int var2;
- ASSERT_OK(value.get(&var2));
- ASSERT_EQUALS(var2, 6);
- }
-
- // If configuration file contains a deprecated dotted name, value will be set in the
- // environment with the canonical name as the key. Deprecated dotted name will not appear
- // in result environment.
- TEST(YAMLConfigFile, DeprecatedDottedNameDeprecatedOnly) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- "dotted.deprecated");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "dotted.deprecated: 6");
+ ::mongo::StringBuilder sb;
+ sb << *i << ": 6";
+ parser.setConfig("config.yaml", sb.str());
ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
moe::Value value;
@@ -3691,814 +3747,731 @@ namespace {
int var1;
ASSERT_OK(value.get(&var1));
ASSERT_EQUALS(var1, 6);
- ASSERT_FALSE(environment.count(moe::Key("dotted.deprecated")));
- }
-
- // Deprecated dotted name cannot be the same as the canonical name.
- TEST(YAMLConfigFile, DeprecatedDottedNameSameAsCanonicalDottedName) {
- moe::OptionSection testOpts;
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- "dotted.canonical"), ::mongo::DBException);
- }
-
- // Deprecated dotted name cannot be the empty string.
- TEST(YAMLConfigFile, DeprecatedDottedNameEmptyString) {
- moe::OptionSection testOpts;
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1", ""),
- ::mongo::DBException);
- }
-
- // Deprecated dotted name cannot be the same as another option's dotted name.
- TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDottedName) {
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1");
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical2", "var2", moe::Int, "Var2",
- "dotted.canonical1"), ::mongo::DBException);
- }
-
- // Deprecated dotted name cannot be the same as another option's deprecated dotted name.
- TEST(YAMLConfigFile, DeprecatedDottedNameSameAsOtherOptionsDeprecatedDottedName) {
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("dotted.canonical1", "var1", moe::Int, "Var1",
- "dotted.deprecated1");
- ASSERT_THROWS(testOpts.addOptionChaining("dotted.canonical2", "var2", moe::Int, "Var2",
- "dotted.deprecated1"), ::mongo::DBException);
- }
-
- // It is an error to have both canonical and deprecated dotted names in the same
- // configuration file.
- TEST(YAMLConfigFile, DeprecatedDottedNameCanonicalAndDeprecated) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- "dotted.deprecated");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "dotted.canonical: 5\n"
- "dotted.deprecated: 6");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- // An option can have multiple deprecated dotted names.
- TEST(YAMLConfigFile, DeprecatedDottedNameMultipleDeprecated) {
- std::vector<std::string> deprecatedDottedNames;
- deprecatedDottedNames.push_back("dotted.deprecated1");
- deprecatedDottedNames.push_back("dotted.deprecated2");
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("dotted.canonical", "var1", moe::Int, "Var1",
- deprecatedDottedNames);
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
-
- // Parse 2 files - each containing a different deprecated dotted name.
- for (std::vector<std::string>::const_iterator i = deprecatedDottedNames.begin();
- i != deprecatedDottedNames.end(); ++i) {
- OptionsParserTester parser;
- moe::Environment environment;
- std::map<std::string, std::string> env_map;
-
- ::mongo::StringBuilder sb;
- sb << *i << ": 6";
- parser.setConfig("config.yaml", sb.str());
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("dotted.canonical"), &value));
- int var1;
- ASSERT_OK(value.get(&var1));
- ASSERT_EQUALS(var1, 6);
- ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[0])));
- ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[1])));
- }
-
- // It is an error to have multiple deprecated dotted names mapping to the same option
- // in the same file.
- {
- OptionsParserTester parser;
- moe::Environment environment;
- std::map<std::string, std::string> env_map;
-
- std::stringstream ss;
- ss << deprecatedDottedNames[0] << ": 6" << std::endl
- << deprecatedDottedNames[1] << ": 7";
- parser.setConfig("config.yaml", ss.str());
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
- }
-
- TEST(YAMLConfigFile, ListBrackets) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "multival: [ \"val1\", \"val2\" ]");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
+ ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[0])));
+ ASSERT_FALSE(environment.count(moe::Key(deprecatedDottedNames[1])));
}
- TEST(YAMLConfigFile, ListDashes) {
+ // It is an error to have multiple deprecated dotted names mapping to the same option
+ // in the same file.
+ {
OptionsParserTester parser;
moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
std::map<std::string, std::string> env_map;
- parser.setConfig("config.yaml", "multival:\n - \"val1\"\n - \"val2\"");
+ std::stringstream ss;
+ ss << deprecatedDottedNames[0] << ": 6" << std::endl
+ << deprecatedDottedNames[1] << ": 7";
+ parser.setConfig("config.yaml", ss.str());
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(YAMLConfigFile, DefaultValueOverride) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", "port: 6");
-
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- moe::Value value;
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 6);
- }
-
- TEST(YAMLConfigFile, Comments) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
- testOpts.addOptionChaining("host", "host", moe::String, "Host");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml",
- "# comment on port\nport: 5\n"
- "# comment on host\nhost: localhost\n");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("port"), &value));
- int port;
- ASSERT_OK(value.get(&port));
- ASSERT_EQUALS(port, 5);
- ASSERT_OK(environment.get(moe::Key("host"), &value));
- std::string host;
- ASSERT_OK(value.get(&host));
- ASSERT_EQUALS(host, "localhost");
- }
-
- TEST(YAMLConfigFile, EmptyKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("port", "port", moe::Int, "Port");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.yaml", ":");
-
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
- }
-
- TEST(YAMLConfigFile, StringVector) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json", "multival : [ \"val1\", \"val2\" ]");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::vector<std::string> multival;
- std::vector<std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(*multivalit, "val1");
- multivalit++;
- ASSERT_EQUALS(*multivalit, "val2");
- }
-
- TEST(YAMLConfigFile, StringMap) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- // NOTE: Indentation is used to determine whether an option is in a sub
- // category, so the spaces after the newlines before key2 and key3 is
- // significant
- "multival : \n key1 : \"value1\"\n key2 : \"value2\"\n key3 : \"\"");
-
- moe::Value value;
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
- ASSERT_OK(environment.get(moe::Key("multival"), &value));
- std::map<std::string, std::string> multival;
- std::map<std::string, std::string>::iterator multivalit;
- ASSERT_OK(value.get(&multival));
- multivalit = multival.begin();
- ASSERT_EQUALS(multivalit->first, "key1");
- ASSERT_EQUALS(multivalit->second, "value1");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key2");
- ASSERT_EQUALS(multivalit->second, "value2");
- multivalit++;
- ASSERT_EQUALS(multivalit->first, "key3");
- ASSERT_EQUALS(multivalit->second, "");
- }
-
- TEST(YAMLConfigFile, StringMapDuplicateKey) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
-
- std::vector<std::string> argv;
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.json");
- std::map<std::string, std::string> env_map;
-
- parser.setConfig("config.json",
- // NOTE: Indentation is used to determine whether an option is in a sub
- // category, so the spaces after the newlines before key2 and key3 is
- // significant
- "multival : \n key1 : \"value1\"\n key1 : \"value2\"");
-
- moe::Value value;
ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
}
-
- TEST(OptionCount, Basic) {
- OptionsParserTester parser;
- moe::Environment environment;
-
- moe::OptionSection testOpts;
- testOpts.addOptionChaining("basic", "basic", moe::String, "Basic Option");
- testOpts.addOptionChaining("hidden", "hidden", moe::String, "Hidden Option").hidden();
-
- moe::OptionSection subSection("Section Name");
- subSection.addOptionChaining("port", "port", moe::Int, "Port")
- .setSources(moe::SourceYAMLConfig);
- testOpts.addSection(subSection);
-
- int numOptions;
- ASSERT_OK(testOpts.countOptions(&numOptions, true /*visibleOnly*/, moe::SourceCommandLine));
- ASSERT_EQUALS(numOptions, 1);
- }
-
- TEST(NumericalBaseParsing, CommandLine) {
- 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("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
-
- // Bad values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--doubleVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--intVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--longVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--unsignedVal");
- argv.push_back("monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // Decimal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--doubleVal");
- argv.push_back("16.1");
- argv.push_back("--intVal");
- argv.push_back("16");
- argv.push_back("--longVal");
- argv.push_back("16");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("16");
- argv.push_back("--unsignedVal");
- argv.push_back("16");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 16.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 16U);
-
- // Octal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--doubleVal");
- argv.push_back("020.1");
- argv.push_back("--intVal");
- argv.push_back("020");
- argv.push_back("--longVal");
- argv.push_back("020");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("020");
- argv.push_back("--unsignedVal");
- argv.push_back("020");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 020.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 020U);
-
- // Hex values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
+}
+
+TEST(YAMLConfigFile, ListBrackets) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "multival: [ \"val1\", \"val2\" ]");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(YAMLConfigFile, ListDashes) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "multival:\n - \"val1\"\n - \"val2\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(YAMLConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port").setDefault(moe::Value(5));
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", "port: 6");
+
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ moe::Value value;
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 6);
+}
+
+TEST(YAMLConfigFile, Comments) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+ testOpts.addOptionChaining("host", "host", moe::String, "Host");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml",
+ "# comment on port\nport: 5\n"
+ "# comment on host\nhost: localhost\n");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("port"), &value));
+ int port;
+ ASSERT_OK(value.get(&port));
+ ASSERT_EQUALS(port, 5);
+ ASSERT_OK(environment.get(moe::Key("host"), &value));
+ std::string host;
+ ASSERT_OK(value.get(&host));
+ ASSERT_EQUALS(host, "localhost");
+}
+
+TEST(YAMLConfigFile, EmptyKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("port", "port", moe::Int, "Port");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.yaml", ":");
+
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(YAMLConfigFile, StringVector) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringVector, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json", "multival : [ \"val1\", \"val2\" ]");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::vector<std::string> multival;
+ std::vector<std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(*multivalit, "val1");
+ multivalit++;
+ ASSERT_EQUALS(*multivalit, "val2");
+}
+
+TEST(YAMLConfigFile, StringMap) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ // NOTE: Indentation is used to determine whether an option is in a sub
+ // category, so the spaces after the newlines before key2 and key3 is
+ // significant
+ "multival : \n key1 : \"value1\"\n key2 : \"value2\"\n key3 : \"\"");
+
+ moe::Value value;
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ ASSERT_OK(environment.get(moe::Key("multival"), &value));
+ std::map<std::string, std::string> multival;
+ std::map<std::string, std::string>::iterator multivalit;
+ ASSERT_OK(value.get(&multival));
+ multivalit = multival.begin();
+ ASSERT_EQUALS(multivalit->first, "key1");
+ ASSERT_EQUALS(multivalit->second, "value1");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key2");
+ ASSERT_EQUALS(multivalit->second, "value2");
+ multivalit++;
+ ASSERT_EQUALS(multivalit->first, "key3");
+ ASSERT_EQUALS(multivalit->second, "");
+}
+
+TEST(YAMLConfigFile, StringMapDuplicateKey) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("multival", "multival", moe::StringMap, "Multiple Values");
+
+ std::vector<std::string> argv;
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.json");
+ std::map<std::string, std::string> env_map;
+
+ parser.setConfig("config.json",
+ // NOTE: Indentation is used to determine whether an option is in a sub
+ // category, so the spaces after the newlines before key2 and key3 is
+ // significant
+ "multival : \n key1 : \"value1\"\n key1 : \"value2\"");
+
+ moe::Value value;
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+}
+
+TEST(OptionCount, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("basic", "basic", moe::String, "Basic Option");
+ testOpts.addOptionChaining("hidden", "hidden", moe::String, "Hidden Option").hidden();
+
+ moe::OptionSection subSection("Section Name");
+ subSection.addOptionChaining("port", "port", moe::Int, "Port")
+ .setSources(moe::SourceYAMLConfig);
+ testOpts.addSection(subSection);
+
+ int numOptions;
+ ASSERT_OK(testOpts.countOptions(&numOptions, true /*visibleOnly*/, moe::SourceCommandLine));
+ ASSERT_EQUALS(numOptions, 1);
+}
+
+TEST(NumericalBaseParsing, CommandLine) {
+ 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("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+
+ // Bad values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--doubleVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--intVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--longVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--unsignedVal");
+ argv.push_back("monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // Decimal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--doubleVal");
+ argv.push_back("16.1");
+ argv.push_back("--intVal");
+ argv.push_back("16");
+ argv.push_back("--longVal");
+ argv.push_back("16");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("16");
+ argv.push_back("--unsignedVal");
+ argv.push_back("16");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 16.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 16U);
+
+ // Octal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--doubleVal");
+ argv.push_back("020.1");
+ argv.push_back("--intVal");
+ argv.push_back("020");
+ argv.push_back("--longVal");
+ argv.push_back("020");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("020");
+ argv.push_back("--unsignedVal");
+ argv.push_back("020");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 020.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 020U);
+
+ // Hex values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
#if !(defined(_WIN32) || defined(__sunos__))
- // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
- // build, so we cannot read hex doubles from the command line on those platforms.
- // See SERVER-14131.
+ // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
+ // build, so we cannot read hex doubles from the command line on those platforms.
+ // See SERVER-14131.
- argv.push_back("--doubleVal");
- argv.push_back("0x10.1");
+ argv.push_back("--doubleVal");
+ argv.push_back("0x10.1");
#endif
- argv.push_back("--intVal");
- argv.push_back("0x10");
- argv.push_back("--longVal");
- argv.push_back("0x10");
- argv.push_back("--unsignedLongLongVal");
- argv.push_back("0x10");
- argv.push_back("--unsignedVal");
- argv.push_back("0x10");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ argv.push_back("--intVal");
+ argv.push_back("0x10");
+ argv.push_back("--longVal");
+ argv.push_back("0x10");
+ argv.push_back("--unsignedLongLongVal");
+ argv.push_back("0x10");
+ argv.push_back("--unsignedVal");
+ argv.push_back("0x10");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
#if !(defined(_WIN32) || defined(__sunos__))
- // See SERVER-14131.
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 0x10.1p0);
+ // See SERVER-14131.
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 0x10.1p0);
#endif
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 0x10U);
- }
-
- TEST(NumericalBaseParsing, INIConfigFile) {
- 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("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
-
- // Bad values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
-
- parser.setConfig("config.ini", "doubleVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "intVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "longVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "unsignedLongLongVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.ini", "unsignedVal=monkeys");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // Decimal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- parser.setConfig("config.ini", "doubleVal=16.1\nintVal=16\nlongVal=16\n"
- "unsignedLongLongVal=16\nunsignedVal=16\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 16.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 16U);
-
- // Octal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
- parser.setConfig("config.ini", "doubleVal=020.1\nintVal=020\nlongVal=020\n"
- "unsignedLongLongVal=020\nunsignedVal=020\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 020.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 020U);
-
- // Hex values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.ini");
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 0x10U);
+}
+
+TEST(NumericalBaseParsing, INIConfigFile) {
+ 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("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+
+ // Bad values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+
+ parser.setConfig("config.ini", "doubleVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "intVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "longVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "unsignedLongLongVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.ini", "unsignedVal=monkeys");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // Decimal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ parser.setConfig("config.ini",
+ "doubleVal=16.1\nintVal=16\nlongVal=16\n"
+ "unsignedLongLongVal=16\nunsignedVal=16\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 16.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 16U);
+
+ // Octal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
+ parser.setConfig("config.ini",
+ "doubleVal=020.1\nintVal=020\nlongVal=020\n"
+ "unsignedLongLongVal=020\nunsignedVal=020\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 020.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 020U);
+
+ // Hex values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.ini");
#if !(defined(_WIN32) || defined(__sunos__))
- // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
- // build, so we cannot read hex doubles from a config file on those platforms.
- // See SERVER-14131.
+ // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
+ // build, so we cannot read hex doubles from a config file on those platforms.
+ // See SERVER-14131.
- parser.setConfig("config.ini", "doubleVal=0x10.1\nintVal=0x10\nlongVal=0x10\n"
- "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
+ parser.setConfig("config.ini",
+ "doubleVal=0x10.1\nintVal=0x10\nlongVal=0x10\n"
+ "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
#else
- parser.setConfig("config.ini", "intVal=0x10\nlongVal=0x10\n"
- "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
+ parser.setConfig("config.ini",
+ "intVal=0x10\nlongVal=0x10\n"
+ "unsignedLongLongVal=0x10\nunsignedVal=0x10\n");
#endif
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
#if !(defined(_WIN32) || defined(__sunos__))
- // See SERVER-14131.
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 0x10.1p0);
+ // See SERVER-14131.
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 0x10.1p0);
#endif
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 0x10);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 0x10U);
- }
-
- TEST(NumericalBaseParsing, YAMLConfigFile) {
- 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("config", "config", moe::String, "Config file to parse");
- testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
- testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
- testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
- testOpts.addOptionChaining("unsignedLongLongVal", "unsignedLongLongVal",
- moe::UnsignedLongLong, "UnsignedLongLongVal");
- testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
-
- // Bad values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
-
- parser.setConfig("config.yaml", "doubleVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "intVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "longVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "unsignedLongLongVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- parser.setConfig("config.yaml", "unsignedVal: \"monkeys\"");
- ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- // Decimal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- parser.setConfig("config.yaml", "doubleVal: 16.1\nintVal: 16\nlongVal: 16\n"
- "unsignedLongLongVal: 16\nunsignedVal: 16\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- double doubleVal;
- int intVal;
- long longVal;
- unsigned long long unsignedLongLongVal;
- unsigned unsignedVal;
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 16.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 16);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 16U);
-
- // Octal values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
- parser.setConfig("config.yaml", "doubleVal: 020.1\nintVal: 020\nlongVal: 020\n"
- "unsignedLongLongVal: 020\nunsignedVal: 020\n");
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
-
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 020.1);
-
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 020);
-
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
-
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 020U);
-
- // Hex values
- argv = std::vector<std::string>();
- argv.push_back("binaryname");
- argv.push_back("--config");
- argv.push_back("config.yaml");
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 0x10);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 0x10U);
+}
+
+TEST(NumericalBaseParsing, YAMLConfigFile) {
+ 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("config", "config", moe::String, "Config file to parse");
+ testOpts.addOptionChaining("doubleVal", "doubleVal", moe::Double, "DoubleVal");
+ testOpts.addOptionChaining("intVal", "intVal", moe::Int, "IntVal");
+ testOpts.addOptionChaining("longVal", "longVal", moe::Long, "LongVal");
+ testOpts.addOptionChaining(
+ "unsignedLongLongVal", "unsignedLongLongVal", moe::UnsignedLongLong, "UnsignedLongLongVal");
+ testOpts.addOptionChaining("unsignedVal", "unsignedVal", moe::Unsigned, "UnsignedVal");
+
+ // Bad values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+
+ parser.setConfig("config.yaml", "doubleVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "intVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "longVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "unsignedLongLongVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ parser.setConfig("config.yaml", "unsignedVal: \"monkeys\"");
+ ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ // Decimal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ parser.setConfig("config.yaml",
+ "doubleVal: 16.1\nintVal: 16\nlongVal: 16\n"
+ "unsignedLongLongVal: 16\nunsignedVal: 16\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ double doubleVal;
+ int intVal;
+ long longVal;
+ unsigned long long unsignedLongLongVal;
+ unsigned unsignedVal;
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 16.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 16);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 16ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 16U);
+
+ // Octal values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
+ parser.setConfig("config.yaml",
+ "doubleVal: 020.1\nintVal: 020\nlongVal: 020\n"
+ "unsignedLongLongVal: 020\nunsignedVal: 020\n");
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 020.1);
+
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 020);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 020ULL);
+
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 020U);
+
+ // Hex values
+ argv = std::vector<std::string>();
+ argv.push_back("binaryname");
+ argv.push_back("--config");
+ argv.push_back("config.yaml");
#if !(defined(_WIN32) || defined(__sunos__))
- // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
- // build, so we cannot read hex doubles from a config file on those platforms.
- // See SERVER-14131.
+ // Hex doubles are not parseable by the Windows SDK libc or the Solaris libc in the mode we
+ // build, so we cannot read hex doubles from a config file on those platforms.
+ // See SERVER-14131.
- parser.setConfig("config.yaml", "doubleVal: 0x10.1\nintVal: 0x10\nlongVal: 0x10\n"
- "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
+ parser.setConfig("config.yaml",
+ "doubleVal: 0x10.1\nintVal: 0x10\nlongVal: 0x10\n"
+ "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
#else
- parser.setConfig("config.yaml", "intVal: 0x10\nlongVal: 0x10\n"
- "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
+ parser.setConfig("config.yaml",
+ "intVal: 0x10\nlongVal: 0x10\n"
+ "unsignedLongLongVal: 0x10\nunsignedVal: 0x10\n");
#endif
- environment = moe::Environment();
- ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
+ environment = moe::Environment();
+ ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
#if !(defined(_WIN32) || defined(__sunos__))
- // See SERVER-14131.
- ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
- ASSERT_OK(value.get(&doubleVal));
- ASSERT_EQUALS(doubleVal, 0x10.1p0);
+ // See SERVER-14131.
+ ASSERT_OK(environment.get(moe::Key("doubleVal"), &value));
+ ASSERT_OK(value.get(&doubleVal));
+ ASSERT_EQUALS(doubleVal, 0x10.1p0);
#endif
- ASSERT_OK(environment.get(moe::Key("intVal"), &value));
- ASSERT_OK(value.get(&intVal));
- ASSERT_EQUALS(intVal, 0x10);
+ ASSERT_OK(environment.get(moe::Key("intVal"), &value));
+ ASSERT_OK(value.get(&intVal));
+ ASSERT_EQUALS(intVal, 0x10);
- ASSERT_OK(environment.get(moe::Key("longVal"), &value));
- ASSERT_OK(value.get(&longVal));
- ASSERT_EQUALS(longVal, 0x10);
+ ASSERT_OK(environment.get(moe::Key("longVal"), &value));
+ ASSERT_OK(value.get(&longVal));
+ ASSERT_EQUALS(longVal, 0x10);
- ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
- ASSERT_OK(value.get(&unsignedLongLongVal));
- ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
+ ASSERT_OK(environment.get(moe::Key("unsignedLongLongVal"), &value));
+ ASSERT_OK(value.get(&unsignedLongLongVal));
+ ASSERT_EQUALS(unsignedLongLongVal, 0x10ULL);
- ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
- ASSERT_OK(value.get(&unsignedVal));
- ASSERT_EQUALS(unsignedVal, 0x10U);
- }
+ ASSERT_OK(environment.get(moe::Key("unsignedVal"), &value));
+ ASSERT_OK(value.get(&unsignedVal));
+ ASSERT_EQUALS(unsignedVal, 0x10U);
+}
-} // unnamed namespace
+} // unnamed namespace
diff --git a/src/mongo/util/options_parser/startup_option_init.cpp b/src/mongo/util/options_parser/startup_option_init.cpp
index 21dfad053db..0ff85fb9f49 100644
--- a/src/mongo/util/options_parser/startup_option_init.cpp
+++ b/src/mongo/util/options_parser/startup_option_init.cpp
@@ -34,38 +34,49 @@
/* Groups for all of option handling */
MONGO_INITIALIZER_GROUP(BeginStartupOptionHandling,
- ("GlobalLogManager", "ValidateLocale"), ("EndStartupOptionHandling"))
+ ("GlobalLogManager", "ValidateLocale"),
+ ("EndStartupOptionHandling"))
/* Groups for option registration */
MONGO_INITIALIZER_GROUP(BeginStartupOptionRegistration,
- ("BeginStartupOptionHandling"), ("EndStartupOptionRegistration"))
+ ("BeginStartupOptionHandling"),
+ ("EndStartupOptionRegistration"))
/* Groups for general option registration (useful for controlling the order in which options are
* registered for modules, which affects the order in which they are printed in help output) */
MONGO_INITIALIZER_GROUP(BeginGeneralStartupOptionRegistration,
- ("BeginStartupOptionRegistration"), ("EndGeneralStartupOptionRegistration"))
+ ("BeginStartupOptionRegistration"),
+ ("EndGeneralStartupOptionRegistration"))
MONGO_INITIALIZER_GROUP(EndGeneralStartupOptionRegistration,
- ("BeginGeneralStartupOptionRegistration"), ("EndStartupOptionRegistration"))
+ ("BeginGeneralStartupOptionRegistration"),
+ ("EndStartupOptionRegistration"))
MONGO_INITIALIZER_GROUP(EndStartupOptionRegistration,
- ("BeginStartupOptionRegistration"), ("BeginStartupOptionParsing"))
+ ("BeginStartupOptionRegistration"),
+ ("BeginStartupOptionParsing"))
/* Groups for option parsing */
MONGO_INITIALIZER_GROUP(BeginStartupOptionParsing,
- ("EndStartupOptionRegistration"), ("EndStartupOptionParsing"))
+ ("EndStartupOptionRegistration"),
+ ("EndStartupOptionParsing"))
MONGO_INITIALIZER_GROUP(EndStartupOptionParsing,
- ("BeginStartupOptionParsing"), ("BeginStartupOptionValidation"))
+ ("BeginStartupOptionParsing"),
+ ("BeginStartupOptionValidation"))
/* Groups for option validation */
MONGO_INITIALIZER_GROUP(BeginStartupOptionValidation,
- ("EndStartupOptionParsing"), ("EndStartupOptionValidation"))
+ ("EndStartupOptionParsing"),
+ ("EndStartupOptionValidation"))
MONGO_INITIALIZER_GROUP(EndStartupOptionValidation,
- ("BeginStartupOptionValidation"), ("BeginStartupOptionStorage"))
+ ("BeginStartupOptionValidation"),
+ ("BeginStartupOptionStorage"))
/* Groups for option storage */
MONGO_INITIALIZER_GROUP(BeginStartupOptionStorage,
- ("EndStartupOptionValidation"), ("EndStartupOptionStorage"))
+ ("EndStartupOptionValidation"),
+ ("EndStartupOptionStorage"))
MONGO_INITIALIZER_GROUP(EndStartupOptionStorage,
- ("BeginStartupOptionStorage"), ("EndStartupOptionHandling"))
+ ("BeginStartupOptionStorage"),
+ ("EndStartupOptionHandling"))
MONGO_INITIALIZER_GROUP(EndStartupOptionHandling, ("BeginStartupOptionHandling"), ("default"))
diff --git a/src/mongo/util/options_parser/startup_option_init.h b/src/mongo/util/options_parser/startup_option_init.h
index ce8671e0e05..7133611849e 100644
--- a/src/mongo/util/options_parser/startup_option_init.h
+++ b/src/mongo/util/options_parser/startup_option_init.h
@@ -59,8 +59,8 @@
* return Status::OK();
* }
*/
-#define MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Register, \
+#define MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(fname) \
+ MONGO_INITIALIZER_GENERAL(fname##_Register, \
("BeginGeneralStartupOptionRegistration"), \
("EndGeneralStartupOptionRegistration"))
@@ -74,8 +74,8 @@
* return Status::OK();
* }
*/
-#define MONGO_MODULE_STARTUP_OPTIONS_REGISTER(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Register, \
+#define MONGO_MODULE_STARTUP_OPTIONS_REGISTER(fname) \
+ MONGO_INITIALIZER_GENERAL(fname##_Register, \
("EndGeneralStartupOptionRegistration"), \
("EndStartupOptionRegistration"))
@@ -90,9 +90,8 @@
* }
*/
#define MONGO_STARTUP_OPTIONS_PARSE(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Parse, \
- ("BeginStartupOptionParsing"), \
- ("EndStartupOptionParsing"))
+ MONGO_INITIALIZER_GENERAL( \
+ fname##_Parse, ("BeginStartupOptionParsing"), ("EndStartupOptionParsing"))
/**
* Macro to define an initializer function named "<fname>_Validate" to validate the command line and
@@ -107,9 +106,8 @@
* }
*/
#define MONGO_STARTUP_OPTIONS_VALIDATE(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Validate, \
- ("BeginStartupOptionValidation"), \
- ("EndStartupOptionValidation"))
+ MONGO_INITIALIZER_GENERAL( \
+ fname##_Validate, ("BeginStartupOptionValidation"), ("EndStartupOptionValidation"))
/**
* Macro to define an initializer function named "<fname>_Store" to store the command line and
@@ -125,6 +123,5 @@
* }
*/
#define MONGO_STARTUP_OPTIONS_STORE(fname) \
- MONGO_INITIALIZER_GENERAL(fname##_Store, \
- ("BeginStartupOptionStorage"), \
- ("EndStartupOptionStorage"))
+ MONGO_INITIALIZER_GENERAL( \
+ fname##_Store, ("BeginStartupOptionStorage"), ("EndStartupOptionStorage"))
diff --git a/src/mongo/util/options_parser/startup_options.cpp b/src/mongo/util/options_parser/startup_options.cpp
index f38b6e8b3f3..587131aea41 100644
--- a/src/mongo/util/options_parser/startup_options.cpp
+++ b/src/mongo/util/options_parser/startup_options.cpp
@@ -34,8 +34,8 @@
namespace mongo {
namespace optionenvironment {
- OptionSection startupOptions("Options");
- Environment startupOptionsParsed;
+OptionSection startupOptions("Options");
+Environment startupOptionsParsed;
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/startup_options.h b/src/mongo/util/options_parser/startup_options.h
index d6e7e9763a1..1ea7b7b8232 100644
--- a/src/mongo/util/options_parser/startup_options.h
+++ b/src/mongo/util/options_parser/startup_options.h
@@ -32,35 +32,35 @@
namespace mongo {
namespace optionenvironment {
- /*
- * This structure stores information about all the command line options. The parser will use
- * this description when it parses the command line, the INI config file, and the JSON config
- * file. See the OptionSection and OptionDescription classes for more details.
- *
- * Example:
- * MONGO_MODULE_STARTUP_OPTIONS_REGISTER(MongodOptions)(InitializerContext* context) {
- * return addMongodOptions(&moe::startupOptions);
- * startupOptions.addOptionChaining("option", "option", moe::String, "description");
- * return Status::OK();
- * }
- */
- extern OptionSection startupOptions;
+/*
+ * This structure stores information about all the command line options. The parser will use
+ * this description when it parses the command line, the INI config file, and the JSON config
+ * file. See the OptionSection and OptionDescription classes for more details.
+ *
+ * Example:
+ * MONGO_MODULE_STARTUP_OPTIONS_REGISTER(MongodOptions)(InitializerContext* context) {
+ * return addMongodOptions(&moe::startupOptions);
+ * startupOptions.addOptionChaining("option", "option", moe::String, "description");
+ * return Status::OK();
+ * }
+ */
+extern OptionSection startupOptions;
- /*
- * This structure stores the parsed command line options. After the "defult" group of the
- * MONGO_INITIALIZERS, this structure should be fully validated from an option perspective. See
- * the Environment, Constraint, and Value classes for more details.
- *
- * Example:
- * if (startupOptionsParsed.count("option")) {
- * std::string value;
- * ret = startupOptionsParsed.get("option", &value);
- * if (!ret.isOK()) {
- * return ret;
- * }
- * }
- */
- extern Environment startupOptionsParsed;
+/*
+ * This structure stores the parsed command line options. After the "defult" group of the
+ * MONGO_INITIALIZERS, this structure should be fully validated from an option perspective. See
+ * the Environment, Constraint, and Value classes for more details.
+ *
+ * Example:
+ * if (startupOptionsParsed.count("option")) {
+ * std::string value;
+ * ret = startupOptionsParsed.get("option", &value);
+ * if (!ret.isOK()) {
+ * return ret;
+ * }
+ * }
+ */
+extern Environment startupOptionsParsed;
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/value.cpp b/src/mongo/util/options_parser/value.cpp
index f41092ab384..5c8d2d14fea 100644
--- a/src/mongo/util/options_parser/value.cpp
+++ b/src/mongo/util/options_parser/value.cpp
@@ -32,209 +32,251 @@
namespace mongo {
namespace optionenvironment {
- // Value implementation
+// Value implementation
- // Value access functions
+// Value access functions
- Status Value::get(StringVector_t* val) const {
- if (_type != StringVector) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: StringVector, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _stringVectorVal;
- return Status::OK();
- }
- Status Value::get(StringMap_t* val) const {
- if (_type != StringMap) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: StringMap, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _stringMapVal;
- return Status::OK();
+Status Value::get(StringVector_t* val) const {
+ if (_type != StringVector) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: StringVector, but Value is of type: "
+ << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(bool* val) const {
- if (_type != Bool) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Bool, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _boolVal;
- return Status::OK();
+ *val = _stringVectorVal;
+ return Status::OK();
+}
+Status Value::get(StringMap_t* val) const {
+ if (_type != StringMap) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: StringMap, but Value is of type: "
+ << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(double* val) const {
- if (_type != Double) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Double, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _doubleVal;
- return Status::OK();
+ *val = _stringMapVal;
+ return Status::OK();
+}
+Status Value::get(bool* val) const {
+ if (_type != Bool) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: Bool, but Value is of type: " << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(int* val) const {
- if (_type != Int) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Int, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _intVal;
- return Status::OK();
+ *val = _boolVal;
+ return Status::OK();
+}
+Status Value::get(double* val) const {
+ if (_type != Double) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: Double, but Value is of type: " << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(long* val) const {
- if (_type == Long) {
- *val = _longVal;
- return Status::OK();
- }
- else if (_type == Int) {
- *val = _intVal;
- return Status::OK();
- }
+ *val = _doubleVal;
+ return Status::OK();
+}
+Status Value::get(int* val) const {
+ if (_type != Int) {
StringBuilder sb;
- sb << "Value of type: " << typeToString()
- << " is not convertible to type: Long";
+ sb << "Attempting to get Value as type: Int, but Value is of type: " << typeToString();
return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(std::string* val) const {
- if (_type != String) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: string, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
- *val = _stringVal;
+ *val = _intVal;
+ return Status::OK();
+}
+Status Value::get(long* val) const {
+ if (_type == Long) {
+ *val = _longVal;
+ return Status::OK();
+ } else if (_type == Int) {
+ *val = _intVal;
return Status::OK();
}
- Status Value::get(unsigned long long* val) const {
- if (_type == UnsignedLongLong) {
- *val = _unsignedLongLongVal;
- return Status::OK();
- }
- else if (_type == Unsigned) {
- *val = _unsignedVal;
- return Status::OK();
- }
+ StringBuilder sb;
+ sb << "Value of type: " << typeToString() << " is not convertible to type: Long";
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+}
+Status Value::get(std::string* val) const {
+ if (_type != String) {
StringBuilder sb;
- sb << "Value of type: " << typeToString()
- << " is not convertible to type: UnsignedLongLong";
+ sb << "Attempting to get Value as type: string, but Value is of type: " << typeToString();
return Status(ErrorCodes::TypeMismatch, sb.str());
}
- Status Value::get(unsigned* val) const {
- if (_type != Unsigned) {
- StringBuilder sb;
- sb << "Attempting to get Value as type: Unsigned, but Value is of type: "
- << typeToString();
- return Status(ErrorCodes::TypeMismatch, sb.str());
- }
+ *val = _stringVal;
+ return Status::OK();
+}
+Status Value::get(unsigned long long* val) const {
+ if (_type == UnsignedLongLong) {
+ *val = _unsignedLongLongVal;
+ return Status::OK();
+ } else if (_type == Unsigned) {
*val = _unsignedVal;
return Status::OK();
}
+ StringBuilder sb;
+ sb << "Value of type: " << typeToString() << " is not convertible to type: UnsignedLongLong";
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+}
+Status Value::get(unsigned* val) const {
+ if (_type != Unsigned) {
+ StringBuilder sb;
+ sb << "Attempting to get Value as type: Unsigned, but Value is of type: " << typeToString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+ }
+ *val = _unsignedVal;
+ return Status::OK();
+}
- // Value utility functions
+// Value utility functions
- std::string Value::typeToString() const {
- switch (_type) {
- case StringVector: return "StringVector";
- case StringMap: return "StringMap";
- case Bool: return "Bool";
- case Double: return "Double";
- case Int: return "Int";
- case Long: return "Long";
- case String: return "String";
- case UnsignedLongLong: return "UnsignedLongLong";
- case Unsigned: return "Unsigned";
- case None: return "None";
- default: return "Unknown";
- }
+std::string Value::typeToString() const {
+ switch (_type) {
+ case StringVector:
+ return "StringVector";
+ case StringMap:
+ return "StringMap";
+ case Bool:
+ return "Bool";
+ case Double:
+ return "Double";
+ case Int:
+ return "Int";
+ case Long:
+ return "Long";
+ case String:
+ return "String";
+ case UnsignedLongLong:
+ return "UnsignedLongLong";
+ case Unsigned:
+ return "Unsigned";
+ case None:
+ return "None";
+ default:
+ return "Unknown";
}
- bool Value::isEmpty() const {
- return _type == None;
+}
+bool Value::isEmpty() const {
+ return _type == None;
+}
+bool Value::equal(const Value& otherVal) const {
+ if (_type != otherVal._type) {
+ return false;
}
- bool Value::equal(const Value& otherVal) const {
- if (_type != otherVal._type) {
- return false;
- }
- switch (_type) {
- case StringVector: return _stringVectorVal == otherVal._stringVectorVal;
- case StringMap: return _stringMapVal == otherVal._stringMapVal;
- case Bool: return _boolVal == otherVal._boolVal;
- case Double: return _doubleVal == otherVal._doubleVal;
- case Int: return _intVal == otherVal._intVal;
- case Long: return _longVal == otherVal._longVal;
- case String: return _stringVal == otherVal._stringVal;
- case UnsignedLongLong: return _unsignedLongLongVal == otherVal._unsignedLongLongVal;
- case Unsigned: return _unsignedVal == otherVal._unsignedVal;
- case None: return true;
- default: return false; /* Undefined */
- }
+ switch (_type) {
+ case StringVector:
+ return _stringVectorVal == otherVal._stringVectorVal;
+ case StringMap:
+ return _stringMapVal == otherVal._stringMapVal;
+ case Bool:
+ return _boolVal == otherVal._boolVal;
+ case Double:
+ return _doubleVal == otherVal._doubleVal;
+ case Int:
+ return _intVal == otherVal._intVal;
+ case Long:
+ return _longVal == otherVal._longVal;
+ case String:
+ return _stringVal == otherVal._stringVal;
+ case UnsignedLongLong:
+ return _unsignedLongLongVal == otherVal._unsignedLongLongVal;
+ case Unsigned:
+ return _unsignedVal == otherVal._unsignedVal;
+ case None:
+ return true;
+ default:
+ return false; /* Undefined */
}
+}
- // Dump the value as a string. This function is used only for debugging purposes.
- std::string Value::toString() const {
- StringBuilder sb;
- switch (_type) {
- case StringVector:
- if (!_stringVectorVal.empty())
- {
- // Convert all but the last element to avoid a trailing ","
- for (StringVector_t::const_iterator iterator = _stringVectorVal.begin();
- iterator != _stringVectorVal.end() - 1; iterator++) {
- sb << *iterator << ",";
- }
-
- // Now add the last element with no delimiter
- sb << _stringVectorVal.back();
+// Dump the value as a string. This function is used only for debugging purposes.
+std::string Value::toString() const {
+ StringBuilder sb;
+ switch (_type) {
+ case StringVector:
+ if (!_stringVectorVal.empty()) {
+ // Convert all but the last element to avoid a trailing ","
+ for (StringVector_t::const_iterator iterator = _stringVectorVal.begin();
+ iterator != _stringVectorVal.end() - 1;
+ iterator++) {
+ sb << *iterator << ",";
}
- break;
- case StringMap:
- if (!_stringMapVal.empty())
- {
- // Convert all but the last element to avoid a trailing ","
- if (_stringMapVal.begin() != _stringMapVal.end()) {
- StringMap_t::const_iterator iterator;
- StringMap_t::const_iterator it_last;
- for (iterator = _stringMapVal.begin(), it_last = --_stringMapVal.end();
- iterator != it_last; ++iterator) {
- sb << iterator->first << ":" << iterator->second << ",";
- }
- }
- // Now add the last element with no delimiter
- sb << _stringMapVal.end()->first << ":" << _stringMapVal.end()->second;
+ // Now add the last element with no delimiter
+ sb << _stringVectorVal.back();
+ }
+ break;
+ case StringMap:
+ if (!_stringMapVal.empty()) {
+ // Convert all but the last element to avoid a trailing ","
+ if (_stringMapVal.begin() != _stringMapVal.end()) {
+ StringMap_t::const_iterator iterator;
+ StringMap_t::const_iterator it_last;
+ for (iterator = _stringMapVal.begin(), it_last = --_stringMapVal.end();
+ iterator != it_last;
+ ++iterator) {
+ sb << iterator->first << ":" << iterator->second << ",";
+ }
}
- break;
- case Bool: sb << _boolVal; break;
- case Double: sb << _doubleVal; break;
- case Int: sb << _intVal; break;
- case Long: sb << _longVal; break;
- case String: sb << _stringVal; break;
- case UnsignedLongLong: sb << _unsignedLongLongVal; break;
- case Unsigned: sb << _unsignedVal; break;
- case None: sb << "(not set)"; break;
- default: sb << "(undefined)"; break;
- }
- return sb.str();
+
+ // Now add the last element with no delimiter
+ sb << _stringMapVal.end()->first << ":" << _stringMapVal.end()->second;
+ }
+ break;
+ case Bool:
+ sb << _boolVal;
+ break;
+ case Double:
+ sb << _doubleVal;
+ break;
+ case Int:
+ sb << _intVal;
+ break;
+ case Long:
+ sb << _longVal;
+ break;
+ case String:
+ sb << _stringVal;
+ break;
+ case UnsignedLongLong:
+ sb << _unsignedLongLongVal;
+ break;
+ case Unsigned:
+ sb << _unsignedVal;
+ break;
+ case None:
+ sb << "(not set)";
+ break;
+ default:
+ sb << "(undefined)";
+ break;
}
- const std::type_info& Value::type() const {
- switch (_type) {
- case StringVector: return typeid(StringVector_t);
- case StringMap: return typeid(StringMap_t);
- case Bool: return typeid(bool);
- case Double: return typeid(double);
- case Int: return typeid(int);
- case Long: return typeid(long);
- case String: return typeid(std::string);
- case UnsignedLongLong: return typeid(unsigned long long);
- case Unsigned: return typeid(unsigned);
- case None: return typeid(void);
- default: return typeid(void);
- }
+ return sb.str();
+}
+const std::type_info& Value::type() const {
+ switch (_type) {
+ case StringVector:
+ return typeid(StringVector_t);
+ case StringMap:
+ return typeid(StringMap_t);
+ case Bool:
+ return typeid(bool);
+ case Double:
+ return typeid(double);
+ case Int:
+ return typeid(int);
+ case Long:
+ return typeid(long);
+ case String:
+ return typeid(std::string);
+ case UnsignedLongLong:
+ return typeid(unsigned long long);
+ case Unsigned:
+ return typeid(unsigned);
+ case None:
+ return typeid(void);
+ default:
+ return typeid(void);
}
+}
-} // namespace optionenvironment
-} // namespace mongo
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/value.h b/src/mongo/util/options_parser/value.h
index 9c9bb1468d7..2f7a089ea80 100644
--- a/src/mongo/util/options_parser/value.h
+++ b/src/mongo/util/options_parser/value.h
@@ -36,147 +36,145 @@
namespace mongo {
namespace optionenvironment {
- class Constraint;
- class KeyConstraint;
+class Constraint;
+class KeyConstraint;
+
+/**
+ * Helper typedefs for the more complex C++ types supported by this Value class
+ */
+typedef std::map<std::string, std::string> StringMap_t;
+typedef std::vector<std::string> StringVector_t;
+
+typedef std::string Key;
+
+/** A simple container interface for storing various C++ values.
+ *
+ * Usage:
+ *
+ * Value intVal(2);
+ * Value stringVal("string");
+ *
+ * int intContents = 1;
+ * Status ret = stringVal.get(&intContents);
+ * // ret != Status::OK()
+ * // intContents is still 1
+ *
+ * ret = intVal.get(&intContents);
+ * // ret == Status::OK()
+ * // intContents is now 2
+ */
+class Value {
+public:
+ // Constructors
+
+ explicit Value() : _type(None) {}
+ explicit Value(StringVector_t val) : _stringVectorVal(val), _type(StringVector) {}
+ explicit Value(StringMap_t val) : _stringMapVal(val), _type(StringMap) {}
+ explicit Value(bool val) : _boolVal(val), _type(Bool) {}
+ explicit Value(double val) : _doubleVal(val), _type(Double) {}
+ explicit Value(int val) : _intVal(val), _type(Int) {}
+ explicit Value(long val) : _longVal(val), _type(Long) {}
+ explicit Value(std::string val) : _stringVal(val), _type(String) {}
+ explicit Value(unsigned long long val) : _unsignedLongLongVal(val), _type(UnsignedLongLong) {}
+ explicit Value(unsigned val) : _unsignedVal(val), _type(Unsigned) {}
+
+ // Access interface
+
+ Status get(StringVector_t* val) const;
+ Status get(StringMap_t* val) const;
+ Status get(bool* val) const;
+ Status get(double* val) const;
+ Status get(int* val) const;
+ Status get(long* val) const;
+ Status get(std::string* val) const;
+ Status get(unsigned long long* val) const;
+ Status get(unsigned* val) const;
+
+ // Utility functions
/**
- * Helper typedefs for the more complex C++ types supported by this Value class
+ * Return the value's type as a string
*/
- typedef std::map<std::string, std::string> StringMap_t;
- typedef std::vector<std::string> StringVector_t;
+ std::string typeToString() const;
- typedef std::string Key;
+ /**
+ * Return true if the value was created with the no argument constructor
+ */
+ bool isEmpty() const;
- /** A simple container interface for storing various C++ values.
- *
- * Usage:
- *
- * Value intVal(2);
- * Value stringVal("string");
- *
- * int intContents = 1;
- * Status ret = stringVal.get(&intContents);
- * // ret != Status::OK()
- * // intContents is still 1
+ /**
+ * Return true if the other Value equals this value, both in type and in contents
*
- * ret = intVal.get(&intContents);
- * // ret == Status::OK()
- * // intContents is now 2
+ * Two empty values are equal
*/
- class Value {
- public:
-
- // Constructors
-
- explicit Value() : _type(None) { }
- explicit Value(StringVector_t val) : _stringVectorVal(val), _type(StringVector) {}
- explicit Value(StringMap_t val) : _stringMapVal(val), _type(StringMap) {}
- explicit Value(bool val) : _boolVal(val), _type(Bool) { }
- explicit Value(double val) : _doubleVal(val), _type(Double) { }
- explicit Value(int val) : _intVal(val), _type(Int) { }
- explicit Value(long val) : _longVal(val), _type(Long) { }
- explicit Value(std::string val) : _stringVal(val), _type(String) { }
- explicit Value(unsigned long long val) : _unsignedLongLongVal(val),
- _type(UnsignedLongLong) { }
- explicit Value(unsigned val) : _unsignedVal(val), _type(Unsigned) { }
-
- // Access interface
-
- Status get(StringVector_t* val) const;
- Status get(StringMap_t* val) const;
- Status get(bool* val) const;
- Status get(double* val) const;
- Status get(int* val) const;
- Status get(long* val) const;
- Status get(std::string* val) const;
- Status get(unsigned long long* val) const;
- Status get(unsigned* val) const;
-
- // Utility functions
-
- /**
- * Return the value's type as a string
- */
- std::string typeToString() const;
-
- /**
- * Return true if the value was created with the no argument constructor
- */
- bool isEmpty() const;
-
- /**
- * Return true if the other Value equals this value, both in type and in contents
- *
- * Two empty values are equal
- */
- bool equal(const Value&) const;
-
- /**
- * Return the std::string representation of this Value. This function is used only for
- * debugging purposes and does not output data in an easily parseable format.
- */
- std::string toString() const;
-
- /**
- * The functions below are the legacy interface to be consistent with boost::any during the
- * transition period
- */
-
- /**
- * Returns the contents of this Value as type T. Throws MsgAssertionException if the type
- * does not match
- */
- template <typename T>
- T as() const;
-
- /**
- * Return the type_info for this value
- */
- const std::type_info& type() const;
-
- private:
- StringVector_t _stringVectorVal;
- StringMap_t _stringMapVal;
- std::string _stringVal;
- union {
- bool _boolVal;
- double _doubleVal;
- int _intVal;
- long _longVal;
- unsigned long long _unsignedLongLongVal;
- unsigned _unsignedVal;
- };
-
- // Types currently supported by Value
- enum Type {
- StringVector, // std::vector<std::string>
- StringMap, // std::map<std::string, std::string>
- Bool, // bool
- Double, // double
- Int, // int
- Long, // long
- String, // std::string
- UnsignedLongLong, // unsigned long long
- Unsigned, // unsigned
- None, // (not set)
- };
-
- Type _type;
- };
+ bool equal(const Value&) const;
+ /**
+ * Return the std::string representation of this Value. This function is used only for
+ * debugging purposes and does not output data in an easily parseable format.
+ */
+ std::string toString() const;
+
+ /**
+ * The functions below are the legacy interface to be consistent with boost::any during the
+ * transition period
+ */
+
+ /**
+ * Returns the contents of this Value as type T. Throws MsgAssertionException if the type
+ * does not match
+ */
template <typename T>
- T Value::as() const {
- T valueType;
+ T as() const;
- Status ret = get(&valueType);
- if (!ret.isOK()) {
- StringBuilder message;
- message << "failed to extract typed value from Value container: " << ret.toString();
- throw MsgAssertionException(17114, message.str());
- }
+ /**
+ * Return the type_info for this value
+ */
+ const std::type_info& type() const;
+
+private:
+ StringVector_t _stringVectorVal;
+ StringMap_t _stringMapVal;
+ std::string _stringVal;
+ union {
+ bool _boolVal;
+ double _doubleVal;
+ int _intVal;
+ long _longVal;
+ unsigned long long _unsignedLongLongVal;
+ unsigned _unsignedVal;
+ };
+
+ // Types currently supported by Value
+ enum Type {
+ StringVector, // std::vector<std::string>
+ StringMap, // std::map<std::string, std::string>
+ Bool, // bool
+ Double, // double
+ Int, // int
+ Long, // long
+ String, // std::string
+ UnsignedLongLong, // unsigned long long
+ Unsigned, // unsigned
+ None, // (not set)
+ };
+
+ Type _type;
+};
- return valueType;
+template <typename T>
+T Value::as() const {
+ T valueType;
+
+ Status ret = get(&valueType);
+ if (!ret.isOK()) {
+ StringBuilder message;
+ message << "failed to extract typed value from Value container: " << ret.toString();
+ throw MsgAssertionException(17114, message.str());
}
-} // namespace optionenvironment
-} // namespace mongo
+ return valueType;
+}
+
+} // namespace optionenvironment
+} // namespace mongo