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