1414//
1515// SPDX-License-Identifier: Apache-2.0
1616
17+ #ifndef IOX_HOOFS_TESTING_FATAL_FAILURE_HPP
18+ #define IOX_HOOFS_TESTING_FATAL_FAILURE_HPP
19+
1720#include " iceoryx_hoofs/testing/mocks/error_handler_mock.hpp"
21+ #include " iox/optional.hpp"
1822#include " test.hpp"
1923
24+ #include < atomic>
2025#include < csetjmp>
2126#include < thread>
2227
2328namespace iox
2429{
2530namespace testing
2631{
32+ namespace detail
33+ {
34+ // / @brief This function is the base for 'IOX_EXPECT_FATAL_FAILURE' and 'IOX_EXPECT_NO_FATAL_FAILURE' and should not be
35+ // / used by its own. The function only works in combination with the iceoryx error handler.
36+ // / @tparam[in] ErrorType The error type which is expected, e.g. 'iox::HoofsError'
37+ // / @param[in] testFunction This function will be executed as SUT and might call the error handler with a 'FATAL' error
38+ // / level
39+ // / @param[in] onFatalFailurePath This function will be executed on the failure path after the failure was detected
40+ // / @param[in] onNonFatalFailurePath This function will be executed on the non-failure path if no failure was detected
41+ // / @return true if a fatal failure occurs, false otherwise
2742template <typename ErrorType>
28- void EXPECT_FATAL_FAILURE (const std::function<void ()>& testFunction,
29- const ErrorType expectedError ,
30- const iox::ErrorLevel expectedErrorLevel )
43+ bool FATAL_FAILURE_TEST (const std::function<void ()>& testFunction,
44+ const std::function<void( const ErrorType, const iox::ErrorLevel)>& onFatalFailurePath ,
45+ const std::function<void()>& onNonFatalFailurePath )
3146{
47+ std::atomic<bool > hasFatalFailure{false };
3248 auto th = std::thread ([&] {
3349 constexpr int JMP_VALUE{1 };
3450 std::jmp_buf jmpBuffer;
3551
52+ optional<ErrorType> detectedError;
53+ optional<iox::ErrorLevel> detectedErrorLevel;
54+
3655 auto errorHandlerGuard =
3756 iox::ErrorHandlerMock::setTemporaryErrorHandler<ErrorType>([&](const auto error, const auto errorLevel) {
38- EXPECT_THAT (error, :: testing::Eq (expectedError) );
39- EXPECT_THAT (errorLevel, :: testing::Eq (expectedErrorLevel) );
57+ detectedError. emplace (error);
58+ detectedErrorLevel. emplace (errorLevel);
4059
4160 // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback
4261 std::longjmp (&jmpBuffer[0 ], JMP_VALUE);
@@ -45,15 +64,63 @@ void EXPECT_FATAL_FAILURE(const std::function<void()>& testFunction,
4564 // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback
4665 if (setjmp (&jmpBuffer[0 ]) == JMP_VALUE)
4766 {
67+ hasFatalFailure = true ;
68+ // using value directly is save since this path is only executed if the error handler was called and the
69+ // respective values were set
70+ onFatalFailurePath (detectedError.value (), detectedErrorLevel.value ());
4871 return ;
4972 }
5073
5174 testFunction ();
5275
53- GTEST_FAIL () << " Expected fatal failure but execution continued! " ;
76+ onNonFatalFailurePath () ;
5477 });
5578
5679 th.join ();
80+
81+ return hasFatalFailure.load (std::memory_order_relaxed);
82+ }
83+ } // namespace detail
84+
85+ // / @brief This function is used in cases a fatal failure is expected. The function only works in combination with the
86+ // / iceoryx error handler.
87+ // / @tparam[in] ErrorType The error type which is expected, e.g. 'iox::HoofsError'
88+ // / @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler
89+ // / @param[in] expectedError The error value which triggered the fatal failure
90+ // / @return true if a fatal failure occurs, false otherwise
91+ template <typename ErrorType>
92+ bool EXPECT_FATAL_FAILURE (const std::function<void ()>& testFunction,
93+ const ErrorType expectedError,
94+ const iox::ErrorLevel)
95+ {
96+ return detail::FATAL_FAILURE_TEST<ErrorType>(
97+ testFunction,
98+ [&](const auto error, const auto errorLevel) {
99+ EXPECT_THAT (error, ::testing::Eq (expectedError));
100+ EXPECT_THAT (errorLevel, ::testing::Eq (iox::ErrorLevel::FATAL));
101+ },
102+ [&] { GTEST_FAIL () << " Expected fatal failure but execution continued!" ; });
103+ }
104+
105+ // / @brief This function is used in cases no fatal failure is expected but could potentially occur. The function only
106+ // / works in combination with the iceoryx error handler.
107+ // / @tparam[in] ErrorType The error type which is expected if the test fails, e.g. 'iox::HoofsError'
108+ // / @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler
109+ // / @return true if no fatal failure occurs, false otherwise
110+ template <typename ErrorType>
111+ bool IOX_EXPECT_NO_FATAL_FAILURE (const std::function<void ()>& testFunction)
112+ {
113+ return !detail::FATAL_FAILURE_TEST<ErrorType>(
114+ testFunction,
115+ [&](const auto error, const auto errorLevel) {
116+ GTEST_FAIL () << " Expected no fatal failure but execution failed! Error code: " << error
117+ << " ; Error level: " << errorLevel;
118+ },
119+ [&] {});
120+ return false ;
57121}
122+
58123} // namespace testing
59124} // namespace iox
125+
126+ #endif // IOX_HOOFS_TESTING_FATAL_FAILURE_HPP
0 commit comments