Skip to content

Commit 4ad994a

Browse files
committed
iox-#1613 Add IOX_EXPECT_NO_FATAL_FAILURE and documentation
1 parent 1a55f72 commit 4ad994a

File tree

1 file changed

+73
-6
lines changed

1 file changed

+73
-6
lines changed

iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,48 @@
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

2328
namespace iox
2429
{
2530
namespace 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
2742
template <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

Comments
 (0)