Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for testing exception #1649

Closed
AlexisWilke opened this issue Jun 2, 2019 · 2 comments
Closed

Better support for testing exception #1649

AlexisWilke opened this issue Jun 2, 2019 · 2 comments

Comments

@AlexisWilke
Copy link

Description

I was thinking I could just check the what() string of an exception in Catch2. The fact is I had to write my own Matcher.

It seems to me that since a fairly standard exception is expected to have a what() returning a string which we could match, that it would make sense to offer such a generic Matcher.

Example Matcher

I wrote my own std::exception Matcher which looks as follow. Using it with CATCH_REQUIRE_THROWS_MATCHES() is very simple:

    CATCH_REQUIRE_THROWS_MATCHES(std::make_shared<advgetopt::getopt>(options_environment, sub_argc, sub_argv)
                , advgetopt::getopt_exception_logic
                , Catch::Matchers::ExceptionMessage(
                          "section \"invalid::name\" includes a section separator (::) in \""
                        + options_filename
                        + "\". We only support one level."));

I think this is much cleaner than having to have a toString() or and operator std::string() in your exceptions. This is much more generic.

namespace Catch
{
namespace Matchers
{


class ExceptionWatcher
    : public MatcherBase<std::exception>
{
public:
    ExceptionWatcher(std::string const & expected_message)
        : m_expected_message(expected_message)
    {
    }

    /** \brief Check whether we got a match.
     *
     * This function compares the expected string with the actual exception
     * what() output.
     */
    bool match(std::exception const & e) const override
    {
        return e.what() == m_expected_message;
    }

    /** \brief Describe this matcher.
     *
     * This function produces a string describing what this matcher does.
     *
     * \return The description of this matcher.
     */
    virtual std::string describe() const override
    {
        return "compare the exception what() message with \""
             + m_expected_message
             + "\".";
    }

private:
    std::string     m_expected_message = std::string();
};


inline ExceptionWatcher ExceptionMessage(std::string const & expeted_message)
{
    return ExceptionWatcher(expeted_message);
}



}
// Matchers namespace
}
// Catch namespace

Cons?

I know some people like to create their own exceptions from scratch, although I've seen many projects and more and more I see exceptions being properly derived from std::runtime_error or std::logic_error. So I have hope that having such a generic Watcher in Catch2 will be considered. Maybe even have a <string>_e which automatically converts said string to that generic exception Watcher.

So in effect I don't personally see any cons (outside of having to maintain one more class and maybe a few more functions.)

Also I was wondering how I could have access to all the string Watchers functionality (i.e. StartWith, EndsWith, Contains... instead of just return e.what() == m_expected_message; because that can prove difficult when a exception message contains a run-time value.)

@horenmar
Copy link
Member

horenmar commented Jun 6, 2019

Isn't the very basic version of what you want just REQUIRE_THROWS_WITH(expr, message)?

@AlexisWilke
Copy link
Author

Ah, it's very close... I can verify the message but not the type of the exception, though.

I suppose I could run both:

  • REQUIRE_THROWS_AS() to verify the type; and
  • REQUIRE_THROWS_WITH() to check the message.

amitherman95 pushed a commit to amitherman95/Catch2 that referenced this issue Oct 18, 2019
Only works for exceptions that publicly derive from `std::exception`
and the matching is done exactly, including case and whitespace.

Closes catchorg#1649
Closes catchorg#1728

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	modified:   ../docs/matchers.md
#	modified:   ../include/internal/catch_capture_matchers.h
#	modified:   ../projects/CMakeLists.txt
#	modified:   ../projects/SelfTest/Baselines/compact.sw.approved.txt
#	modified:   ../projects/SelfTest/Baselines/console.std.approved.txt
#	modified:   ../projects/SelfTest/Baselines/console.sw.approved.txt
#	modified:   ../projects/SelfTest/Baselines/junit.sw.approved.txt
#	modified:   ../projects/SelfTest/Baselines/xml.sw.approved.txt
#	modified:   ../projects/SelfTest/UsageTests/Matchers.tests.cpp
#
# Untracked files:
#	./
#	../clang-full/
#	../clang-test/
#	../clang10-build/
#	../coverage-build/
#	../gcc-build/
#	../gcc-full/
#	../include/internal/catch_matchers_exception.cpp
#	../include/internal/catch_matchers_exception.hpp
#	../misc-build/
#	../msvc-sln/
#	../notes.txt
#	../test-install/
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants