Skip to content

Commit ace5f51

Browse files
authored
Merge pull request eclipse-iceoryx#1879 from ApexAI/iox-1613-create-mechanism-to-replace-expect-death-tests
iox-1613 replace EXPECT_DEATH with custom mechanism
2 parents 10f1e87 + efc7d2e commit ace5f51

26 files changed

+531
-288
lines changed

doc/design/error-handling.md

+17
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,23 @@ auto errorFunc = [](Error& error) {
264264
func(arg).and_then(successFunc).or_else(errorFunc);
265265
```
266266
267+
### Testing fatal error
268+
269+
For fatal errors the error handler will terminate the execution of the binary. In order to test these paths the
270+
`iox::testing::IOX_EXPECT_FATAL_FAILURE` function should be used instead of the `EXPECT_DEATH` gTest macro.
271+
The `EXPECT_DEATH` gTest macro forks the process which slows down the test execution (especially with the ThreadSanitizer enabled)
272+
and causes issues with running thread. The `IOX_EXPECT_FATAL_FAILURE` registers a temporary error handler and runs the provided
273+
function in a separate thread. When the error handler is called `longjmp` is used to prevent the termination and instead ensures
274+
to gracefully shutdown the thread.
275+
276+
```cpp
277+
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
278+
TEST(MyTest, valueOnNulloptIsFatal) {
279+
iox::optional<bool> sut;
280+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED);
281+
}
282+
```
283+
267284
## Open points
268285

269286
### Centralized error handling

iceoryx_binding_c/source/c_runtime.cpp

+4-10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//
1616
// SPDX-License-Identifier: Apache-2.0
1717

18+
#include "iceoryx_hoofs/cxx/requires.hpp"
1819
#include "iceoryx_posh/runtime/posh_runtime.hpp"
1920

2021
using namespace iox;
@@ -26,16 +27,9 @@ extern "C" {
2627

2728
void iox_runtime_init(const char* const name)
2829
{
29-
if (name == nullptr)
30-
{
31-
LogError() << "Runtime name is a nullptr!";
32-
std::terminate();
33-
}
34-
else if (strnlen(name, iox::MAX_RUNTIME_NAME_LENGTH + 1) > MAX_RUNTIME_NAME_LENGTH)
35-
{
36-
LogError() << "Runtime name has more than 100 characters!";
37-
std::terminate();
38-
}
30+
iox::cxx::Expects(name != nullptr && "Runtime name is a nullptr!");
31+
iox::cxx::Expects(strnlen(name, iox::MAX_RUNTIME_NAME_LENGTH + 1) <= MAX_RUNTIME_NAME_LENGTH
32+
&& "Runtime name has more than 100 characters!");
3933

4034
PoshRuntime::initRuntime(RuntimeName_t(iox::TruncateToCapacity, name));
4135
}

iceoryx_binding_c/test/moduletests/test_publisher.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
//
1616
// SPDX-License-Identifier: Apache-2.0
1717

18+
#include "iceoryx_binding_c/error_handling/error_handling.hpp"
1819
#include "iceoryx_binding_c/internal/cpp2c_enum_translation.hpp"
1920
#include "iceoryx_binding_c/internal/cpp2c_publisher.hpp"
21+
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
2022
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp"
2123
#include "iceoryx_posh/internal/popo/ports/publisher_port_roudi.hpp"
2224
#include "iceoryx_posh/internal/popo/ports/publisher_port_user.hpp"
@@ -37,6 +39,7 @@ extern "C" {
3739
namespace
3840
{
3941
using namespace ::testing;
42+
using namespace iox::testing;
4043
using namespace iox::capro;
4144
using namespace iox::cxx;
4245
using namespace iox::mepoo;
@@ -137,7 +140,8 @@ TEST(iox_pub_test_DeathTest, initPublisherWithNotInitializedPublisherOptionsTerm
137140
iox_pub_options_t options;
138141
iox_pub_storage_t storage;
139142

140-
EXPECT_DEATH({ iox_pub_init(&storage, "a", "b", "c", &options); }, ".*");
143+
IOX_EXPECT_FATAL_FAILURE<iox::CBindingError>([&] { iox_pub_init(&storage, "a", "b", "c", &options); },
144+
iox::CBindingError::BINDING_C__PUBLISHER_OPTIONS_NOT_INITIALIZED);
141145
}
142146

143147
TEST_F(iox_pub_test, initPublisherWithDefaultOptionsWorks)

iceoryx_binding_c/test/moduletests/test_runtime.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ extern "C" {
1818
#include "iceoryx_binding_c/runtime.h"
1919
}
2020

21+
#include "iceoryx_hoofs/error_handling/error_handling.hpp"
22+
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
2123
#include "iceoryx_posh/iceoryx_posh_types.hpp"
2224
#include "iceoryx_posh/testing/roudi_gtest.hpp"
2325

2426
namespace
2527
{
2628
using namespace iox;
2729
using namespace iox::runtime;
30+
using namespace iox::testing;
2831

2932
class BindingC_Runtime_test : public RouDi_GTest
3033
{
@@ -69,13 +72,19 @@ TEST_F(BindingC_Runtime_test, RuntimeNameLengthIsOutOfLimit)
6972
::testing::Test::RecordProperty("TEST_ID", "8fd6735d-f331-4c9c-9a91-3f06d3856d15");
7073
std::string tooLongName(iox::MAX_RUNTIME_NAME_LENGTH + 1, 's');
7174

72-
EXPECT_DEATH({ iox_runtime_init(tooLongName.c_str()); }, ".*");
75+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>(
76+
[&] {
77+
iox_runtime_init(tooLongName.c_str());
78+
;
79+
},
80+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
7381
}
7482

7583
TEST_F(BindingC_Runtime_test, RuntimeNameIsNullptr)
7684
{
7785
::testing::Test::RecordProperty("TEST_ID", "eb1b76c9-5420-42a9-88b3-db2e36e332de");
78-
EXPECT_DEATH({ iox_runtime_init(nullptr); }, ".*");
86+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { iox_runtime_init(nullptr); },
87+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
7988
}
8089

8190
TEST_F(BindingC_Runtime_test, GetInstanceNameIsNullptr)

iceoryx_binding_c/test/moduletests/test_service_discovery.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414
//
1515
// SPDX-License-Identifier: Apache-2.0
1616

17+
#include "iceoryx_hoofs/error_handling/error_handling.hpp"
18+
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
1719
#include "iceoryx_posh/runtime/service_discovery.hpp"
1820
#include "iceoryx_posh/testing/roudi_gtest.hpp"
1921

2022
using namespace iox;
2123
using namespace iox::runtime;
24+
using namespace iox::testing;
2225

2326
extern "C" {
2427
#include "iceoryx_binding_c/publisher.h"
@@ -63,7 +66,8 @@ description_vector iox_service_discovery_test::searchResult;
6366
TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageTerminates)
6467
{
6568
::testing::Test::RecordProperty("TEST_ID", "be551a9e-7dcf-406a-a74c-7dcb1ee16c30");
66-
EXPECT_DEATH({ iox_service_discovery_init(nullptr); }, ".*");
69+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { iox_service_discovery_init(nullptr); },
70+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
6771
}
6872

6973
/// @note We test only if the arguments of iox_service_discovery_find_service are correctly passed to

iceoryx_binding_c/test/moduletests/test_subscriber.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
//
1616
// SPDX-License-Identifier: Apache-2.0
1717

18+
#include "iceoryx_binding_c/error_handling/error_handling.hpp"
1819
#include "iceoryx_binding_c/internal/cpp2c_enum_translation.hpp"
1920
#include "iceoryx_binding_c/internal/cpp2c_subscriber.hpp"
21+
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
2022
#include "iceoryx_posh/internal/mepoo/memory_manager.hpp"
2123
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp"
2224
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_pusher.hpp"
@@ -28,6 +30,7 @@
2830

2931
using namespace iox;
3032
using namespace iox::popo;
33+
using namespace iox::testing;
3134

3235
extern "C" {
3336
#include "iceoryx_binding_c/chunk.h"
@@ -130,14 +133,14 @@ TEST_F(iox_sub_test, initSubscriberWithNullptrForStorageReturnsNullptr)
130133
EXPECT_EQ(iox_sub_init(nullptr, "all", "glory", "hypnotoad", &options), nullptr);
131134
}
132135

133-
// this crashes if the fixture is used, therefore a test without a fixture
134-
TEST(iox_sub_test_DeathTest, initSubscriberWithNotInitializedPublisherOptionsTerminates)
136+
TEST_F(iox_sub_test, initSubscriberWithNotInitializedSubscriberOptionsTerminates)
135137
{
136138
::testing::Test::RecordProperty("TEST_ID", "6a33309e-fe21-45f6-815a-eebe0136c572");
137139
iox_sub_options_t options;
138140
iox_sub_storage_t storage;
139141

140-
EXPECT_DEATH({ iox_sub_init(&storage, "a", "b", "c", &options); }, ".*");
142+
IOX_EXPECT_FATAL_FAILURE<iox::CBindingError>([&] { iox_sub_init(&storage, "a", "b", "c", &options); },
143+
iox::CBindingError::BINDING_C__SUBSCRIBER_OPTIONS_NOT_INITIALIZED);
141144
}
142145

143146
TEST_F(iox_sub_test, initSubscriberWithDefaultOptionsWorks)

iceoryx_dust/test/moduletests/test_cxx_forward_list.cpp

+33-51
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616

1717
#include "iceoryx_dust/cxx/forward_list.hpp"
1818
#include "iceoryx_hoofs/cxx/attributes.hpp"
19+
#include "iceoryx_hoofs/error_handling/error_handling.hpp"
20+
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
1921
#include "test.hpp"
2022

2123
namespace
2224
{
2325
using namespace ::testing;
2426
using namespace iox::cxx;
27+
using namespace iox::testing;
2528

2629
constexpr uint64_t TESTLISTCAPACITY{10U};
2730
constexpr int64_t TEST_LIST_ELEMENT_DEFAULT_VALUE{-99L};
@@ -142,15 +145,6 @@ int64_t iteratorTraitReturnDoubleValue(IterType iter)
142145
IterValueType m_value = *iter;
143146
return (2 * m_value); // will only work for integer-convertible m_value types
144147
}
145-
146-
// in context of EXPECT_DEATH tests, dummyFunc() shall help suppressing following warning :
147-
// -Wunused-comparison
148-
// reason: the warning is already addressed with the internal handling, which shall be tested here
149-
bool dummyFunc(bool whatever)
150-
{
151-
std::cerr << "Never get here - ever " << whatever << std::endl;
152-
return whatever;
153-
}
154148
} // namespace
155149

156150

@@ -292,9 +286,7 @@ TEST_F(forward_list_test, FullWhenFilledWithMoreThanCapacityElements)
292286
}
293287

294288
EXPECT_THAT(sut.full(), Eq(true));
295-
// @todo iox-#1613 remove EXPECT_DEATH
296-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
297-
EXPECT_DEATH(sut.emplace_front(), "");
289+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { sut.emplace_front(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED);
298290
}
299291
TEST_F(forward_list_test, NotFullWhenFilledWithCapacityAndEraseOneElements)
300292
{
@@ -666,9 +658,8 @@ TEST_F(forward_list_test, EmplaceAfterWithWrongListIterator)
666658
++cnt;
667659
}
668660

669-
// @todo iox-#1613 remove EXPECT_DEATH
670-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
671-
EXPECT_DEATH(sut11.emplace_after(iterOfSut12, cnt), "");
661+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { sut11.emplace_after(iterOfSut12, cnt); },
662+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
672663
}
673664

674665
TEST_F(forward_list_test, PushFrontConstCustomSuccessfullWhenSpaceAvailableLValue)
@@ -1166,39 +1157,39 @@ TEST_F(forward_list_test, IteratorComparisonOfDifferentLists)
11661157

11671158
auto iterSut1 = sut11.begin();
11681159
auto iterSut2 = sut12.begin();
1169-
// @todo iox-#1613 remove EXPECT_DEATH
1170-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1171-
EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), "");
1160+
1161+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); },
1162+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
11721163

11731164
iterSut1 = sut11.before_begin();
11741165
iterSut2 = sut12.before_begin();
1175-
// @todo iox-#1613 remove EXPECT_DEATH
1176-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1177-
EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), "");
1166+
1167+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); },
1168+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
11781169

11791170
iterSut1 = sut11.end();
11801171
iterSut2 = sut12.end();
1181-
// @todo iox-#1613 remove EXPECT_DEATH
1182-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1183-
EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), "");
1172+
1173+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); },
1174+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
11841175

11851176
iterSut1 = sut11.begin();
11861177
iterSut2 = sut12.begin();
1187-
// @todo iox-#1613 remove EXPECT_DEATH
1188-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1189-
EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), "");
1178+
1179+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); },
1180+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
11901181

11911182
iterSut1 = sut11.before_begin();
11921183
iterSut2 = sut12.before_begin();
1193-
// @todo iox-#1613 remove EXPECT_DEATH
1194-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1195-
EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), "");
1184+
1185+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); },
1186+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
11961187

11971188
iterSut1 = sut11.end();
11981189
iterSut2 = sut12.end();
1199-
// @todo iox-#1613 remove EXPECT_DEATH
1200-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1201-
EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), "");
1190+
1191+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); },
1192+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
12021193
}
12031194

12041195

@@ -1988,9 +1979,7 @@ TEST_F(forward_list_test, invalidIteratorErase)
19881979
auto iter = sut.begin();
19891980
sut.pop_front();
19901981

1991-
// @todo iox-#1613 remove EXPECT_DEATH
1992-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
1993-
EXPECT_DEATH(sut.erase_after(iter), "");
1982+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { sut.erase_after(iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED);
19941983
}
19951984

19961985
TEST_F(forward_list_test, invalidIteratorIncrement)
@@ -2005,9 +1994,7 @@ TEST_F(forward_list_test, invalidIteratorIncrement)
20051994
auto iter = sut.cbegin();
20061995
sut.pop_front();
20071996

2008-
// @todo iox-#1613 remove EXPECT_DEATH
2009-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
2010-
EXPECT_DEATH(++iter, "");
1997+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { ++iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED);
20111998
}
20121999

20132000
TEST_F(forward_list_test, invalidIteratorComparison)
@@ -2022,9 +2009,8 @@ TEST_F(forward_list_test, invalidIteratorComparison)
20222009
auto iter = sut.cbegin();
20232010
sut.pop_front();
20242011

2025-
// @todo iox-#1613 remove EXPECT_DEATH
2026-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
2027-
EXPECT_DEATH(dummyFunc(sut.cbegin() == iter), "");
2012+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(sut.cbegin() == iter); },
2013+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
20282014
}
20292015

20302016
TEST_F(forward_list_test, invalidIteratorComparisonUnequal)
@@ -2039,9 +2025,8 @@ TEST_F(forward_list_test, invalidIteratorComparisonUnequal)
20392025
sut.pop_front();
20402026
auto iter2 = sut.cbegin();
20412027

2042-
// @todo iox-#1613 remove EXPECT_DEATH
2043-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
2044-
EXPECT_DEATH(dummyFunc(iter2 != iter), "");
2028+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iter2 != iter); },
2029+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
20452030
}
20462031

20472032
TEST_F(forward_list_test, invalidIteratorDereferencing)
@@ -2056,9 +2041,7 @@ TEST_F(forward_list_test, invalidIteratorDereferencing)
20562041
auto iter = sut.cbegin();
20572042
sut.pop_front();
20582043

2059-
// @todo iox-#1613 remove EXPECT_DEATH
2060-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
2061-
EXPECT_DEATH(sut.remove(*iter), "");
2044+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { sut.remove(*iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED);
20622045
}
20632046

20642047
TEST_F(forward_list_test, invalidIteratorAddressOfOperator)
@@ -2073,9 +2056,8 @@ TEST_F(forward_list_test, invalidIteratorAddressOfOperator)
20732056
auto iter = sut.cbegin();
20742057
sut.pop_front();
20752058

2076-
// @todo iox-#1613 remove EXPECT_DEATH
2077-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
2078-
EXPECT_DEATH(dummyFunc(iter->m_value == 12U), "");
2059+
IOX_EXPECT_FATAL_FAILURE<iox::HoofsError>([&] { IOX_DISCARD_RESULT(iter->m_value == 12U); },
2060+
iox::HoofsError::EXPECTS_ENSURES_FAILED);
20792061
}
20802062

20812063
TEST_F(forward_list_test, ListIsCopyableViaMemcpy)

iceoryx_dust/test/moduletests/test_file_reader.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ TEST_F(FileReader_test, errorTerminateMode)
160160
std::set_terminate([]() { std::cout << "", std::abort(); });
161161

162162
// @todo iox-#1613 remove EXPECT_DEATH
163+
// using IOX_EXPECT_FATAL_FAILURE currently causes issues with the leak sanitizer with this test
163164
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c)
164165
EXPECT_DEATH(
165166
{

0 commit comments

Comments
 (0)