Commit a958ffece27fd4cef59ff4809bb672810d65f0b0

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

Dropping name from simple print, better seperation for Errors

Some error codes are renamed
include/CLI/App.hpp
@@ -746,7 +746,7 @@ class App { @@ -746,7 +746,7 @@ class App {
746 return e.get_exit_code(); 746 return e.get_exit_code();
747 } 747 }
748 748
749 - if(e.exit_code != static_cast<int>(ExitCodes::Success)) { 749 + if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
750 if(failure_message_) 750 if(failure_message_)
751 err << failure_message_(this, e) << std::flush; 751 err << failure_message_(this, e) << std::flush;
752 } 752 }
@@ -1514,7 +1514,7 @@ inline std::string simple(const App *app, const Error &amp;e) { @@ -1514,7 +1514,7 @@ inline std::string simple(const App *app, const Error &amp;e) {
1514 }; 1514 };
1515 1515
1516 inline std::string help(const App *app, const Error &e) { 1516 inline std::string help(const App *app, const Error &e) {
1517 - std::string header = std::string("ERROR: ") + e.what() + "\n"; 1517 + std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
1518 header += app->help(); 1518 header += app->help();
1519 return header; 1519 return header;
1520 }; 1520 };
include/CLI/Error.hpp
@@ -7,6 +7,20 @@ @@ -7,6 +7,20 @@
7 #include <stdexcept> 7 #include <stdexcept>
8 #include <string> 8 #include <string>
9 9
  10 +// Use one of these on all error classes
  11 +#define CLI11_ERROR_DEF(parent, name) \
  12 + protected: \
  13 + name(std::string name, std::string msg, int exit_code) : parent(name, msg, exit_code) {} \
  14 + name(std::string name, std::string msg, ExitCodes exit_code) : parent(name, msg, exit_code) {} \
  15 + \
  16 + public: \
  17 + name(std::string msg, ExitCodes exit_code) : parent(#name, msg, exit_code) {} \
  18 + name(std::string msg, int exit_code) : parent(#name, msg, exit_code) {}
  19 +
  20 +// This is added after the one above if a class is used directly and builds its own message
  21 +#define CLI11_ERROR_SIMPLE(name) \
  22 + name(std::string msg) : name(#name, msg, ExitCodes::name) {}
  23 +
10 namespace CLI { 24 namespace CLI {
11 25
12 /// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut, 26 /// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut,
@@ -17,15 +31,15 @@ enum class ExitCodes { @@ -17,15 +31,15 @@ enum class ExitCodes {
17 BadNameString, 31 BadNameString,
18 OptionAlreadyAdded, 32 OptionAlreadyAdded,
19 File, 33 File,
20 - Conversion,  
21 - Validation,  
22 - Required,  
23 - Requires,  
24 - Excludes,  
25 - Extras,  
26 - ExtrasINI,  
27 - Invalid,  
28 - Horrible, 34 + ConversionError,
  35 + ValidationError,
  36 + RequiredError,
  37 + RequiresError,
  38 + ExcludesError,
  39 + ExtrasError,
  40 + ExtrasINIError,
  41 + InvalidError,
  42 + HorribleError,
29 OptionNotFound, 43 OptionNotFound,
30 BaseClass = 127 44 BaseClass = 127
31 }; 45 };
@@ -39,126 +53,141 @@ enum class ExitCodes { @@ -39,126 +53,141 @@ enum class ExitCodes {
39 /// @{ 53 /// @{
40 54
41 /// All errors derive from this one 55 /// All errors derive from this one
42 -struct Error : public std::runtime_error { 56 +class Error : public std::runtime_error {
43 int exit_code; 57 int exit_code;
  58 + std::string name{"Error"};
  59 +
  60 + public:
44 int get_exit_code() const { return exit_code; } 61 int get_exit_code() const { return exit_code; }
45 62
46 - Error(std::string parent, std::string name, ExitCodes exit_code = ExitCodes::BaseClass)  
47 - : runtime_error(parent + ": " + name), exit_code(static_cast<int>(exit_code)) {}  
48 - Error(std::string parent, std::string name, int exit_code = static_cast<int>(ExitCodes::BaseClass))  
49 - : runtime_error(parent + ": " + name), exit_code(exit_code) {} 63 + std::string get_name() const { return name; }
  64 +
  65 + Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
  66 + : runtime_error(msg), exit_code(exit_code), name(name) {}
  67 +
  68 + Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
50 }; 69 };
51 70
  71 +// Note: Using Error::Error constructors does not work on GCC 4.7
  72 +
52 /// Construction errors (not in parsing) 73 /// Construction errors (not in parsing)
53 -struct ConstructionError : public Error {  
54 - // Using Error::Error constructors seem to not work on GCC 4.7  
55 - ConstructionError(std::string parent, std::string name, ExitCodes exit_code = ExitCodes::BaseClass)  
56 - : Error(parent, name, exit_code) {} 74 +class ConstructionError : public Error {
  75 + CLI11_ERROR_DEF(Error, ConstructionError)
57 }; 76 };
58 77
59 /// Thrown when an option is set to conflicting values (non-vector and multi args, for example) 78 /// Thrown when an option is set to conflicting values (non-vector and multi args, for example)
60 -struct IncorrectConstruction : public ConstructionError {  
61 - IncorrectConstruction(std::string name)  
62 - : ConstructionError("IncorrectConstruction", name, ExitCodes::IncorrectConstruction) {} 79 +class IncorrectConstruction : public ConstructionError {
  80 + CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction)
  81 + CLI11_ERROR_SIMPLE(IncorrectConstruction)
63 }; 82 };
64 83
65 /// Thrown on construction of a bad name 84 /// Thrown on construction of a bad name
66 -struct BadNameString : public ConstructionError {  
67 - BadNameString(std::string name) : ConstructionError("BadNameString", name, ExitCodes::BadNameString) {} 85 +class BadNameString : public ConstructionError {
  86 + CLI11_ERROR_DEF(ConstructionError, BadNameString)
  87 + CLI11_ERROR_SIMPLE(BadNameString)
68 }; 88 };
69 89
70 /// Thrown when an option already exists 90 /// Thrown when an option already exists
71 -struct OptionAlreadyAdded : public ConstructionError {  
72 - OptionAlreadyAdded(std::string name)  
73 - : ConstructionError("OptionAlreadyAdded", name, ExitCodes::OptionAlreadyAdded) {} 91 +class OptionAlreadyAdded : public ConstructionError {
  92 + CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded)
  93 + CLI11_ERROR_SIMPLE(OptionAlreadyAdded)
74 }; 94 };
75 95
76 // Parsing errors 96 // Parsing errors
77 97
78 /// Anything that can error in Parse 98 /// Anything that can error in Parse
79 -struct ParseError : public Error {  
80 - ParseError(std::string parent, std::string name, ExitCodes exit_code = ExitCodes::BaseClass)  
81 - : Error(parent, name, exit_code) {}  
82 - ParseError(std::string parent, std::string name, int exit_code = static_cast<int>(ExitCodes::BaseClass))  
83 - : Error(parent, name, exit_code) {} 99 +class ParseError : public Error {
  100 + CLI11_ERROR_DEF(Error, ParseError)
84 }; 101 };
85 102
86 // Not really "errors" 103 // Not really "errors"
87 104
88 /// This is a successful completion on parsing, supposed to exit 105 /// This is a successful completion on parsing, supposed to exit
89 -struct Success : public ParseError {  
90 - Success() : ParseError("Success", "Successfully completed, should be caught and quit", ExitCodes::Success) {} 106 +class Success : public ParseError {
  107 + CLI11_ERROR_DEF(ParseError, Success)
  108 + Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
91 }; 109 };
92 110
93 /// -h or --help on command line 111 /// -h or --help on command line
94 -struct CallForHelp : public ParseError {  
95 - CallForHelp()  
96 - : ParseError("CallForHelp", "This should be caught in your main function, see examples", ExitCodes::Success) {} 112 +class CallForHelp : public ParseError {
  113 + CLI11_ERROR_DEF(ParseError, CallForHelp)
  114 + CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
97 }; 115 };
98 116
99 /// Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error code. 117 /// Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error code.
100 -struct RuntimeError : public ParseError {  
101 - RuntimeError(int exit_code = 1) : ParseError("RuntimeError", "runtime error", exit_code) {} 118 +class RuntimeError : public ParseError {
  119 + CLI11_ERROR_DEF(ParseError, RuntimeError)
  120 + RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
102 }; 121 };
103 122
104 /// Thrown when parsing an INI file and it is missing 123 /// Thrown when parsing an INI file and it is missing
105 -struct FileError : public ParseError {  
106 - FileError(std::string name) : ParseError("FileError", name, ExitCodes::File) {} 124 +class FileError : public ParseError {
  125 + CLI11_ERROR_DEF(ParseError, FileError)
  126 + FileError(std::string msg) : FileError(msg, ExitCodes::File) {}
107 }; 127 };
108 128
109 /// Thrown when conversion call back fails, such as when an int fails to coerce to a string 129 /// Thrown when conversion call back fails, such as when an int fails to coerce to a string
110 -struct ConversionError : public ParseError {  
111 - ConversionError(std::string name) : ParseError("ConversionError", name, ExitCodes::Conversion) {} 130 +class ConversionError : public ParseError {
  131 + CLI11_ERROR_DEF(ParseError, ConversionError)
  132 + CLI11_ERROR_SIMPLE(ConversionError)
112 }; 133 };
113 134
114 /// Thrown when validation of results fails 135 /// Thrown when validation of results fails
115 -struct ValidationError : public ParseError {  
116 - ValidationError(std::string name) : ParseError("ValidationError", name, ExitCodes::Validation) {} 136 +class ValidationError : public ParseError {
  137 + CLI11_ERROR_DEF(ParseError, ValidationError)
  138 + CLI11_ERROR_SIMPLE(ValidationError)
117 }; 139 };
118 140
119 /// Thrown when a required option is missing 141 /// Thrown when a required option is missing
120 -struct RequiredError : public ParseError {  
121 - RequiredError(std::string name) : ParseError("RequiredError", name, ExitCodes::Required) {} 142 +class RequiredError : public ParseError {
  143 + CLI11_ERROR_DEF(ParseError, RequiredError)
  144 + CLI11_ERROR_SIMPLE(RequiredError)
122 }; 145 };
123 146
124 /// Thrown when a requires option is missing 147 /// Thrown when a requires option is missing
125 -struct RequiresError : public ParseError {  
126 - RequiresError(std::string name, std::string subname)  
127 - : ParseError("RequiresError", name + " requires " + subname, ExitCodes::Requires) {} 148 +class RequiresError : public ParseError {
  149 + CLI11_ERROR_DEF(ParseError, RequiresError)
  150 + RequiresError(std::string curname, std::string subname)
  151 + : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
128 }; 152 };
129 153
130 /// Thrown when a exludes option is present 154 /// Thrown when a exludes option is present
131 -struct ExcludesError : public ParseError {  
132 - ExcludesError(std::string name, std::string subname)  
133 - : ParseError("ExcludesError", name + " excludes " + subname, ExitCodes::Excludes) {} 155 +class ExcludesError : public ParseError {
  156 + CLI11_ERROR_DEF(ParseError, ExcludesError)
  157 + ExcludesError(std::string curname, std::string subname)
  158 + : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
134 }; 159 };
135 160
136 /// Thrown when too many positionals or options are found 161 /// Thrown when too many positionals or options are found
137 -struct ExtrasError : public ParseError {  
138 - ExtrasError(std::string name) : ParseError("ExtrasError", name, ExitCodes::Extras) {} 162 +class ExtrasError : public ParseError {
  163 + CLI11_ERROR_DEF(ParseError, ExtrasError)
  164 + CLI11_ERROR_SIMPLE(ExtrasError)
139 }; 165 };
140 166
141 /// Thrown when extra values are found in an INI file 167 /// Thrown when extra values are found in an INI file
142 -struct ExtrasINIError : public ParseError {  
143 - ExtrasINIError(std::string name) : ParseError("ExtrasINIError", name, ExitCodes::ExtrasINI) {} 168 +class ExtrasINIError : public ParseError {
  169 + CLI11_ERROR_DEF(ParseError, ExtrasINIError)
  170 + CLI11_ERROR_SIMPLE(ExtrasINIError)
144 }; 171 };
145 172
146 /// Thrown when validation fails before parsing 173 /// Thrown when validation fails before parsing
147 -struct InvalidError : public ParseError {  
148 - InvalidError(std::string name) : ParseError("InvalidError", name, ExitCodes::Invalid) {} 174 +class InvalidError : public ParseError {
  175 + CLI11_ERROR_DEF(ParseError, InvalidError)
  176 + CLI11_ERROR_SIMPLE(InvalidError)
149 }; 177 };
150 178
151 -/// This is just a safety check to verify selection and parsing match  
152 -struct HorribleError : public ParseError {  
153 - HorribleError(std::string name)  
154 - : ParseError("HorribleError", "(You should never see this error) " + name, ExitCodes::Horrible) {} 179 +/// This is just a safety check to verify selection and parsing match - you should not ever see it
  180 +class HorribleError : public ParseError {
  181 + CLI11_ERROR_DEF(ParseError, HorribleError)
  182 + CLI11_ERROR_SIMPLE(HorribleError)
155 }; 183 };
156 184
157 // After parsing 185 // After parsing
158 186
159 /// Thrown when counting a non-existent option 187 /// Thrown when counting a non-existent option
160 -struct OptionNotFound : public Error {  
161 - OptionNotFound(std::string name) : Error("OptionNotFound", name, ExitCodes::OptionNotFound) {} 188 +class OptionNotFound : public Error {
  189 + CLI11_ERROR_DEF(Error, OptionNotFound)
  190 + CLI11_ERROR_SIMPLE(OptionNotFound)
162 }; 191 };
163 192
164 /// @} 193 /// @}
tests/HelpTest.cpp
@@ -309,7 +309,7 @@ TEST(THelp, RemoveHelp) { @@ -309,7 +309,7 @@ TEST(THelp, RemoveHelp) {
309 try { 309 try {
310 app.parse(input); 310 app.parse(input);
311 } catch(const CLI::ParseError &e) { 311 } catch(const CLI::ParseError &e) {
312 - EXPECT_EQ(static_cast<int>(CLI::ExitCodes::Extras), e.get_exit_code()); 312 + EXPECT_EQ(static_cast<int>(CLI::ExitCodes::ExtrasError), e.get_exit_code());
313 } 313 }
314 } 314 }
315 315
@@ -328,7 +328,7 @@ TEST(THelp, NoHelp) { @@ -328,7 +328,7 @@ TEST(THelp, NoHelp) {
328 try { 328 try {
329 app.parse(input); 329 app.parse(input);
330 } catch(const CLI::ParseError &e) { 330 } catch(const CLI::ParseError &e) {
331 - EXPECT_EQ(static_cast<int>(CLI::ExitCodes::Extras), e.get_exit_code()); 331 + EXPECT_EQ(static_cast<int>(CLI::ExitCodes::ExtrasError), e.get_exit_code());
332 } 332 }
333 } 333 }
334 334
@@ -385,14 +385,14 @@ TEST(Exit, ErrorWithoutHelp) { @@ -385,14 +385,14 @@ TEST(Exit, ErrorWithoutHelp) {
385 try { 385 try {
386 app.parse(input); 386 app.parse(input);
387 } catch(const CLI::ParseError &e) { 387 } catch(const CLI::ParseError &e) {
388 - EXPECT_EQ(static_cast<int>(CLI::ExitCodes::Extras), e.get_exit_code()); 388 + EXPECT_EQ(static_cast<int>(CLI::ExitCodes::ExtrasError), e.get_exit_code());
389 } 389 }
390 } 390 }
391 391
392 TEST(Exit, ExitCodes) { 392 TEST(Exit, ExitCodes) {
393 CLI::App app; 393 CLI::App app;
394 394
395 - auto i = static_cast<int>(CLI::ExitCodes::Extras); 395 + auto i = static_cast<int>(CLI::ExitCodes::ExtrasError);
396 EXPECT_EQ(0, app.exit(CLI::Success())); 396 EXPECT_EQ(0, app.exit(CLI::Success()));
397 EXPECT_EQ(0, app.exit(CLI::CallForHelp())); 397 EXPECT_EQ(0, app.exit(CLI::CallForHelp()));
398 EXPECT_EQ(i, app.exit(CLI::ExtrasError("Thing"))); 398 EXPECT_EQ(i, app.exit(CLI::ExtrasError("Thing")));
@@ -432,10 +432,10 @@ TEST_F(CapturedHelp, CallForHelp) { @@ -432,10 +432,10 @@ TEST_F(CapturedHelp, CallForHelp) {
432 } 432 }
433 433
434 TEST_F(CapturedHelp, NormalError) { 434 TEST_F(CapturedHelp, NormalError) {
435 - EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::Extras)); 435 + EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::ExtrasError));
436 EXPECT_EQ(out.str(), ""); 436 EXPECT_EQ(out.str(), "");
437 EXPECT_THAT(err.str(), HasSubstr("for more information")); 437 EXPECT_THAT(err.str(), HasSubstr("for more information"));
438 - EXPECT_THAT(err.str(), HasSubstr("ExtrasError")); 438 + EXPECT_THAT(err.str(), Not(HasSubstr("ExtrasError")));
439 EXPECT_THAT(err.str(), HasSubstr("Thing")); 439 EXPECT_THAT(err.str(), HasSubstr("Thing"));
440 EXPECT_THAT(err.str(), Not(HasSubstr("Usage"))); 440 EXPECT_THAT(err.str(), Not(HasSubstr("Usage")));
441 } 441 }
@@ -443,7 +443,7 @@ TEST_F(CapturedHelp, NormalError) { @@ -443,7 +443,7 @@ TEST_F(CapturedHelp, NormalError) {
443 TEST_F(CapturedHelp, RepacedError) { 443 TEST_F(CapturedHelp, RepacedError) {
444 app.set_failure_message(CLI::FailureMessage::help); 444 app.set_failure_message(CLI::FailureMessage::help);
445 445
446 - EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::Extras)); 446 + EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::ExtrasError));
447 EXPECT_EQ(out.str(), ""); 447 EXPECT_EQ(out.str(), "");
448 EXPECT_THAT(err.str(), Not(HasSubstr("for more information"))); 448 EXPECT_THAT(err.str(), Not(HasSubstr("for more information")));
449 EXPECT_THAT(err.str(), HasSubstr("ERROR: ExtrasError")); 449 EXPECT_THAT(err.str(), HasSubstr("ERROR: ExtrasError"));