Commit 4dac11c025cf0782b298e2ba461c956d2c2e6ffe
Committed by
Henry Schreiner
1 parent
c1fb53f0
Finishing addition of ->configurable()
Showing
5 changed files
with
75 additions
and
33 deletions
include/CLI/App.hpp
include/CLI/Error.hpp
| ... | ... | @@ -86,30 +86,32 @@ class IncorrectConstruction : public ConstructionError { |
| 86 | 86 | CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction) |
| 87 | 87 | CLI11_ERROR_SIMPLE(IncorrectConstruction) |
| 88 | 88 | static IncorrectConstruction PositionalFlag(std::string name) { |
| 89 | - return IncorrectConstruction(name + ": Flags cannot be positional");} | |
| 89 | + return IncorrectConstruction(name + ": Flags cannot be positional"); | |
| 90 | + } | |
| 90 | 91 | static IncorrectConstruction Set0Opt(std::string name) { |
| 91 | - return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");} | |
| 92 | + return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead"); | |
| 93 | + } | |
| 92 | 94 | static IncorrectConstruction ChangeNotVector(std::string name) { |
| 93 | - return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");} | |
| 95 | + return IncorrectConstruction(name + ": You can only change the expected arguments for vectors"); | |
| 96 | + } | |
| 94 | 97 | static IncorrectConstruction AfterMultiOpt(std::string name) { |
| 95 | - return IncorrectConstruction(name + ": You can't change expected arguments after you've changed the multi option policy!");} | |
| 98 | + return IncorrectConstruction( | |
| 99 | + name + ": You can't change expected arguments after you've changed the multi option policy!"); | |
| 100 | + } | |
| 96 | 101 | static IncorrectConstruction MissingOption(std::string name) { |
| 97 | - return IncorrectConstruction("Option " + name + " is not defined");} | |
| 102 | + return IncorrectConstruction("Option " + name + " is not defined"); | |
| 103 | + } | |
| 98 | 104 | static IncorrectConstruction MultiOptionPolicy(std::string name) { |
| 99 | - return IncorrectConstruction(name + ": multi_option_policy only works for flags and single value options");} | |
| 100 | - | |
| 105 | + return IncorrectConstruction(name + ": multi_option_policy only works for flags and single value options"); | |
| 106 | + } | |
| 101 | 107 | }; |
| 102 | 108 | |
| 103 | 109 | /// Thrown on construction of a bad name |
| 104 | 110 | class BadNameString : public ConstructionError { |
| 105 | 111 | CLI11_ERROR_DEF(ConstructionError, BadNameString) |
| 106 | 112 | CLI11_ERROR_SIMPLE(BadNameString) |
| 107 | - static BadNameString OneCharName(std::string name) { | |
| 108 | - return BadNameString("Invalid one char name: " + name); | |
| 109 | - } | |
| 110 | - static BadNameString BadLongName(std::string name) { | |
| 111 | - return BadNameString("Bad long name: " + name); | |
| 112 | - } | |
| 113 | + static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); } | |
| 114 | + static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); } | |
| 113 | 115 | static BadNameString DashesOnly(std::string name) { |
| 114 | 116 | return BadNameString("Must have a name, not just dashes: " + name); |
| 115 | 117 | } |
| ... | ... | @@ -162,7 +164,7 @@ class RuntimeError : public ParseError { |
| 162 | 164 | class FileError : public ParseError { |
| 163 | 165 | CLI11_ERROR_DEF(ParseError, FileError) |
| 164 | 166 | CLI11_ERROR_SIMPLE(FileError) |
| 165 | - static FileError Missing(std::string name) {return FileError(name + " was not readable (missing?)");} | |
| 167 | + static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); } | |
| 166 | 168 | }; |
| 167 | 169 | |
| 168 | 170 | /// Thrown when conversion call back fails, such as when an int fails to coerce to a string |
| ... | ... | @@ -174,9 +176,11 @@ class ConversionError : public ParseError { |
| 174 | 176 | ConversionError(std::string name, std::vector<std::string> results) |
| 175 | 177 | : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {} |
| 176 | 178 | static ConversionError TooManyInputsFlag(std::string name) { |
| 177 | - return ConversionError(name + ": too many inputs for a flag");} | |
| 179 | + return ConversionError(name + ": too many inputs for a flag"); | |
| 180 | + } | |
| 178 | 181 | static ConversionError TrueFalse(std::string name) { |
| 179 | - return ConversionError(name + ": Should be true/false or a number");} | |
| 182 | + return ConversionError(name + ": Should be true/false or a number"); | |
| 183 | + } | |
| 180 | 184 | }; |
| 181 | 185 | |
| 182 | 186 | /// Thrown when validation of results fails |
| ... | ... | @@ -189,15 +193,14 @@ class ValidationError : public ParseError { |
| 189 | 193 | /// Thrown when a required option is missing |
| 190 | 194 | class RequiredError : public ParseError { |
| 191 | 195 | CLI11_ERROR_DEF(ParseError, RequiredError) |
| 192 | - RequiredError(std::string name) : RequiredError(name + " is required") {} | |
| 196 | + RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {} | |
| 193 | 197 | static RequiredError Subcommand(size_t min_subcom) { |
| 194 | 198 | if(min_subcom == 1) |
| 195 | 199 | return RequiredError("A subcommand"); |
| 196 | 200 | else |
| 197 | - return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError); | |
| 201 | + return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands", | |
| 202 | + ExitCodes::RequiredError); | |
| 198 | 203 | } |
| 199 | - | |
| 200 | - | |
| 201 | 204 | }; |
| 202 | 205 | |
| 203 | 206 | /// Thrown when the wrong number of arguments has been received |
| ... | ... | @@ -210,13 +213,13 @@ class ArgumentMismatch : public ParseError { |
| 210 | 213 | : ("Expected at least " + std::to_string(-expected) + " arguments to " + name + |
| 211 | 214 | ", got " + std::to_string(recieved)), |
| 212 | 215 | ExitCodes::ArgumentMismatch) {} |
| 213 | - | |
| 216 | + | |
| 214 | 217 | static ArgumentMismatch AtLeast(std::string name, int num) { |
| 215 | - return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required");} | |
| 218 | + return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required"); | |
| 219 | + } | |
| 216 | 220 | static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) { |
| 217 | - return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");} | |
| 218 | - | |
| 219 | - | |
| 221 | + return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing"); | |
| 222 | + } | |
| 220 | 223 | }; |
| 221 | 224 | |
| 222 | 225 | /// Thrown when a requires option is missing |
| ... | ... | @@ -247,9 +250,10 @@ class ExtrasError : public ParseError { |
| 247 | 250 | class INIError : public ParseError { |
| 248 | 251 | CLI11_ERROR_DEF(ParseError, INIError) |
| 249 | 252 | CLI11_ERROR_SIMPLE(INIError) |
| 250 | - static INIError Extras(std::string item) {return INIError("INI was not able to parse " + item);} | |
| 251 | - static INIError NotConfigurable(std::string item) {return INIError(item + ": This option is not allowed in a configuration file");} | |
| 252 | - | |
| 253 | + static INIError Extras(std::string item) { return INIError("INI was not able to parse " + item); } | |
| 254 | + static INIError NotConfigurable(std::string item) { | |
| 255 | + return INIError(item + ": This option is not allowed in a configuration file"); | |
| 256 | + } | |
| 253 | 257 | }; |
| 254 | 258 | |
| 255 | 259 | /// Thrown when validation fails before parsing | ... | ... |
include/CLI/Option.hpp
| ... | ... | @@ -43,15 +43,15 @@ template <typename CRTP> class OptionBase { |
| 43 | 43 | |
| 44 | 44 | /// Allow this option to be given in a configuration file |
| 45 | 45 | bool configurable_{true}; |
| 46 | - | |
| 46 | + | |
| 47 | 47 | /// Policy for multiple arguments when `expected_ == 1` (can be set on bool flags, too) |
| 48 | 48 | MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw}; |
| 49 | - | |
| 50 | 49 | |
| 51 | 50 | template <typename T> void copy_to(T *other) const { |
| 52 | 51 | other->group(group_); |
| 53 | 52 | other->required(required_); |
| 54 | 53 | other->ignore_case(ignore_case_); |
| 54 | + other->configurable(configurable_); | |
| 55 | 55 | other->multi_option_policy(multi_option_policy_); |
| 56 | 56 | } |
| 57 | 57 | |
| ... | ... | @@ -84,7 +84,7 @@ template <typename CRTP> class OptionBase { |
| 84 | 84 | |
| 85 | 85 | /// The status of ignore case |
| 86 | 86 | bool get_ignore_case() const { return ignore_case_; } |
| 87 | - | |
| 87 | + | |
| 88 | 88 | /// The status of configurable |
| 89 | 89 | bool get_configurable() const { return configurable_; } |
| 90 | 90 | |
| ... | ... | @@ -113,7 +113,7 @@ template <typename CRTP> class OptionBase { |
| 113 | 113 | self->multi_option_policy(MultiOptionPolicy::Join); |
| 114 | 114 | return self; |
| 115 | 115 | } |
| 116 | - | |
| 116 | + | |
| 117 | 117 | /// Allow in a configuration file |
| 118 | 118 | CRTP *configurable(bool value = true) { |
| 119 | 119 | configurable_ = value; | ... | ... |
tests/CreationTest.cpp
| ... | ... | @@ -303,12 +303,14 @@ TEST_F(TApp, OptionFromDefaultsSubcommands) { |
| 303 | 303 | EXPECT_FALSE(app.option_defaults()->get_required()); |
| 304 | 304 | EXPECT_EQ(app.option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::Throw); |
| 305 | 305 | EXPECT_FALSE(app.option_defaults()->get_ignore_case()); |
| 306 | + EXPECT_TRUE(app.option_defaults()->get_configurable()); | |
| 306 | 307 | EXPECT_EQ(app.option_defaults()->get_group(), "Options"); |
| 307 | 308 | |
| 308 | 309 | app.option_defaults() |
| 309 | 310 | ->required() |
| 310 | 311 | ->multi_option_policy(CLI::MultiOptionPolicy::TakeLast) |
| 311 | 312 | ->ignore_case() |
| 313 | + ->configurable(false) | |
| 312 | 314 | ->group("Something"); |
| 313 | 315 | |
| 314 | 316 | auto app2 = app.add_subcommand("app2"); |
| ... | ... | @@ -316,6 +318,7 @@ TEST_F(TApp, OptionFromDefaultsSubcommands) { |
| 316 | 318 | EXPECT_TRUE(app2->option_defaults()->get_required()); |
| 317 | 319 | EXPECT_EQ(app2->option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::TakeLast); |
| 318 | 320 | EXPECT_TRUE(app2->option_defaults()->get_ignore_case()); |
| 321 | + EXPECT_FALSE(app2->option_defaults()->get_configurable()); | |
| 319 | 322 | EXPECT_EQ(app2->option_defaults()->get_group(), "Something"); |
| 320 | 323 | } |
| 321 | 324 | ... | ... |
tests/IniTest.cpp
| ... | ... | @@ -379,6 +379,41 @@ TEST_F(TApp, IniFailure) { |
| 379 | 379 | EXPECT_THROW(run(), CLI::INIError); |
| 380 | 380 | } |
| 381 | 381 | |
| 382 | +TEST_F(TApp, IniConfigurable) { | |
| 383 | + | |
| 384 | + TempFile tmpini{"TestIniTmp.ini"}; | |
| 385 | + | |
| 386 | + app.add_config("--config", tmpini); | |
| 387 | + bool value; | |
| 388 | + app.add_flag("--val", value)->configurable(true); | |
| 389 | + | |
| 390 | + { | |
| 391 | + std::ofstream out{tmpini}; | |
| 392 | + out << "[default]" << std::endl; | |
| 393 | + out << "val=1" << std::endl; | |
| 394 | + } | |
| 395 | + | |
| 396 | + EXPECT_NO_THROW(run()); | |
| 397 | + EXPECT_TRUE(value); | |
| 398 | +} | |
| 399 | + | |
| 400 | +TEST_F(TApp, IniNotConfigurable) { | |
| 401 | + | |
| 402 | + TempFile tmpini{"TestIniTmp.ini"}; | |
| 403 | + | |
| 404 | + app.add_config("--config", tmpini); | |
| 405 | + bool value; | |
| 406 | + app.add_flag("--val", value)->configurable(false); | |
| 407 | + | |
| 408 | + { | |
| 409 | + std::ofstream out{tmpini}; | |
| 410 | + out << "[default]" << std::endl; | |
| 411 | + out << "val=1" << std::endl; | |
| 412 | + } | |
| 413 | + | |
| 414 | + EXPECT_THROW(run(), CLI::INIError); | |
| 415 | +} | |
| 416 | + | |
| 382 | 417 | TEST_F(TApp, IniSubFailure) { |
| 383 | 418 | |
| 384 | 419 | TempFile tmpini{"TestIniTmp.ini"}; | ... | ... |