Specialize ConfigOption for bool to accept "truthy" / "falsy" values

This commit is contained in:
Stephen Shelton 2020-04-29 12:32:07 -06:00
parent 331770b348
commit 320564d792
No known key found for this signature in database
GPG Key ID: EE4BADACCE8B631C
3 changed files with 41 additions and 5 deletions

View File

@ -16,6 +16,18 @@ namespace llarp
{ {
} }
template <>
bool
OptionDefinition<bool>::fromString(const std::string& input)
{
if (input == "false" || input == "off" || input == "0" || input == "no")
return false;
else if (input == "true" || input == "on" || input == "1" || input == "yes")
return true;
else
throw std::invalid_argument(stringify(input, " is not a valid bool"));
}
ConfigDefinition& ConfigDefinition&
ConfigDefinition::defineOption(OptionDefinition_ptr def) ConfigDefinition::defineOption(OptionDefinition_ptr def)
{ {

View File

@ -168,17 +168,19 @@ namespace llarp
stringify("duplicate value for ", name, ", previous value: ", parsedValues[0])); stringify("duplicate value for ", name, ", previous value: ", parsedValues[0]));
} }
parsedValues.emplace_back(fromString(input));
}
T
fromString(const std::string& input)
{
std::istringstream iss(input); std::istringstream iss(input);
T t; T t;
iss >> t; iss >> t;
if (iss.fail()) if (iss.fail())
{
throw std::invalid_argument(stringify(input, " is not a valid ", typeid(T).name())); throw std::invalid_argument(stringify(input, " is not a valid ", typeid(T).name()));
}
else else
{ return t;
parsedValues.emplace_back(std::move(t));
}
} }
std::string std::string
@ -239,6 +241,12 @@ namespace llarp
std::function<void(T)> acceptor; std::function<void(T)> acceptor;
}; };
/// Specialization for bool types. We don't want to use stringstream parsing in this
/// case because we want to accept "truthy" and "falsy" string values (e.g. "off" == false)
template <>
bool
OptionDefinition<bool>::fromString(const std::string& input);
using UndeclaredValueHandler = using UndeclaredValueHandler =
std::function<void(string_view section, string_view name, string_view value)>; std::function<void(string_view section, string_view name, string_view value)>;

View File

@ -387,3 +387,19 @@ TEST_CASE("ConfigDefinition [bind]iface regression", "[config regression]")
CHECK(undeclaredName == "enp35s0"); CHECK(undeclaredName == "enp35s0");
CHECK(undeclaredValue == "1091"); CHECK(undeclaredValue == "1091");
} }
TEST_CASE("ConfigDefinition truthy bool values", "[config]")
{
llarp::OptionDefinition<bool> def("foo", "bar", false, true);
// defaults to true
auto maybe = def.getValue();
CHECK(maybe.has_value());
CHECK(maybe.value() == true);
// "off" should result in false
CHECK_NOTHROW(def.parseValue("off"));
maybe = def.getValue();
CHECK(maybe.has_value());
CHECK(maybe.value() == false);
}