EXPECT_THROW_EQ and ASSERT_THROW_EQ macros for unittests (#1232)
* EXPECT_THROW_EQ and ASSERT_THROW_EQ macros for unittests Signed-off-by: Stephen Brawner <brawner@gmail.com> * Address PR Feedback Signed-off-by: Stephen Brawner <brawner@gmail.com>
This commit is contained in:
parent
60bcee36ab
commit
04bccb95cb
3 changed files with 404 additions and 0 deletions
|
@ -518,6 +518,11 @@ if(TARGET test_subscription_options)
|
||||||
target_link_libraries(test_subscription_options ${PROJECT_NAME})
|
target_link_libraries(test_subscription_options ${PROJECT_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
ament_add_gtest(test_rclcpp_gtest_macros utils/test_rclcpp_gtest_macros.cpp)
|
||||||
|
if(TARGET test_rclcpp_gtest_macros)
|
||||||
|
target_link_libraries(test_rclcpp_gtest_macros ${PROJECT_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Install test resources
|
# Install test resources
|
||||||
install(
|
install(
|
||||||
DIRECTORY resources
|
DIRECTORY resources
|
||||||
|
|
195
rclcpp/test/utils/rclcpp_gtest_macros.hpp
Normal file
195
rclcpp/test/utils/rclcpp_gtest_macros.hpp
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright 2020 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef UTILS__RCLCPP_GTEST_MACROS_HPP_
|
||||||
|
#define UTILS__RCLCPP_GTEST_MACROS_HPP_
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "rclcpp/exceptions/exceptions.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace testing
|
||||||
|
{
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if two thrown objects are equals.
|
||||||
|
*
|
||||||
|
* For generic thrown objects, probably is unlikely to be used. This type must
|
||||||
|
* overload the == and << operators.
|
||||||
|
*/
|
||||||
|
template<typename T,
|
||||||
|
typename = typename std::enable_if_t<
|
||||||
|
!std::is_convertible<T, std::exception>::value>>
|
||||||
|
::testing::AssertionResult AreThrowableContentsEqual(
|
||||||
|
const T & expected, const T & actual, const char * expected_exception_expression,
|
||||||
|
const char * throwing_expression)
|
||||||
|
{
|
||||||
|
if (expected == actual) {
|
||||||
|
return ::testing::AssertionSuccess() <<
|
||||||
|
"'\nThe value of the non-standard throwable thrown by the expression\n'" <<
|
||||||
|
throwing_expression << "'\n\nmatches the value of the expected thrown object\n'" <<
|
||||||
|
expected_exception_expression << "'\n\t(" << expected << " == " << actual << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::testing::AssertionFailure() <<
|
||||||
|
"\nThe value of the non-standard throwable thrown by the expression\n'" <<
|
||||||
|
throwing_expression << "'\n\ndoes not match the value of the expected thrown object\n'" <<
|
||||||
|
expected_exception_expression << "'\n\t(" << expected << " != " << actual << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if two std::exceptions are equal according to their message.
|
||||||
|
*
|
||||||
|
* If the exception type also derives from rclcpp::Exception, then the next overload is called
|
||||||
|
* instead
|
||||||
|
*/
|
||||||
|
template<typename T,
|
||||||
|
typename = typename std::enable_if_t<
|
||||||
|
!std::is_convertible<T, rclcpp::exceptions::RCLErrorBase>::value>>
|
||||||
|
::testing::AssertionResult AreThrowableContentsEqual(
|
||||||
|
const std::exception & expected, const std::exception & actual,
|
||||||
|
const char * expected_exception_expression,
|
||||||
|
const char * throwing_expression)
|
||||||
|
{
|
||||||
|
if (std::strcmp(expected.what(), actual.what()) == 0) {
|
||||||
|
return ::testing::AssertionSuccess() <<
|
||||||
|
"'\nThe contents of the std::exception thrown by the expression\n'" <<
|
||||||
|
throwing_expression << "':\n\te.what(): '" << actual.what() <<
|
||||||
|
"'\n\nmatch the contents of the expected std::exception\n'" <<
|
||||||
|
expected_exception_expression << "'\n\te.what(): '" << expected.what() << "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::testing::AssertionFailure() <<
|
||||||
|
"\nThe contents of the std::exception thrown by the expression\n'" <<
|
||||||
|
throwing_expression << "':\n\te.what(): '" << actual.what() <<
|
||||||
|
"'\n\ndo not match the contents of the expected std::exception\n'" <<
|
||||||
|
expected_exception_expression << "'\n\te.what(): '" << expected.what() << "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if two exceptions that derive from rclcpp::RCLErrorBase are equal.
|
||||||
|
*
|
||||||
|
* This checks equality based on their return and message. It does not check the formatted
|
||||||
|
* message, which is what is reported by std::exception::what() for RCLErrors.
|
||||||
|
*/
|
||||||
|
template<typename T,
|
||||||
|
typename = typename std::enable_if_t<
|
||||||
|
std::is_convertible<T, rclcpp::exceptions::RCLErrorBase>::value>>
|
||||||
|
::testing::AssertionResult AreThrowableContentsEqual(
|
||||||
|
const rclcpp::exceptions::RCLErrorBase & expected,
|
||||||
|
const rclcpp::exceptions::RCLErrorBase & actual,
|
||||||
|
const char * expected_exception_expression,
|
||||||
|
const char * throwing_expression)
|
||||||
|
{
|
||||||
|
if ((expected.ret == actual.ret) && (expected.message == actual.message)) {
|
||||||
|
return ::testing::AssertionSuccess() <<
|
||||||
|
"'\nThe contents of the RCLError thrown by the expression\n'" << throwing_expression <<
|
||||||
|
"':\n\trcl_ret_t: " << actual.ret << "\n\tmessage: '" << actual.message <<
|
||||||
|
"'\n\nmatch the contents of the expected RCLError\n'" <<
|
||||||
|
expected_exception_expression << "'\n\trcl_ret_t: " << expected.ret <<
|
||||||
|
"\n\tmessage: '" << expected.message << "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::testing::AssertionFailure() <<
|
||||||
|
"'\nThe contents of the RCLError thrown by the expression\n'" << throwing_expression <<
|
||||||
|
"':\n\trcl_ret_t: " << actual.ret << "\n\tmessage: '" << actual.message <<
|
||||||
|
"'\n\ndo not match the contents of the expected RCLError\n'" <<
|
||||||
|
expected_exception_expression << "'\n\trcl_ret_t: " << expected.ret << "\n\tmessage: '" <<
|
||||||
|
expected.message << "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def CHECK_THROW_EQ_IMPL
|
||||||
|
* \brief Implemented check if statement throws expected exception. don't use directly, use
|
||||||
|
* RCLCPP_EXPECT_THROW_EQ or RCLCPP_ASSERT_THROW_EQ instead.
|
||||||
|
*/
|
||||||
|
#define CHECK_THROW_EQ_IMPL(throwing_statement, expected_exception, assertion_result) \
|
||||||
|
do { \
|
||||||
|
using ExceptionT = decltype(expected_exception); \
|
||||||
|
try { \
|
||||||
|
throwing_statement; \
|
||||||
|
assertion_result = ::testing::AssertionFailure() << \
|
||||||
|
"\nExpected the expression:\n\t'" #throwing_statement "'\nto throw: \n\t'" << \
|
||||||
|
#expected_exception "'\nbut it did not throw.\n"; \
|
||||||
|
} catch (const ExceptionT & e) { \
|
||||||
|
assertion_result = \
|
||||||
|
rclcpp::testing::details::AreThrowableContentsEqual<ExceptionT>( \
|
||||||
|
expected_exception, e, #expected_exception, #throwing_statement); \
|
||||||
|
} catch (const std::exception & e) { \
|
||||||
|
assertion_result = ::testing::AssertionFailure() << \
|
||||||
|
"\nExpected the expression:\n\t'" #throwing_statement "'\nto throw: \n\t'" << \
|
||||||
|
#expected_exception "'\nbut it threw:\n\tType: " << typeid(e).name() << \
|
||||||
|
"\n\te.what(): '" << e.what() << "'\n"; \
|
||||||
|
} catch (...) { \
|
||||||
|
assertion_result = ::testing::AssertionFailure() << \
|
||||||
|
"\nExpected the expression:\n\t'" #throwing_statement "'\nto throw: \n\t'" << \
|
||||||
|
#expected_exception "'\nbut it threw an unrecognized throwable type.\n"; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def RCLCPP_EXPECT_THROW_EQ
|
||||||
|
* \brief Check if a statement throws the expected exception type and that the exceptions matches
|
||||||
|
* the expected exception.
|
||||||
|
*
|
||||||
|
* Like other gtest EXPECT_ macros, this doesn't halt a test and return on failure. Instead it
|
||||||
|
* just adds a failure to the current test.
|
||||||
|
*
|
||||||
|
* See test_gtest_macros.cpp for examples
|
||||||
|
*/
|
||||||
|
#define RCLCPP_EXPECT_THROW_EQ(throwing_statement, expected_exception) \
|
||||||
|
do { \
|
||||||
|
::testing::AssertionResult \
|
||||||
|
is_the_result_of_the_throwing_expression_equal_to_the_expected_throwable = \
|
||||||
|
::testing::AssertionSuccess(); \
|
||||||
|
CHECK_THROW_EQ_IMPL( \
|
||||||
|
throwing_statement, \
|
||||||
|
expected_exception, \
|
||||||
|
is_the_result_of_the_throwing_expression_equal_to_the_expected_throwable); \
|
||||||
|
EXPECT_TRUE(is_the_result_of_the_throwing_expression_equal_to_the_expected_throwable); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def RCLCPP_ASSERT_THROW_EQ
|
||||||
|
* \brief Assert that a statement throws the expected exception type and that the exceptions
|
||||||
|
* matches the expected exception.
|
||||||
|
*
|
||||||
|
* See test_gtest_macros.cpp for examples
|
||||||
|
*
|
||||||
|
* Like other gtest ASSERT_ macros, this will halt the test on failure and return.
|
||||||
|
*/
|
||||||
|
#define RCLCPP_ASSERT_THROW_EQ(throwing_statement, expected_exception) \
|
||||||
|
do { \
|
||||||
|
::testing::AssertionResult \
|
||||||
|
is_the_result_of_the_throwing_expression_equal_to_the_expected_throwable = \
|
||||||
|
::testing::AssertionSuccess(); \
|
||||||
|
CHECK_THROW_EQ_IMPL( \
|
||||||
|
throwing_statement, \
|
||||||
|
expected_exception, \
|
||||||
|
is_the_result_of_the_throwing_expression_equal_to_the_expected_throwable); \
|
||||||
|
ASSERT_TRUE(is_the_result_of_the_throwing_expression_equal_to_the_expected_throwable); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif // UTILS__RCLCPP_GTEST_MACROS_HPP_
|
204
rclcpp/test/utils/test_rclcpp_gtest_macros.cpp
Normal file
204
rclcpp/test/utils/test_rclcpp_gtest_macros.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
// Copyright 2020 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "./rclcpp_gtest_macros.hpp"
|
||||||
|
|
||||||
|
#include "rcl/rcl.h"
|
||||||
|
#include "rclcpp/rclcpp.hpp"
|
||||||
|
|
||||||
|
struct NonStandardThrowable
|
||||||
|
{
|
||||||
|
bool operator==(const NonStandardThrowable &) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & os, const NonStandardThrowable &)
|
||||||
|
{
|
||||||
|
os << "NonStandardThrowable";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestGtestMacros, standard_exceptions) {
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(
|
||||||
|
throw std::runtime_error("some runtime error"),
|
||||||
|
std::runtime_error("some runtime error"));
|
||||||
|
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(
|
||||||
|
throw std::invalid_argument("some invalid argument error"),
|
||||||
|
std::invalid_argument("some invalid argument error"));
|
||||||
|
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(
|
||||||
|
throw std::runtime_error("some runtime error"),
|
||||||
|
std::runtime_error("some runtime error"));
|
||||||
|
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(
|
||||||
|
throw std::invalid_argument("some invalid argument error"),
|
||||||
|
std::invalid_argument("some invalid argument error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestGtestMacros, standard_exceptions_not_equals) {
|
||||||
|
::testing::AssertionResult result = ::testing::AssertionSuccess();
|
||||||
|
CHECK_THROW_EQ_IMPL(
|
||||||
|
throw std::runtime_error("some runtime error"),
|
||||||
|
std::range_error("some runtime error"),
|
||||||
|
result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
|
||||||
|
CHECK_THROW_EQ_IMPL(
|
||||||
|
throw std::invalid_argument("some invalid argument error"),
|
||||||
|
std::invalid_argument("some different invalid argument error"),
|
||||||
|
result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestGTestMacros, non_standard_types) {
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw 0, 0);
|
||||||
|
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw 42, 42);
|
||||||
|
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw std::string("some string"), std::string("some string"));
|
||||||
|
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw NonStandardThrowable(), NonStandardThrowable());
|
||||||
|
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw 0, 0);
|
||||||
|
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw 42, 42);
|
||||||
|
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw std::string("some string"), std::string("some string"));
|
||||||
|
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw NonStandardThrowable(), NonStandardThrowable());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestGTestMacros, non_standard_types_not_equals) {
|
||||||
|
::testing::AssertionResult result = ::testing::AssertionSuccess();
|
||||||
|
|
||||||
|
CHECK_THROW_EQ_IMPL(throw 0, 1, result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
result = ::testing::AssertionSuccess();
|
||||||
|
|
||||||
|
CHECK_THROW_EQ_IMPL(throw -42, 42, result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
result = ::testing::AssertionSuccess();
|
||||||
|
|
||||||
|
CHECK_THROW_EQ_IMPL(throw std::string("some string"), std::string("some other string"), result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestGTestMacros, rclcpp_exceptions) {
|
||||||
|
rcutils_error_state_t rcl_error_state = {"this is some error message", __FILE__, __LINE__};
|
||||||
|
{
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLError(RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw actual, expected);
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw actual, expected);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLBadAlloc(RCL_RET_BAD_ALLOC, &rcl_error_state);
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLBadAlloc(RCL_RET_BAD_ALLOC, &rcl_error_state);
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw actual, expected);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Prefixes are not checked
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &rcl_error_state, "different_prefix");
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw actual, expected);
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw actual, expected);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// File names are not checked
|
||||||
|
rcutils_error_state_t different_error_state = rcl_error_state;
|
||||||
|
std::snprintf(
|
||||||
|
different_error_state.file, RCUTILS_ERROR_STATE_FILE_MAX_LENGTH, "different_file.cpp");
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &different_error_state, "exception_prefix");
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw actual, expected);
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw actual, expected);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Line numbers are not checked
|
||||||
|
rcutils_error_state_t different_error_state = rcl_error_state;
|
||||||
|
different_error_state.line_number += 42;
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &different_error_state, "exception_prefix");
|
||||||
|
RCLCPP_EXPECT_THROW_EQ(throw actual, expected);
|
||||||
|
RCLCPP_ASSERT_THROW_EQ(throw actual, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestGTestMacros, rclcpp_exceptions_not_equal) {
|
||||||
|
rcutils_error_state_t rcl_error_state = {"this is some error message", __FILE__, __LINE__};
|
||||||
|
{
|
||||||
|
// Check different return errors
|
||||||
|
::testing::AssertionResult result = ::testing::AssertionSuccess();
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLError(RCL_RET_BAD_ALLOC, &rcl_error_state, "exception_prefix");
|
||||||
|
CHECK_THROW_EQ_IMPL(throw actual, expected, result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Check different error messages
|
||||||
|
rcutils_error_state_t different_error_state = rcl_error_state;
|
||||||
|
std::snprintf(
|
||||||
|
different_error_state.message,
|
||||||
|
RCUTILS_ERROR_STATE_MESSAGE_MAX_LENGTH,
|
||||||
|
"this is a different error message");
|
||||||
|
::testing::AssertionResult result = ::testing::AssertionSuccess();
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLError(
|
||||||
|
RCL_RET_ERROR, &different_error_state, "exception_prefix");
|
||||||
|
CHECK_THROW_EQ_IMPL(throw actual, expected, result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Check different exception types
|
||||||
|
::testing::AssertionResult result = ::testing::AssertionSuccess();
|
||||||
|
auto expected =
|
||||||
|
rclcpp::exceptions::RCLError(RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
auto actual =
|
||||||
|
rclcpp::exceptions::RCLInvalidArgument(RCL_RET_ERROR, &rcl_error_state, "exception_prefix");
|
||||||
|
CHECK_THROW_EQ_IMPL(throw actual, expected, result);
|
||||||
|
EXPECT_FALSE(result);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue