diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 3d5bf96e..6f68586b 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -727,20 +727,20 @@ class App { } /// Print a nice error message and return the exit code - int exit(const Error &e) const { + int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const { /// Avoid printing anything if this is a CLI::RuntimeError if(dynamic_cast(&e) != nullptr) return e.get_exit_code(); if(dynamic_cast(&e) != nullptr) { - std::cout << help(); + out << help(); return e.get_exit_code(); } if(e.exit_code != static_cast(ExitCodes::Success)) { if(failure_message_) - std::cerr << failure_message_(this, e) << std::flush; + err << failure_message_(this, e) << std::flush; } return e.get_exit_code(); @@ -1428,17 +1428,20 @@ class App { }; namespace FailureMessage { + inline std::string simple(const App *app, const Error &e) { std::string header = std::string("ERROR: ") + e.what() + "\n"; if(app->get_help_ptr() != nullptr) - header += "Run with " + app->get_help_ptr()->single_name() + " for more help\n"; + header += "Run with " + app->get_help_ptr()->single_name() + " for more information.\n"; return header; }; + inline std::string help(const App *app, const Error &e) { std::string header = std::string("ERROR: ") + e.what() + "\n"; header += app->help(); return header; }; + } // namespace FailureMessage namespace detail { diff --git a/tests/HelpTest.cpp b/tests/HelpTest.cpp index 5576102e..06e83169 100644 --- a/tests/HelpTest.cpp +++ b/tests/HelpTest.cpp @@ -386,3 +386,54 @@ TEST(Exit, ExitCodes) { EXPECT_EQ(42, app.exit(CLI::RuntimeError(42))); EXPECT_EQ(1, app.exit(CLI::RuntimeError())); // Not sure if a default here is a good thing } + +struct CapturedHelp : public ::testing::Test { + CLI::App app{"My Test Program"}; + std::stringstream out; + std::stringstream err; + + int run(const CLI::Error &e) { return app.exit(e, out, err); } + + void reset() { + out.clear(); + err.clear(); + } +}; + +TEST_F(CapturedHelp, Sucessful) { + EXPECT_EQ(run(CLI::Success()), 0); + EXPECT_EQ(out.str(), ""); + EXPECT_EQ(err.str(), ""); +} + +TEST_F(CapturedHelp, JustAnError) { + EXPECT_EQ(run(CLI::RuntimeError(42)), 42); + EXPECT_EQ(out.str(), ""); + EXPECT_EQ(err.str(), ""); +} + +TEST_F(CapturedHelp, CallForHelp) { + EXPECT_EQ(run(CLI::CallForHelp()), 0); + EXPECT_EQ(out.str(), app.help()); + EXPECT_EQ(err.str(), ""); +} + +TEST_F(CapturedHelp, NormalError) { + EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast(CLI::ExitCodes::Extras)); + EXPECT_EQ(out.str(), ""); + EXPECT_THAT(err.str(), HasSubstr("for more information")); + EXPECT_THAT(err.str(), HasSubstr("ERROR: ExtrasError")); + EXPECT_THAT(err.str(), HasSubstr("Thing")); + EXPECT_THAT(err.str(), Not(HasSubstr("Usage"))); +} + +TEST_F(CapturedHelp, RepacedError) { + app.set_failure_message(CLI::FailureMessage::help); + + EXPECT_EQ(run(CLI::ExtrasError("Thing")), static_cast(CLI::ExitCodes::Extras)); + EXPECT_EQ(out.str(), ""); + EXPECT_THAT(err.str(), Not(HasSubstr("for more information"))); + EXPECT_THAT(err.str(), HasSubstr("ERROR: ExtrasError")); + EXPECT_THAT(err.str(), HasSubstr("Thing")); + EXPECT_THAT(err.str(), HasSubstr("Usage")); +}