1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-29 12:13:52 +00:00

Dropping name from simple print, better seperation for Errors

Some error codes are renamed
This commit is contained in:
Henry Fredrick Schreiner 2017-11-22 21:55:13 -05:00 committed by Henry Schreiner
parent 1735306815
commit a958ffece2
3 changed files with 102 additions and 73 deletions

View File

@ -746,7 +746,7 @@ class App {
return e.get_exit_code(); return e.get_exit_code();
} }
if(e.exit_code != static_cast<int>(ExitCodes::Success)) { if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
if(failure_message_) if(failure_message_)
err << failure_message_(this, e) << std::flush; err << failure_message_(this, e) << std::flush;
} }
@ -1514,7 +1514,7 @@ inline std::string simple(const App *app, const Error &e) {
}; };
inline std::string help(const App *app, const Error &e) { inline std::string help(const App *app, const Error &e) {
std::string header = std::string("ERROR: ") + e.what() + "\n"; std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
header += app->help(); header += app->help();
return header; return header;
}; };

View File

@ -7,6 +7,20 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
// Use one of these on all error classes
#define CLI11_ERROR_DEF(parent, name) \
protected: \
name(std::string name, std::string msg, int exit_code) : parent(name, msg, exit_code) {} \
name(std::string name, std::string msg, ExitCodes exit_code) : parent(name, msg, exit_code) {} \
\
public: \
name(std::string msg, ExitCodes exit_code) : parent(#name, msg, exit_code) {} \
name(std::string msg, int exit_code) : parent(#name, msg, exit_code) {}
// This is added after the one above if a class is used directly and builds its own message
#define CLI11_ERROR_SIMPLE(name) \
name(std::string msg) : name(#name, msg, ExitCodes::name) {}
namespace CLI { namespace CLI {
/// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut, /// 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 {
BadNameString, BadNameString,
OptionAlreadyAdded, OptionAlreadyAdded,
File, File,
Conversion, ConversionError,
Validation, ValidationError,
Required, RequiredError,
Requires, RequiresError,
Excludes, ExcludesError,
Extras, ExtrasError,
ExtrasINI, ExtrasINIError,
Invalid, InvalidError,
Horrible, HorribleError,
OptionNotFound, OptionNotFound,
BaseClass = 127 BaseClass = 127
}; };
@ -39,126 +53,141 @@ enum class ExitCodes {
/// @{ /// @{
/// All errors derive from this one /// All errors derive from this one
struct Error : public std::runtime_error { class Error : public std::runtime_error {
int exit_code; int exit_code;
std::string name{"Error"};
public:
int get_exit_code() const { return exit_code; } int get_exit_code() const { return exit_code; }
Error(std::string parent, std::string name, ExitCodes exit_code = ExitCodes::BaseClass) std::string get_name() const { return name; }
: runtime_error(parent + ": " + name), exit_code(static_cast<int>(exit_code)) {}
Error(std::string parent, std::string name, int exit_code = static_cast<int>(ExitCodes::BaseClass)) Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
: runtime_error(parent + ": " + name), exit_code(exit_code) {} : runtime_error(msg), exit_code(exit_code), name(name) {}
Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
}; };
// Note: Using Error::Error constructors does not work on GCC 4.7
/// Construction errors (not in parsing) /// Construction errors (not in parsing)
struct ConstructionError : public Error { class ConstructionError : public Error {
// Using Error::Error constructors seem to not work on GCC 4.7 CLI11_ERROR_DEF(Error, ConstructionError)
ConstructionError(std::string parent, std::string name, ExitCodes exit_code = ExitCodes::BaseClass)
: Error(parent, name, exit_code) {}
}; };
/// Thrown when an option is set to conflicting values (non-vector and multi args, for example) /// Thrown when an option is set to conflicting values (non-vector and multi args, for example)
struct IncorrectConstruction : public ConstructionError { class IncorrectConstruction : public ConstructionError {
IncorrectConstruction(std::string name) CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction)
: ConstructionError("IncorrectConstruction", name, ExitCodes::IncorrectConstruction) {} CLI11_ERROR_SIMPLE(IncorrectConstruction)
}; };
/// Thrown on construction of a bad name /// Thrown on construction of a bad name
struct BadNameString : public ConstructionError { class BadNameString : public ConstructionError {
BadNameString(std::string name) : ConstructionError("BadNameString", name, ExitCodes::BadNameString) {} CLI11_ERROR_DEF(ConstructionError, BadNameString)
CLI11_ERROR_SIMPLE(BadNameString)
}; };
/// Thrown when an option already exists /// Thrown when an option already exists
struct OptionAlreadyAdded : public ConstructionError { class OptionAlreadyAdded : public ConstructionError {
OptionAlreadyAdded(std::string name) CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded)
: ConstructionError("OptionAlreadyAdded", name, ExitCodes::OptionAlreadyAdded) {} CLI11_ERROR_SIMPLE(OptionAlreadyAdded)
}; };
// Parsing errors // Parsing errors
/// Anything that can error in Parse /// Anything that can error in Parse
struct ParseError : public Error { class ParseError : public Error {
ParseError(std::string parent, std::string name, ExitCodes exit_code = ExitCodes::BaseClass) CLI11_ERROR_DEF(Error, ParseError)
: Error(parent, name, exit_code) {}
ParseError(std::string parent, std::string name, int exit_code = static_cast<int>(ExitCodes::BaseClass))
: Error(parent, name, exit_code) {}
}; };
// Not really "errors" // Not really "errors"
/// This is a successful completion on parsing, supposed to exit /// This is a successful completion on parsing, supposed to exit
struct Success : public ParseError { class Success : public ParseError {
Success() : ParseError("Success", "Successfully completed, should be caught and quit", ExitCodes::Success) {} CLI11_ERROR_DEF(ParseError, Success)
Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
}; };
/// -h or --help on command line /// -h or --help on command line
struct CallForHelp : public ParseError { class CallForHelp : public ParseError {
CallForHelp() CLI11_ERROR_DEF(ParseError, CallForHelp)
: ParseError("CallForHelp", "This should be caught in your main function, see examples", ExitCodes::Success) {} CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
}; };
/// Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error code. /// Does not output a diagnostic in CLI11_PARSE, but allows to return from main() with a specific error code.
struct RuntimeError : public ParseError { class RuntimeError : public ParseError {
RuntimeError(int exit_code = 1) : ParseError("RuntimeError", "runtime error", exit_code) {} CLI11_ERROR_DEF(ParseError, RuntimeError)
RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
}; };
/// Thrown when parsing an INI file and it is missing /// Thrown when parsing an INI file and it is missing
struct FileError : public ParseError { class FileError : public ParseError {
FileError(std::string name) : ParseError("FileError", name, ExitCodes::File) {} CLI11_ERROR_DEF(ParseError, FileError)
FileError(std::string msg) : FileError(msg, ExitCodes::File) {}
}; };
/// Thrown when conversion call back fails, such as when an int fails to coerce to a string /// Thrown when conversion call back fails, such as when an int fails to coerce to a string
struct ConversionError : public ParseError { class ConversionError : public ParseError {
ConversionError(std::string name) : ParseError("ConversionError", name, ExitCodes::Conversion) {} CLI11_ERROR_DEF(ParseError, ConversionError)
CLI11_ERROR_SIMPLE(ConversionError)
}; };
/// Thrown when validation of results fails /// Thrown when validation of results fails
struct ValidationError : public ParseError { class ValidationError : public ParseError {
ValidationError(std::string name) : ParseError("ValidationError", name, ExitCodes::Validation) {} CLI11_ERROR_DEF(ParseError, ValidationError)
CLI11_ERROR_SIMPLE(ValidationError)
}; };
/// Thrown when a required option is missing /// Thrown when a required option is missing
struct RequiredError : public ParseError { class RequiredError : public ParseError {
RequiredError(std::string name) : ParseError("RequiredError", name, ExitCodes::Required) {} CLI11_ERROR_DEF(ParseError, RequiredError)
CLI11_ERROR_SIMPLE(RequiredError)
}; };
/// Thrown when a requires option is missing /// Thrown when a requires option is missing
struct RequiresError : public ParseError { class RequiresError : public ParseError {
RequiresError(std::string name, std::string subname) CLI11_ERROR_DEF(ParseError, RequiresError)
: ParseError("RequiresError", name + " requires " + subname, ExitCodes::Requires) {} RequiresError(std::string curname, std::string subname)
: RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
}; };
/// Thrown when a exludes option is present /// Thrown when a exludes option is present
struct ExcludesError : public ParseError { class ExcludesError : public ParseError {
ExcludesError(std::string name, std::string subname) CLI11_ERROR_DEF(ParseError, ExcludesError)
: ParseError("ExcludesError", name + " excludes " + subname, ExitCodes::Excludes) {} ExcludesError(std::string curname, std::string subname)
: ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
}; };
/// Thrown when too many positionals or options are found /// Thrown when too many positionals or options are found
struct ExtrasError : public ParseError { class ExtrasError : public ParseError {
ExtrasError(std::string name) : ParseError("ExtrasError", name, ExitCodes::Extras) {} CLI11_ERROR_DEF(ParseError, ExtrasError)
CLI11_ERROR_SIMPLE(ExtrasError)
}; };
/// Thrown when extra values are found in an INI file /// Thrown when extra values are found in an INI file
struct ExtrasINIError : public ParseError { class ExtrasINIError : public ParseError {
ExtrasINIError(std::string name) : ParseError("ExtrasINIError", name, ExitCodes::ExtrasINI) {} CLI11_ERROR_DEF(ParseError, ExtrasINIError)
CLI11_ERROR_SIMPLE(ExtrasINIError)
}; };
/// Thrown when validation fails before parsing /// Thrown when validation fails before parsing
struct InvalidError : public ParseError { class InvalidError : public ParseError {
InvalidError(std::string name) : ParseError("InvalidError", name, ExitCodes::Invalid) {} CLI11_ERROR_DEF(ParseError, InvalidError)
CLI11_ERROR_SIMPLE(InvalidError)
}; };
/// This is just a safety check to verify selection and parsing match /// This is just a safety check to verify selection and parsing match - you should not ever see it
struct HorribleError : public ParseError { class HorribleError : public ParseError {
HorribleError(std::string name) CLI11_ERROR_DEF(ParseError, HorribleError)
: ParseError("HorribleError", "(You should never see this error) " + name, ExitCodes::Horrible) {} CLI11_ERROR_SIMPLE(HorribleError)
}; };
// After parsing // After parsing
/// Thrown when counting a non-existent option /// Thrown when counting a non-existent option
struct OptionNotFound : public Error { class OptionNotFound : public Error {
OptionNotFound(std::string name) : Error("OptionNotFound", name, ExitCodes::OptionNotFound) {} CLI11_ERROR_DEF(Error, OptionNotFound)
CLI11_ERROR_SIMPLE(OptionNotFound)
}; };
/// @} /// @}

View File

@ -309,7 +309,7 @@ TEST(THelp, RemoveHelp) {
try { try {
app.parse(input); app.parse(input);
} catch(const CLI::ParseError &e) { } catch(const CLI::ParseError &e) {
EXPECT_EQ(static_cast<int>(CLI::ExitCodes::Extras), e.get_exit_code()); EXPECT_EQ(static_cast<int>(CLI::ExitCodes::ExtrasError), e.get_exit_code());
} }
} }
@ -328,7 +328,7 @@ TEST(THelp, NoHelp) {
try { try {
app.parse(input); app.parse(input);
} catch(const CLI::ParseError &e) { } catch(const CLI::ParseError &e) {
EXPECT_EQ(static_cast<int>(CLI::ExitCodes::Extras), e.get_exit_code()); EXPECT_EQ(static_cast<int>(CLI::ExitCodes::ExtrasError), e.get_exit_code());
} }
} }
@ -385,14 +385,14 @@ TEST(Exit, ErrorWithoutHelp) {
try { try {
app.parse(input); app.parse(input);
} catch(const CLI::ParseError &e) { } catch(const CLI::ParseError &e) {
EXPECT_EQ(static_cast<int>(CLI::ExitCodes::Extras), e.get_exit_code()); EXPECT_EQ(static_cast<int>(CLI::ExitCodes::ExtrasError), e.get_exit_code());
} }
} }
TEST(Exit, ExitCodes) { TEST(Exit, ExitCodes) {
CLI::App app; CLI::App app;
auto i = static_cast<int>(CLI::ExitCodes::Extras); auto i = static_cast<int>(CLI::ExitCodes::ExtrasError);
EXPECT_EQ(0, app.exit(CLI::Success())); EXPECT_EQ(0, app.exit(CLI::Success()));
EXPECT_EQ(0, app.exit(CLI::CallForHelp())); EXPECT_EQ(0, app.exit(CLI::CallForHelp()));
EXPECT_EQ(i, app.exit(CLI::ExtrasError("Thing"))); EXPECT_EQ(i, app.exit(CLI::ExtrasError("Thing")));
@ -432,10 +432,10 @@ TEST_F(CapturedHelp, CallForHelp) {
} }
TEST_F(CapturedHelp, NormalError) { TEST_F(CapturedHelp, NormalError) {
EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::Extras)); EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::ExtrasError));
EXPECT_EQ(out.str(), ""); EXPECT_EQ(out.str(), "");
EXPECT_THAT(err.str(), HasSubstr("for more information")); EXPECT_THAT(err.str(), HasSubstr("for more information"));
EXPECT_THAT(err.str(), HasSubstr("ExtrasError")); EXPECT_THAT(err.str(), Not(HasSubstr("ExtrasError")));
EXPECT_THAT(err.str(), HasSubstr("Thing")); EXPECT_THAT(err.str(), HasSubstr("Thing"));
EXPECT_THAT(err.str(), Not(HasSubstr("Usage"))); EXPECT_THAT(err.str(), Not(HasSubstr("Usage")));
} }
@ -443,7 +443,7 @@ TEST_F(CapturedHelp, NormalError) {
TEST_F(CapturedHelp, RepacedError) { TEST_F(CapturedHelp, RepacedError) {
app.set_failure_message(CLI::FailureMessage::help); app.set_failure_message(CLI::FailureMessage::help);
EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::Extras)); EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast<int>(CLI::ExitCodes::ExtrasError));
EXPECT_EQ(out.str(), ""); EXPECT_EQ(out.str(), "");
EXPECT_THAT(err.str(), Not(HasSubstr("for more information"))); EXPECT_THAT(err.str(), Not(HasSubstr("for more information")));
EXPECT_THAT(err.str(), HasSubstr("ERROR: ExtrasError")); EXPECT_THAT(err.str(), HasSubstr("ERROR: ExtrasError"));