Commit 4dac11c025cf0782b298e2ba461c956d2c2e6ffe

Authored by Henry Fredrick Schreiner
Committed by Henry Schreiner
1 parent c1fb53f0

Finishing addition of ->configurable()

include/CLI/App.hpp
@@ -1209,7 +1209,7 @@ class App { @@ -1209,7 +1209,7 @@ class App {
1209 1209
1210 if(!op->get_configurable()) 1210 if(!op->get_configurable())
1211 throw INIError::NotConfigurable(current.fullname); 1211 throw INIError::NotConfigurable(current.fullname);
1212 - 1212 +
1213 if(op->results_.empty()) { 1213 if(op->results_.empty()) {
1214 // Flag parsing 1214 // Flag parsing
1215 if(op->get_expected() == 0) { 1215 if(op->get_expected() == 0) {
include/CLI/Error.hpp
@@ -86,30 +86,32 @@ class IncorrectConstruction : public ConstructionError { @@ -86,30 +86,32 @@ class IncorrectConstruction : public ConstructionError {
86 CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction) 86 CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction)
87 CLI11_ERROR_SIMPLE(IncorrectConstruction) 87 CLI11_ERROR_SIMPLE(IncorrectConstruction)
88 static IncorrectConstruction PositionalFlag(std::string name) { 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 static IncorrectConstruction Set0Opt(std::string name) { 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 static IncorrectConstruction ChangeNotVector(std::string name) { 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 static IncorrectConstruction AfterMultiOpt(std::string name) { 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 static IncorrectConstruction MissingOption(std::string name) { 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 static IncorrectConstruction MultiOptionPolicy(std::string name) { 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 /// Thrown on construction of a bad name 109 /// Thrown on construction of a bad name
104 class BadNameString : public ConstructionError { 110 class BadNameString : public ConstructionError {
105 CLI11_ERROR_DEF(ConstructionError, BadNameString) 111 CLI11_ERROR_DEF(ConstructionError, BadNameString)
106 CLI11_ERROR_SIMPLE(BadNameString) 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 static BadNameString DashesOnly(std::string name) { 115 static BadNameString DashesOnly(std::string name) {
114 return BadNameString("Must have a name, not just dashes: " + name); 116 return BadNameString("Must have a name, not just dashes: " + name);
115 } 117 }
@@ -162,7 +164,7 @@ class RuntimeError : public ParseError { @@ -162,7 +164,7 @@ class RuntimeError : public ParseError {
162 class FileError : public ParseError { 164 class FileError : public ParseError {
163 CLI11_ERROR_DEF(ParseError, FileError) 165 CLI11_ERROR_DEF(ParseError, FileError)
164 CLI11_ERROR_SIMPLE(FileError) 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 /// Thrown when conversion call back fails, such as when an int fails to coerce to a string 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,9 +176,11 @@ class ConversionError : public ParseError {
174 ConversionError(std::string name, std::vector<std::string> results) 176 ConversionError(std::string name, std::vector<std::string> results)
175 : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {} 177 : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
176 static ConversionError TooManyInputsFlag(std::string name) { 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 static ConversionError TrueFalse(std::string name) { 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 /// Thrown when validation of results fails 186 /// Thrown when validation of results fails
@@ -189,15 +193,14 @@ class ValidationError : public ParseError { @@ -189,15 +193,14 @@ class ValidationError : public ParseError {
189 /// Thrown when a required option is missing 193 /// Thrown when a required option is missing
190 class RequiredError : public ParseError { 194 class RequiredError : public ParseError {
191 CLI11_ERROR_DEF(ParseError, RequiredError) 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 static RequiredError Subcommand(size_t min_subcom) { 197 static RequiredError Subcommand(size_t min_subcom) {
194 if(min_subcom == 1) 198 if(min_subcom == 1)
195 return RequiredError("A subcommand"); 199 return RequiredError("A subcommand");
196 else 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 /// Thrown when the wrong number of arguments has been received 206 /// Thrown when the wrong number of arguments has been received
@@ -210,13 +213,13 @@ class ArgumentMismatch : public ParseError { @@ -210,13 +213,13 @@ class ArgumentMismatch : public ParseError {
210 : ("Expected at least " + std::to_string(-expected) + " arguments to " + name + 213 : ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
211 ", got " + std::to_string(recieved)), 214 ", got " + std::to_string(recieved)),
212 ExitCodes::ArgumentMismatch) {} 215 ExitCodes::ArgumentMismatch) {}
213 - 216 +
214 static ArgumentMismatch AtLeast(std::string name, int num) { 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 static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) { 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 /// Thrown when a requires option is missing 225 /// Thrown when a requires option is missing
@@ -247,9 +250,10 @@ class ExtrasError : public ParseError { @@ -247,9 +250,10 @@ class ExtrasError : public ParseError {
247 class INIError : public ParseError { 250 class INIError : public ParseError {
248 CLI11_ERROR_DEF(ParseError, INIError) 251 CLI11_ERROR_DEF(ParseError, INIError)
249 CLI11_ERROR_SIMPLE(INIError) 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 /// Thrown when validation fails before parsing 259 /// Thrown when validation fails before parsing
include/CLI/Option.hpp
@@ -43,15 +43,15 @@ template &lt;typename CRTP&gt; class OptionBase { @@ -43,15 +43,15 @@ template &lt;typename CRTP&gt; class OptionBase {
43 43
44 /// Allow this option to be given in a configuration file 44 /// Allow this option to be given in a configuration file
45 bool configurable_{true}; 45 bool configurable_{true};
46 - 46 +
47 /// Policy for multiple arguments when `expected_ == 1` (can be set on bool flags, too) 47 /// Policy for multiple arguments when `expected_ == 1` (can be set on bool flags, too)
48 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw}; 48 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
49 -  
50 49
51 template <typename T> void copy_to(T *other) const { 50 template <typename T> void copy_to(T *other) const {
52 other->group(group_); 51 other->group(group_);
53 other->required(required_); 52 other->required(required_);
54 other->ignore_case(ignore_case_); 53 other->ignore_case(ignore_case_);
  54 + other->configurable(configurable_);
55 other->multi_option_policy(multi_option_policy_); 55 other->multi_option_policy(multi_option_policy_);
56 } 56 }
57 57
@@ -84,7 +84,7 @@ template &lt;typename CRTP&gt; class OptionBase { @@ -84,7 +84,7 @@ template &lt;typename CRTP&gt; class OptionBase {
84 84
85 /// The status of ignore case 85 /// The status of ignore case
86 bool get_ignore_case() const { return ignore_case_; } 86 bool get_ignore_case() const { return ignore_case_; }
87 - 87 +
88 /// The status of configurable 88 /// The status of configurable
89 bool get_configurable() const { return configurable_; } 89 bool get_configurable() const { return configurable_; }
90 90
@@ -113,7 +113,7 @@ template &lt;typename CRTP&gt; class OptionBase { @@ -113,7 +113,7 @@ template &lt;typename CRTP&gt; class OptionBase {
113 self->multi_option_policy(MultiOptionPolicy::Join); 113 self->multi_option_policy(MultiOptionPolicy::Join);
114 return self; 114 return self;
115 } 115 }
116 - 116 +
117 /// Allow in a configuration file 117 /// Allow in a configuration file
118 CRTP *configurable(bool value = true) { 118 CRTP *configurable(bool value = true) {
119 configurable_ = value; 119 configurable_ = value;
tests/CreationTest.cpp
@@ -303,12 +303,14 @@ TEST_F(TApp, OptionFromDefaultsSubcommands) { @@ -303,12 +303,14 @@ TEST_F(TApp, OptionFromDefaultsSubcommands) {
303 EXPECT_FALSE(app.option_defaults()->get_required()); 303 EXPECT_FALSE(app.option_defaults()->get_required());
304 EXPECT_EQ(app.option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::Throw); 304 EXPECT_EQ(app.option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::Throw);
305 EXPECT_FALSE(app.option_defaults()->get_ignore_case()); 305 EXPECT_FALSE(app.option_defaults()->get_ignore_case());
  306 + EXPECT_TRUE(app.option_defaults()->get_configurable());
306 EXPECT_EQ(app.option_defaults()->get_group(), "Options"); 307 EXPECT_EQ(app.option_defaults()->get_group(), "Options");
307 308
308 app.option_defaults() 309 app.option_defaults()
309 ->required() 310 ->required()
310 ->multi_option_policy(CLI::MultiOptionPolicy::TakeLast) 311 ->multi_option_policy(CLI::MultiOptionPolicy::TakeLast)
311 ->ignore_case() 312 ->ignore_case()
  313 + ->configurable(false)
312 ->group("Something"); 314 ->group("Something");
313 315
314 auto app2 = app.add_subcommand("app2"); 316 auto app2 = app.add_subcommand("app2");
@@ -316,6 +318,7 @@ TEST_F(TApp, OptionFromDefaultsSubcommands) { @@ -316,6 +318,7 @@ TEST_F(TApp, OptionFromDefaultsSubcommands) {
316 EXPECT_TRUE(app2->option_defaults()->get_required()); 318 EXPECT_TRUE(app2->option_defaults()->get_required());
317 EXPECT_EQ(app2->option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::TakeLast); 319 EXPECT_EQ(app2->option_defaults()->get_multi_option_policy(), CLI::MultiOptionPolicy::TakeLast);
318 EXPECT_TRUE(app2->option_defaults()->get_ignore_case()); 320 EXPECT_TRUE(app2->option_defaults()->get_ignore_case());
  321 + EXPECT_FALSE(app2->option_defaults()->get_configurable());
319 EXPECT_EQ(app2->option_defaults()->get_group(), "Something"); 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,6 +379,41 @@ TEST_F(TApp, IniFailure) {
379 EXPECT_THROW(run(), CLI::INIError); 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 TEST_F(TApp, IniSubFailure) { 417 TEST_F(TApp, IniSubFailure) {
383 418
384 TempFile tmpini{"TestIniTmp.ini"}; 419 TempFile tmpini{"TestIniTmp.ini"};