Catch2 заставляет меня добавить приведение к std::string в мои исключения, это может создать другие проблемы?

Я использую Catch2 для написания своих модульных тестов.

Одна вещь, которую я хочу сделать, - убедиться, что я ловлю правильное исключение. Я бросаю одни и те же исключения во многих обстоятельствах, поэтому просто зная, что я ловлю std::logic_error не доказывает, что конкретный случай исключения был действительно пойман.

Catch2 предоставляет REQUIRE_THROWS_MATCHES() макрос для этой цели.

Вот пример того, как я использую его с Equals согласовани:

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

Только это не компилируется, если в моих исключениях нет оператора приведения. В этом случае это достаточно просто, так как у меня есть собственное исключение. Но мне интересно, почему автор Catch2 решил использовать приведение к std::string вместо использования what() функция.

Вот мое текущее определение исключений базового класса:

class logic_exception_t
    : public std::logic_error
    , public exception_base_t
{
public:
    explicit                    logic_exception_t( std::string const & what, int const stack_trace_depth = STACK_TRACE_DEPTH );
    explicit                    logic_exception_t( char const *        what, int const stack_trace_depth = STACK_TRACE_DEPTH );

    virtual                     ~logic_exception_t() override {}

    virtual char const *        what() const throw() override;
                                operator std::string () const;
};

Здесь operator std::string () const функция:

logic_exception_t::operator std::string () const
{
    return what();
}

Есть ли другой способ удовлетворить требование Catch2 и разрешить преобразование исключения в std::string без необходимости создавать оператор приведения? Мне просто не нравится иметь бросок, который может вызвать другие проблемы в будущем.

Примечание: я пытался сделать приведение явным, и Catch2 тоже не нравится. Он просто передает исключение в функцию, которая ожидает std::string,

2 ответа

Сегодня я столкнулся с той же проблемой; есть половинчатое решение в виде матчера, задокументированное в документации Catch2 .

      REQUIRE_THROWS_MATCHES(fn(), SomeException, Message("Complete exception emssage"));

Тем не менее, я хотел бы иметьContainsкак функциональность. УчитываяMessageреализации, реализовать его тривиально:

      #include <catch2/matchers/catch_matchers.hpp>
#include <exception>
#include <string>

#include <string.h>

class ExceptionMessageContainsMatcher final : public MatcherBase<std::exception>
{
  std::string m_messagePart;

public:
  ExceptionMessageContainsMatcher(const std::string &messagePart) 
    : m_messagePart{messagePart}
  {}

  bool match(const std::exception &e) const {
    return ::strstr(e.what(), m_messagePart.data()) != nullptr;
  }

  std::string describe() const {
    return "exception message does not contain \"" + m_messagePart + '"';   
  }
};

ExceptionMessageContainsMatcher MessageContains(const std::string &message) { 
  return {message};
}

Это позволяет вам писать:

      REQUIRE_THROWS_MATCHES(fn(), SomeException, MessageContains("part of the message"));

На самом деле вы можете определить свой собственный наблюдатель, поэтому я решил написать наблюдателя, который будет делать исключение для его match() функция. Это работает без приведения к std::string!

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
Другие вопросы по тегам