summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
authorShaun Verch <shaun.verch@10gen.com>2013-08-15 11:59:46 -0400
committerShaun Verch <shaun.verch@10gen.com>2013-09-05 13:49:33 -0400
commit5ee03db5cdc40ecc0a28aaad8031df177188ffee (patch)
tree8199d2184bab251c6f3d260cc461c9c92f06ef48 /src/mongo/util
parent50a2462a66402499fa81c9fdb84ee6bab0e5d1a3 (diff)
downloadmongo-5ee03db5cdc40ecc0a28aaad8031df177188ffee.tar.gz
SERVER-8510 Handle default, implicit, and composing options in new configuration parser
Diffstat (limited to 'src/mongo/util')
-rw-r--r--src/mongo/util/options_parser/option_description.h14
-rw-r--r--src/mongo/util/options_parser/option_section.cpp398
-rw-r--r--src/mongo/util/options_parser/option_section.h9
-rw-r--r--src/mongo/util/options_parser/options_parser.cpp130
-rw-r--r--src/mongo/util/options_parser/options_parser.h3
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp272
6 files changed, 808 insertions, 18 deletions
diff --git a/src/mongo/util/options_parser/option_description.h b/src/mongo/util/options_parser/option_description.h
index 08d99122243..78bb88f80c2 100644
--- a/src/mongo/util/options_parser/option_description.h
+++ b/src/mongo/util/options_parser/option_description.h
@@ -18,6 +18,7 @@
#include <iostream>
#include "mongo/base/status.h"
+#include "mongo/util/options_parser/value.h"
namespace mongo {
namespace optionenvironment {
@@ -48,18 +49,27 @@ namespace optionenvironment {
const std::string& singleName, // Used for boost command line and INI
const OptionType type,
const std::string& description,
- const bool isVisible = true)
+ const bool isVisible = true,
+ const Value defaultValue = Value(),
+ const Value implicitValue = Value(),
+ const bool isComposing = false)
: _dottedName(dottedName),
_singleName(singleName),
_type(type),
_description(description),
- _isVisible(isVisible) { }
+ _isVisible(isVisible),
+ _default(defaultValue),
+ _implicit(implicitValue),
+ _isComposing(isComposing) { }
std::string _dottedName;
std::string _singleName;
OptionType _type;
std::string _description;
bool _isVisible;
+ Value _default;
+ Value _implicit;
+ bool _isComposing;
};
class PositionalOptionDescription {
diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp
index d2fc250005d..783f4dc5853 100644
--- a/src/mongo/util/options_parser/option_section.cpp
+++ b/src/mongo/util/options_parser/option_section.cpp
@@ -18,12 +18,75 @@
#include <sstream>
#include "mongo/bson/util/builder.h"
+#include "mongo/util/options_parser/value.h"
namespace mongo {
namespace optionenvironment {
// Registration interface
+ 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());
+ }
+ }
+ }
+ } // namespace
+
+ // TODO: Make sure the section we are adding does not have duplicate options
Status OptionSection::addSection(const OptionSection& subSection) {
if (!subSection._positionalOptions.empty()) {
return Status(ErrorCodes::InternalError,
@@ -51,6 +114,47 @@ namespace optionenvironment {
return Status(ErrorCodes::InternalError, sb.str());
}
}
+
+ // Make sure the type of our default value matches our declared type
+ if (!option._default.isEmpty()) {
+ Status ret = checkValueType(option._type, option._default);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << option._dottedName << "\": "
+ << "mismatch between declared type and type of default value: "
+ << ret.toString();
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+ }
+ }
+
+ // Make sure that if we are registering a composing option it has the type of StringVector
+ if (option._isComposing) {
+ if (option._type != StringVector) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << option._dottedName << "\": "
+ << "only options registered as StringVector can be composing";
+ return Status(ErrorCodes::TypeMismatch, sb.str());
+ }
+ }
+
+ // 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 (option._isComposing && !option._default.isEmpty()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << option._dottedName << "\": "
+ << "Cannot register a default value for a composing option";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+
+ // Disallow registering an implicit value for a composing option since the interaction
+ // between the two is unclear
+ if (option._isComposing && !option._implicit.isEmpty()) {
+ StringBuilder sb;
+ sb << "Could not register option \"" << option._dottedName << "\": "
+ << "Cannot register an implicit value for a composing option";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+
_options.push_back(option);
return Status::OK();
}
@@ -86,30 +190,279 @@ namespace optionenvironment {
/** Helper function to convert the values of our OptionType enum into the classes that
* boost::program_option uses to pass around this information
*/
- po::value_semantic* typeToBoostType(OptionType type) {
+ Status typeToBoostType(std::auto_ptr<po::value_semantic>* boostType,
+ OptionType type,
+ const Value defaultValue = Value(),
+ const Value implicitValue = Value()) {
switch (type) {
- case StringVector: return po::value< std::vector<std::string> >();
- case Bool: return po::value<bool>();
- case Double: return po::value<double>();
- case Int: return po::value<int>();
- case Long: return po::value<long>();
- case String: return po::value<std::string>();
- case UnsignedLongLong: return po::value<unsigned long long>();
- case Unsigned: return po::value<unsigned>();
- case Switch: return po::bool_switch();
- default: return NULL; /* XXX: should not get here */
+ 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 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 Double:
+ {
+ std::auto_ptr<po::typed_value<double> >
+ boostTypeBuilder(po::value<double>());
+
+ if (!implicitValue.isEmpty()) {
+ double 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()) {
+ double 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 Int:
+ {
+ std::auto_ptr<po::typed_value<int> > boostTypeBuilder(po::value<int>());
+
+ if (!implicitValue.isEmpty()) {
+ int 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()) {
+ int 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 Long:
+ {
+ std::auto_ptr<po::typed_value<long> > boostTypeBuilder(po::value<long>());
+
+ if (!implicitValue.isEmpty()) {
+ long 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()) {
+ long 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:
+ {
+ std::auto_ptr<po::typed_value<std::string> >
+ boostTypeBuilder(po::value<std::string>());
+
+ if (!implicitValue.isEmpty()) {
+ std::string 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()) {
+ std::string 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 UnsignedLongLong:
+ {
+ std::auto_ptr<po::typed_value<unsigned long long> >
+ boostTypeBuilder(po::value<unsigned long long>());
+
+ if (!implicitValue.isEmpty()) {
+ unsigned long long 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()) {
+ unsigned long long 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 Unsigned:
+ {
+ std::auto_ptr<po::typed_value<unsigned> >
+ boostTypeBuilder(po::value<unsigned>());
+
+ if (!implicitValue.isEmpty()) {
+ unsigned 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()) {
+ unsigned 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 Switch:
+ {
+ *boostType = std::auto_ptr<po::value_semantic>(po::bool_switch());
+ return Status::OK();
+ }
+ default:
+ {
+ StringBuilder sb;
+ sb << "Unrecognized option type: " << type;
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
}
}
} // namespace
Status OptionSection::getBoostOptions(po::options_description* boostOptions,
- bool visibleOnly) const {
+ bool visibleOnly,
+ bool includeDefaults) const {
std::vector<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
if (!visibleOnly || (oditerator->_isVisible)) {
+ std::auto_ptr<po::value_semantic> boostType;
+ Status ret = typeToBoostType(&boostType,
+ oditerator->_type,
+ includeDefaults ? oditerator->_default : Value(),
+ oditerator->_implicit);
+ if (!ret.isOK()) {
+ StringBuilder sb;
+ sb << "Error getting boost type for option \""
+ << oditerator->_dottedName << "\": " << ret.toString();
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
boostOptions->add_options()(oditerator->_singleName.c_str(),
- typeToBoostType(oditerator->_type),
+ boostType.release(),
oditerator->_description.c_str());
}
}
@@ -119,7 +472,7 @@ namespace optionenvironment {
po::options_description subGroup = ositerator->_name.empty()
? po::options_description()
: po::options_description(ositerator->_name.c_str());
- ositerator->getBoostOptions(&subGroup, visibleOnly);
+ ositerator->getBoostOptions(&subGroup, visibleOnly, includeDefaults);
boostOptions->add(subGroup);
}
@@ -156,6 +509,23 @@ namespace optionenvironment {
return Status::OK();
}
+ Status OptionSection::getDefaults(std::map<Key, Value>* values) const {
+
+ std::vector<OptionDescription>::const_iterator oditerator;
+ for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
+ if (!oditerator->_default.isEmpty()) {
+ (*values)[oditerator->_dottedName] = oditerator->_default;
+ }
+ }
+
+ std::vector<OptionSection>::const_iterator ositerator;
+ for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
+ ositerator->getDefaults(values);
+ }
+
+ return Status::OK();
+ }
+
std::string OptionSection::positionalHelpString(const std::string& execName) const {
po::positional_options_description boostPositionalOptions;
diff --git a/src/mongo/util/options_parser/option_section.h b/src/mongo/util/options_parser/option_section.h
index 86e0a9d2e54..e0699232773 100644
--- a/src/mongo/util/options_parser/option_section.h
+++ b/src/mongo/util/options_parser/option_section.h
@@ -84,7 +84,8 @@ namespace optionenvironment {
// These functions are used by the OptionsParser to make calls into boost::program_options
Status getBoostOptions(po::options_description* boostOptions,
- bool visibleOnly = false) const;
+ bool visibleOnly = false,
+ bool includeDefaults = false) const;
Status getBoostPositionalOptions(
po::positional_options_description* boostPositionalOptions) const;
@@ -93,6 +94,12 @@ namespace optionenvironment {
// found has been registered and has the correct type
Status getAllOptions(std::vector<OptionDescription>* options) 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;
+
std::string positionalHelpString(const std::string& execName) const;
std::string helpString() const;
diff --git a/src/mongo/util/options_parser/options_parser.cpp b/src/mongo/util/options_parser/options_parser.cpp
index 37d7067d9c7..f4de3e2c2ff 100644
--- a/src/mongo/util/options_parser/options_parser.cpp
+++ b/src/mongo/util/options_parser/options_parser.cpp
@@ -310,6 +310,59 @@ namespace optionenvironment {
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;
+ }
+
+ for(std::vector<OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+ if (iterator->_isComposing) {
+ std::vector<std::string> source_value;
+ ret = source.get(iterator->_dottedName, &source_value);
+ 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()) {
+ std::vector<std::string> dest_value;
+ ret = dest->get(iterator->_dottedName, &dest_value);
+ 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 source_value on the end of dest_value
+ dest_value.insert(dest_value.end(),
+ source_value.begin(),
+ source_value.end());
+
+ // Set the resulting value in our output environment
+ ret = dest->set(Key(iterator->_dottedName), Value(dest_value));
+ if (!ret.isOK()) {
+ return ret;
+ }
+ }
+ }
+ }
+
+ return Status::OK();
+ }
+
} // namespace
/**
@@ -451,6 +504,46 @@ namespace optionenvironment {
}
/**
+ * Extract default values from the given options and add to environment
+ */
+ Status OptionsParser::getDefaultValues(const OptionSection& options,
+ Environment* environment) {
+ Environment defaultEnvironment;
+
+ // This should have been caught at the time we registered our options, but we check that the
+ // default types match our declared types here just to be sure.
+ Status ret = addTypeConstraints(options, &defaultEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ std::map <Key, Value> defaultOptions;
+
+ 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 = defaultEnvironment.set(iterator->first, iterator->second);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ }
+
+ ret = defaultEnvironment.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ *environment = defaultEnvironment;
+
+ return Status::OK();
+ }
+
+ /**
* Reads the entire config file into the output string. This is done this way because the JSON
* parser only takes complete strings
*/
@@ -550,10 +643,17 @@ namespace optionenvironment {
const std::map<std::string, std::string>& env, // XXX: Currently unused
Environment* environment) {
+ Environment defaultEnvironment;
Environment commandLineEnvironment;
Environment configEnvironment;
+ Environment composedEnvironment;
- Status ret = parseCommandLine(options, argv, &commandLineEnvironment);
+ Status ret = getDefaultValues(options, &defaultEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = parseCommandLine(options, argv, &commandLineEnvironment);
if (!ret.isOK()) {
return ret;
}
@@ -602,8 +702,30 @@ namespace optionenvironment {
}
}
+ // 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.
+ ret = addCompositions(options, commandLineEnvironment, &composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addCompositions(options, configEnvironment, &composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addCompositions(options, defaultEnvironment, &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(defaultEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
ret = environment->setAll(configEnvironment);
if (!ret.isOK()) {
return ret;
@@ -613,6 +735,12 @@ namespace optionenvironment {
return ret;
}
+ // Add this last because it represents the aggregated results of composing all environments
+ ret = environment->setAll(composedEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
return Status::OK();
}
diff --git a/src/mongo/util/options_parser/options_parser.h b/src/mongo/util/options_parser/options_parser.h
index dd401b04f5e..ceef90bb864 100644
--- a/src/mongo/util/options_parser/options_parser.h
+++ b/src/mongo/util/options_parser/options_parser.h
@@ -103,6 +103,9 @@ namespace optionenvironment {
/** Handles parsing of a JSON config string and adds the results to the given Environment */
Status parseJSONConfigFile(const OptionSection&, const std::string& config, Environment*);
+ /** Gets defaults from the OptionSection and adds the results to the given Environment */
+ Status getDefaultValues(const OptionSection&, Environment*);
+
/** Detects whether the given string represents a JSON config file or an INI config file */
bool isJSONConfig(const std::string& config);
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index d539279aca2..21f675189ea 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -73,6 +73,29 @@ namespace {
moe::Int)));
}
+ TEST(Registration, DefaultValueWrongType) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("help", "help", moe::Switch, "Display help"));
+ ASSERT_NOT_OK(testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port",
+ true, moe::Value("String"))));
+ }
+
+ TEST(Registration, ComposableNotVector) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ ASSERT_NOT_OK(testOpts.addOption(moe::OptionDescription("setParameter", "setParameter",
+ moe::String,
+ "Multiple Values", true/*visible*/,
+ moe::Value()/*no default*/,
+ moe::Value()/*no implicit value*/,
+ true/*composing*/)));
+ }
+
TEST(Parsing, Good) {
moe::OptionsParser parser;
moe::Environment environment;
@@ -372,6 +395,119 @@ namespace {
ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
}
+ TEST(Parsing, DefaultValue) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("help", "help", moe::Switch, "Display help"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ 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.addOption(moe::OptionDescription("help", "help", moe::Switch, "Display help"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ 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, ImplicitValue) {
+ moe::OptionsParser parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("help", "help", moe::Switch, "Display help"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ moe::Value(6),
+ 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.addOption(moe::OptionDescription("help", "help", moe::Switch, "Display help"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ moe::Value(6),
+ 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.addOption(moe::OptionDescription("help", "help", moe::Switch, "Display help"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ moe::Value(6),
+ 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(Style, NoSticky) {
moe::OptionsParser parser;
moe::Environment environment;
@@ -561,6 +697,32 @@ namespace {
ASSERT_EQUALS(str, "NotCommented");
}
+ TEST(INIConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("config", "config",
+ moe::String, "Config file to parse"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ 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(JSONConfigFile, Basic) {
OptionsParserTester parser;
moe::Environment environment;
@@ -842,6 +1004,32 @@ namespace {
ASSERT_NOT_OK(parser.run(testOpts, argv, env_map, &environment));
}
+ TEST(JSONConfigFile, DefaultValueOverride) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("config", "config",
+ moe::String, "Config file to parse"));
+ testOpts.addOption(moe::OptionDescription("port", "port", moe::Int, "Port", true,
+ 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;
@@ -927,4 +1115,88 @@ namespace {
ASSERT_OK(parser.run(testOpts, argv, env_map, &environment));
}
+ TEST(JSONConfigFile, Composing) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("config", "config",
+ moe::String, "Config file to parse"));
+ testOpts.addOption(moe::OptionDescription("setParameter", "setParameter", moe::StringVector,
+ "Multiple Values", true/*visible*/,
+ moe::Value()/*no default*/,
+ moe::Value()/*no implicit value*/,
+ true/*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, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ }
+
+ TEST(INIConfigFile, Composing) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOption(moe::OptionDescription("config", "config",
+ moe::String, "Config file to parse"));
+ testOpts.addOption(moe::OptionDescription("setParameter", "setParameter", moe::StringVector,
+ "Multiple Values", true/*visible*/,
+ moe::Value()/*no default*/,
+ moe::Value()/*no implicit value*/,
+ true/*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, "val1");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val2");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val3");
+ setParameterit++;
+ ASSERT_EQUALS(*setParameterit, "val4");
+ }
+
} // unnamed namespace