From be1c2207f583be7314d7af221a34b7c14555a5a4 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Mon, 6 Feb 2023 23:37:06 +0100 Subject: [PATCH 01/15] iox-#1613 Add EXPECT_FATAL_FAILURE function to replace EXPECT_DEATH --- .../iceoryx_hoofs/testing/fatal_failure.hpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp new file mode 100644 index 0000000000..aece9356eb --- /dev/null +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2023 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "iceoryx_hoofs/testing/mocks/error_handler_mock.hpp" +#include "test.hpp" + +#include +#include + +namespace iox +{ +namespace testing +{ +template +void EXPECT_FATAL_FAILURE(const std::function& testFunction, + const ErrorType expectedError, + const iox::ErrorLevel expectedErrorLevel) +{ + auto th = std::thread([&] { + constexpr int JMP_VALUE{1}; + std::jmp_buf jmpBuffer; + + auto errorHandlerGuard = + iox::ErrorHandlerMock::setTemporaryErrorHandler([&](const auto error, const auto errorLevel) { + EXPECT_THAT(error, ::testing::Eq(expectedError)); + EXPECT_THAT(errorLevel, ::testing::Eq(expectedErrorLevel)); + + // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback + std::longjmp(&jmpBuffer[0], JMP_VALUE); + }); + + // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback + if (setjmp(&jmpBuffer[0]) == JMP_VALUE) + { + return; + } + + testFunction(); + + GTEST_FAIL() << "Expected fatal failure but execution continued!"; + }); + + th.join(); +} +} // namespace testing +} // namespace iox From 93082567c15ae56ebabab6860e44324f9b415264 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Mon, 6 Feb 2023 23:37:51 +0100 Subject: [PATCH 02/15] iox-#1613 Use EXPECT_FATAL_FAILURE in iceoryx_hoofs tests --- .../moduletests/test_concurrent_loffli.cpp | 31 +++-- .../moduletests/test_cxx_function_ref.cpp | 15 ++- .../test/moduletests/test_cxx_list.cpp | 125 +++++++++--------- ...est_design_functional_interface_expect.cpp | 12 +- .../moduletests/test_vocabulary_expected.cpp | 94 +++++++------ .../moduletests/test_vocabulary_string.cpp | 57 ++++---- 6 files changed, 185 insertions(+), 149 deletions(-) diff --git a/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp b/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp index 867b7f0903..2d6d654373 100644 --- a/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp +++ b/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp @@ -15,7 +15,9 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/error_handling/error_handling.hpp" #include "iceoryx_hoofs/internal/concurrent/loffli.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "test.hpp" #include @@ -25,6 +27,7 @@ namespace { using namespace ::testing; +using namespace iox::testing; constexpr uint32_t Size{4}; using LoFFLiTestSubjects = Types; @@ -53,32 +56,38 @@ class LoFFLi_test : public Test TYPED_TEST(LoFFLi_test, Misuse_NullptrMemory) { ::testing::Test::RecordProperty("TEST_ID", "ab877f29-cab0-48ae-a2c0-054633b6415a"); + decltype(this->m_loffli) loFFLi; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(loFFLi.init(nullptr, 1), ".*"); + + EXPECT_FATAL_FAILURE( + [&] { loFFLi.init(nullptr, 1); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(LoFFLi_test, Misuse_ZeroSize) { ::testing::Test::RecordProperty("TEST_ID", "fb9c797b-22b4-4572-a7a2-eaf13574dbac"); - // NOLINTNEXTLINE(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) needed to test LoFFLi::init + + // NOLINTBEGIN(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) needed to test LoFFLi::init uint32_t memoryLoFFLi[4]; decltype(this->m_loffli) loFFLi; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(loFFLi.init(&memoryLoFFLi[0], 0), ".*"); + + EXPECT_FATAL_FAILURE( + [&] { loFFLi.init(&memoryLoFFLi[0], 0); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + // NOLINTEND(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) } TYPED_TEST(LoFFLi_test, Misuse_SizeToLarge) { ::testing::Test::RecordProperty("TEST_ID", "14b4b82c-ae2b-4bd2-97cf-93fcea87f050"); - // NOLINTNEXTLINE(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) needed to test LoFFLi::init + + // NOLINTBEGIN(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) needed to test LoFFLi::init uint32_t memoryLoFFLi[4]; decltype(this->m_loffli) loFFLi; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(loFFLi.init(&memoryLoFFLi[0], UINT32_MAX - 1), ".*"); + + EXPECT_FATAL_FAILURE([&] { loFFLi.init(&memoryLoFFLi[0], UINT32_MAX - 1); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); + // NOLINTEND(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) } diff --git a/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp b/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp index 8557e219b1..387b8f2cd8 100644 --- a/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp +++ b/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp @@ -17,13 +17,15 @@ #include "iceoryx_hoofs/cxx/attributes.hpp" #include "iceoryx_hoofs/cxx/function_ref.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "test.hpp" - namespace { using namespace ::testing; using namespace iox::cxx; +using namespace iox::testing; constexpr int FREE_FUNC_TEST_VALUE = 42 + 42; constexpr int FUNCTOR_TEST_VALUE = 11; @@ -162,15 +164,16 @@ TEST_F(function_refTest, CreateValidByMoveAssignResultEqual) TEST_F(function_refDeathTest, CallMovedFromLeadsToTermination) { ::testing::Test::RecordProperty("TEST_ID", "3402f27e-ced5-483f-ab39-0069cfd172ac"); + auto lambda = []() -> int { return 7654; }; function_ref sut1{lambda}; function_ref sut2{std::move(sut1)}; + // NOLINTJUSTIFICATION Use after move is tested here - // NOLINTBEGIN(bugprone-use-after-move, hicpp-invalid-access-moved, cppcoreguidelines-pro-type-vararg, - // cppcoreguidelines-avoid-goto) - EXPECT_DEATH(sut1(), ""); // ERROR: Empty function_ref invoked - // NOLINTEND(bugprone-use-after-move, hicpp-invalid-access-moved, cppcoreguidelines-pro-type-vararg, - // cppcoreguidelines-avoid-goto) + // NOLINTBEGIN(bugprone-use-after-move, hicpp-invalid-access-moved) + EXPECT_FATAL_FAILURE( + [&] { sut1(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + // NOLINTEND(bugprone-use-after-move, hicpp-invalid-access-moved) } TEST_F(function_refTest, CreateValidAndSwapResultEqual) diff --git a/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp b/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp index ab0e4038ea..a8b90a11c8 100644 --- a/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp +++ b/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp @@ -17,7 +17,9 @@ #include "iceoryx_hoofs/cxx/attributes.hpp" #include "iceoryx_hoofs/cxx/list.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" #include "iceoryx_hoofs/log/logging.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "test.hpp" @@ -25,6 +27,7 @@ namespace { using namespace ::testing; using namespace iox::cxx; +using namespace iox::testing; constexpr uint64_t TESTLISTCAPACITY{10U}; constexpr int64_t TEST_LIST_ELEMENT_DEFAULT_VALUE{-99L}; @@ -149,15 +152,6 @@ int64_t iteratorTraitReturnDoubleValue(IterType iter) IterValueType m_value = *iter; return (2 * m_value); // will only work for integer-convertible m_value types } - -// in context of EXPECT_DEATH tests, dummyFunc() shall help suppressing following warning : -// -Wunused-comparison -// reason: the warning is already addressed with the internal handling, which shall be tested here -bool dummyFunc(bool whatever) -{ - IOX_LOG(ERROR) << "Never get here - ever " << whatever; - return whatever; -} } // namespace @@ -272,15 +266,19 @@ TEST_F(list_test, FullWhenFilledWithCapacityElements) TEST_F(list_test, FullWhenFilledWithMoreThanCapacityElements) { ::testing::Test::RecordProperty("TEST_ID", "585bb3d9-112c-4db8-af5e-e4c646723515"); - for (uint64_t i = 0U; i < sut.capacity(); ++i) - { - sut.emplace_front(); - } - EXPECT_THAT(sut.full(), Eq(true)); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut.emplace_front(), ""); + EXPECT_FATAL_FAILURE( + [&] { + for (uint64_t i = 0U; i < sut.capacity(); ++i) + { + sut.emplace_front(); + } + + EXPECT_THAT(sut.full(), Eq(true)); + sut.emplace_front(); + }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); } TEST_F(list_test, NotFullWhenFilledWithCapacityAndEraseOneElements) { @@ -727,9 +725,8 @@ TEST_F(list_test, EmplaceBackWithMoreThanCapacityElements) } else { - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut1.emplace_back(cnt), ""); + EXPECT_FATAL_FAILURE( + [&] { sut1.emplace_back(cnt); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } ++cnt; } @@ -763,9 +760,8 @@ TEST_F(list_test, EmplaceWithWrongListIterator) ++cnt; } - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut11.emplace(iterOfSut2, cnt), ""); + EXPECT_FATAL_FAILURE( + [&] { sut11.emplace(iterOfSut2, cnt); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(list_test, PushFrontConstCustomSuccessfullWhenSpaceAvailableLValue) @@ -1499,39 +1495,45 @@ TEST_F(list_test, IteratorComparisonOfDifferentLists) auto iterSut1 = sut11.begin(); auto iterSut2 = sut12.begin(); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); iterSut1 = sut11.end(); iterSut2 = sut12.end(); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); iterSut1 = sut11.end(); iterSut2 = sut12.end(); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); } @@ -2313,9 +2315,9 @@ TEST_F(list_test, invalidIteratorErase) ++iter; sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut.erase(iter), ""); + + EXPECT_FATAL_FAILURE( + [&] { sut.erase(iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(list_test, invalidIteratorIncrement) @@ -2331,9 +2333,8 @@ TEST_F(list_test, invalidIteratorIncrement) ++iter; sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(++iter, ""); + EXPECT_FATAL_FAILURE( + [&] { ++iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(list_test, invalidIteratorDecrement) @@ -2349,9 +2350,8 @@ TEST_F(list_test, invalidIteratorDecrement) ++iter; sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(--iter, ""); + EXPECT_FATAL_FAILURE( + [&] { --iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(list_test, invalidIteratorComparison) @@ -2367,9 +2367,10 @@ TEST_F(list_test, invalidIteratorComparison) ++iter; auto iter2 IOX_MAYBE_UNUSED = sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(sut.cbegin() == iter), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut.cbegin() == iter); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); } TEST_F(list_test, invalidIteratorComparisonUnequal) @@ -2385,9 +2386,9 @@ TEST_F(list_test, invalidIteratorComparisonUnequal) ++iter; auto iter2 = sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iter2 != iter), ""); + + EXPECT_FATAL_FAILURE( + [&] { IOX_DISCARD_RESULT(iter2 != iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(list_test, invalidIteratorDereferencing) @@ -2403,9 +2404,8 @@ TEST_F(list_test, invalidIteratorDereferencing) ++iter; auto iter2 IOX_MAYBE_UNUSED = sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc((*iter).m_value), ""); + EXPECT_FATAL_FAILURE( + [&] { IOX_DISCARD_RESULT((*iter).m_value); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(list_test, invalidIteratorAddressOfOperator) @@ -2421,9 +2421,10 @@ TEST_F(list_test, invalidIteratorAddressOfOperator) ++iter; auto iter2 IOX_MAYBE_UNUSED = sut.erase(iter); - /// @NOLINTJUSTIFICATION @todo iox-#1613 remove EXPECT_DEATH - /// @NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iter->m_value == 12U), ""); + + EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iter->m_value == 12U); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED, + iox::ErrorLevel::FATAL); } TEST_F(list_test, ListIsCopyableViaMemcpy) diff --git a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp index ae5403acc1..6c7fbb271d 100644 --- a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp +++ b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp @@ -13,15 +13,16 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 -// + #include "iceoryx_hoofs/error_handling/error_handling.hpp" -#include "iceoryx_hoofs/testing/mocks/error_handler_mock.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "test_design_functional_interface_types.hpp" namespace { using namespace test_design_functional_interface; using namespace ::testing; +using namespace iox::testing; // the macro is used as code generator to make the tests more readable. because of the // template nature of those tests this cannot be implemented in the same readable fashion @@ -83,11 +84,8 @@ void ExpectDoesCallTerminateWhenObjectIsInvalid(const ExpectCall& callExpect) { SutType sut = FactoryType::createInvalidObject(); { - auto handle = - iox::ErrorHandlerMock::setTemporaryErrorHandler([&](auto, auto) { std::terminate(); }); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(callExpect(sut), ".*"); + EXPECT_FATAL_FAILURE( + [&] { callExpect(sut); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } } diff --git a/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp b/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp index 4e86f29551..54c0dde131 100644 --- a/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp +++ b/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp @@ -15,6 +15,8 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iox/expected.hpp" #include "iox/string.hpp" #include "test.hpp" @@ -22,6 +24,7 @@ using namespace ::testing; using namespace ::iox::cxx; using namespace ::iox; +using namespace ::iox::testing; namespace { @@ -583,121 +586,134 @@ TEST_F(expected_test, MoveAssignmentIsNotEnforcedInMoveConstructor) TEST_F(expected_test, AccessingErrorOfLValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "da162edf-06b5-47d2-b35f-361d6004a6c4"); + auto sut = expected::create_value(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ sut.get_error(); }, ""); // ERROR: Trying to access an error but a value is stored + + EXPECT_FATAL_FAILURE( + [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingErrorOfConstLValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "324cab7d-ba04-4ff0-870f-79af993c272f"); + const auto sut = expected::create_value(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ sut.get_error(); }, ""); // ERROR: Trying to access an error but a value is stored + + EXPECT_FATAL_FAILURE( + [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingErrorOfRValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "0a4309e8-d9f3-41a9-9c4b-bdcfda917277"); + auto sut = expected::create_value(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ std::move(sut).get_error(); }, ""); // ERROR: Trying to access an error but a value is stored + + EXPECT_FATAL_FAILURE( + [&] { std::move(sut).get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithArrowOpLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "1a821c6f-83db-4fe1-8adf-873afa1251a1"); + auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ IOX_DISCARD_RESULT(sut->m_a); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { IOX_DISCARD_RESULT(sut->m_a); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithArrowOpLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "c4f04d7c-9fa3-48f6-a6fd-b8e4e47b7632"); + const auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ IOX_DISCARD_RESULT(sut->m_a); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { IOX_DISCARD_RESULT(sut->m_a); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithDerefOpLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "08ce6a3f-3813-46de-8e1e-3ffe8087521e"); + auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ *sut; }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { *sut; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithDerefOpLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "838dd364-f91f-40a7-9720-2b662a045b1e"); + const auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ *sut; }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { *sut; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "92139583-b8d6-4d83-ae7e-f4109b98d214"); + auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ sut.value(); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "1bcbb835-8b4c-4430-a534-a26573c2380d"); + const auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ sut.value(); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingValueOfRValueExpectedWhichContainsErrorLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "32d59b52-81f5-417a-8670-dfb2c54fedfb"); + auto sut = expected::create_error(TestError::ERROR1); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ std::move(sut).value(); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { std::move(sut).value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingErrorOfLValueExpectedWhichContainsValueLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "aee85ead-e066-49fd-99fe-6f1a6045756d"); + constexpr int VALID_VALUE{42}; auto sut = expected::create_value(VALID_VALUE, VALID_VALUE); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ sut.get_error(); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingErrorOfConstLValueExpectedWhichContainsValueLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "a49cf02e-b165-4fd6-9c24-65cedc6cddb9"); + constexpr int VALID_VALUE{42}; const auto sut = expected::create_value(VALID_VALUE, VALID_VALUE); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ sut.get_error(); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, AccessingErrorOfRValueExpectedWhichContainsValueLeadsToErrorHandlerCall) { ::testing::Test::RecordProperty("TEST_ID", "0ea90b5d-1af6-494a-b35c-da103bed2331"); + constexpr int VALID_VALUE{42}; auto sut = expected::create_value(VALID_VALUE, VALID_VALUE); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, cppcoreguidelines-avoid-goto, hicpp-avoid-goto, hicpp-vararg) - EXPECT_DEATH({ std::move(sut).get_error(); }, ""); // ERROR: Trying to access a value but an error is stored + + EXPECT_FATAL_FAILURE( + [&] { std::move(sut).get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TEST_F(expected_test, TwoErrorOnlyExpectedWithEqualErrorAreEqual) diff --git a/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp b/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp index 59ab450297..60abeda4d6 100644 --- a/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp +++ b/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp @@ -15,6 +15,8 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iox/string.hpp" #include "test.hpp" @@ -22,6 +24,7 @@ namespace { using namespace ::testing; using namespace iox; +using namespace iox::testing; template class stringTyped_test : public Test @@ -3140,19 +3143,20 @@ TEST(String100, FindLastOfForNotIncludedSTDStringFails) TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaAtFails) { ::testing::Test::RecordProperty("TEST_ID", "89817818-f05a-4ceb-8663-9727d227048c"); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ this->testSubject.at(0U); }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { this->testSubject.at(0U); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaAtFails) { ::testing::Test::RecordProperty("TEST_ID", "68035709-5f8d-4bcb-80ce-ad5619aba84a"); + using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ this->testSubject.at(STRINGCAP); }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { this->testSubject.at(STRINGCAP); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNonEmptyStringViaAtReturnsCorrectCharacter) @@ -3182,23 +3186,25 @@ TYPED_TEST(stringTyped_test, AccessAndAssignToMaxPositionOfNotEmptyStringViaAtSu TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaConstAtFails) { ::testing::Test::RecordProperty("TEST_ID", "5cf6d322-6ee9-41ce-bbf6-4e0d193fa938"); + using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); const string sut; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ sut.at(0U); }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { sut.at(0U); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaConstAtFails) { ::testing::Test::RecordProperty("TEST_ID", "90a986f4-b29b-4ce7-ad55-79cc4b7b2b29"); + using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); const string sut; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ sut.at(STRINGCAP); }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { sut.at(STRINGCAP); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNotEmptyStringViaConstAtReturnsCorrectCharacter) @@ -3226,19 +3232,20 @@ TYPED_TEST(stringTyped_test, AccessMaxPositionOfNotEmptyStringViaConstAtSucceeds TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaSubscriptOperatorFails) { ::testing::Test::RecordProperty("TEST_ID", "95ced457-1aec-47e9-a496-0197ea3f4600"); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ this->testSubject[0U]; }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { this->testSubject[0U]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaSubscriptOperatorFails) { ::testing::Test::RecordProperty("TEST_ID", "ab52924e-1d6a-41e1-a8a9-8cfd9ab2120d"); + using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ this->testSubject[STRINGCAP]; }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { this->testSubject[STRINGCAP]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNotEmptyStringViaSubscriptOperatorReturnsCorrectCharacter) @@ -3268,23 +3275,25 @@ TYPED_TEST(stringTyped_test, AccessAndAssignToMaxPositionOfNotEmptyStringViaSubs TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaConstSubscriptOperatorFails) { ::testing::Test::RecordProperty("TEST_ID", "7ca75e53-8e26-4451-8712-a86bfe5bd32c"); + using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); const string sut; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ sut[0U]; }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { sut[0U]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaConstSubscriptOperatorFails) { ::testing::Test::RecordProperty("TEST_ID", "5498e314-d321-464a-a667-400ee0c4d81f"); + using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); const string sut; - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH({ sut[STRINGCAP]; }, ""); // ERROR: Out of bounds access ! + + EXPECT_FATAL_FAILURE( + [&] { sut[STRINGCAP]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNotEmptyStringViaConstSubscriptOperatorReturnsCorrectCharacter) From 1a55f722ead43ffaf2eaf2fbaf5fe4ef36e2848a Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 01:21:01 +0100 Subject: [PATCH 03/15] iox-#1613 Use cxx::function for temporary error handler to make leak sanitizer play nice with EXPECT_FATAL_FAILURE --- .../include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp index 39fa207c9b..bc1890a274 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp @@ -16,6 +16,7 @@ #ifndef IOX_HOOFS_TESTUTILS_ERROR_HANDLER_MOCK_HPP #define IOX_HOOFS_TESTUTILS_ERROR_HANDLER_MOCK_HPP +#include "iceoryx_hoofs/cxx/function.hpp" #include "iceoryx_hoofs/error_handling/error_handler.hpp" #include @@ -24,7 +25,7 @@ namespace iox { template -using TypedHandlerFunction = std::function; +using TypedHandlerFunction = cxx::function; /// @brief This mock is needed for unit testing, special debugging cases and /// other corner cases where we'd like to explicitly suppress the From 4ad994a0a7fd7f07ee31ea27a9a3b176e119caaf Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 21:24:50 +0100 Subject: [PATCH 04/15] iox-#1613 Add IOX_EXPECT_NO_FATAL_FAILURE and documentation --- .../iceoryx_hoofs/testing/fatal_failure.hpp | 79 +++++++++++++++++-- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp index aece9356eb..9496d5af18 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp @@ -14,9 +14,14 @@ // // SPDX-License-Identifier: Apache-2.0 +#ifndef IOX_HOOFS_TESTING_FATAL_FAILURE_HPP +#define IOX_HOOFS_TESTING_FATAL_FAILURE_HPP + #include "iceoryx_hoofs/testing/mocks/error_handler_mock.hpp" +#include "iox/optional.hpp" #include "test.hpp" +#include #include #include @@ -24,19 +29,33 @@ namespace iox { namespace testing { +namespace detail +{ +/// @brief This function is the base for 'IOX_EXPECT_FATAL_FAILURE' and 'IOX_EXPECT_NO_FATAL_FAILURE' and should not be +/// used by its own. The function only works in combination with the iceoryx error handler. +/// @tparam[in] ErrorType The error type which is expected, e.g. 'iox::HoofsError' +/// @param[in] testFunction This function will be executed as SUT and might call the error handler with a 'FATAL' error +/// level +/// @param[in] onFatalFailurePath This function will be executed on the failure path after the failure was detected +/// @param[in] onNonFatalFailurePath This function will be executed on the non-failure path if no failure was detected +/// @return true if a fatal failure occurs, false otherwise template -void EXPECT_FATAL_FAILURE(const std::function& testFunction, - const ErrorType expectedError, - const iox::ErrorLevel expectedErrorLevel) +bool FATAL_FAILURE_TEST(const std::function& testFunction, + const std::function& onFatalFailurePath, + const std::function& onNonFatalFailurePath) { + std::atomic hasFatalFailure{false}; auto th = std::thread([&] { constexpr int JMP_VALUE{1}; std::jmp_buf jmpBuffer; + optional detectedError; + optional detectedErrorLevel; + auto errorHandlerGuard = iox::ErrorHandlerMock::setTemporaryErrorHandler([&](const auto error, const auto errorLevel) { - EXPECT_THAT(error, ::testing::Eq(expectedError)); - EXPECT_THAT(errorLevel, ::testing::Eq(expectedErrorLevel)); + detectedError.emplace(error); + detectedErrorLevel.emplace(errorLevel); // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback std::longjmp(&jmpBuffer[0], JMP_VALUE); @@ -45,15 +64,63 @@ void EXPECT_FATAL_FAILURE(const std::function& testFunction, // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback if (setjmp(&jmpBuffer[0]) == JMP_VALUE) { + hasFatalFailure = true; + // using value directly is save since this path is only executed if the error handler was called and the + // respective values were set + onFatalFailurePath(detectedError.value(), detectedErrorLevel.value()); return; } testFunction(); - GTEST_FAIL() << "Expected fatal failure but execution continued!"; + onNonFatalFailurePath(); }); th.join(); + + return hasFatalFailure.load(std::memory_order_relaxed); +} +} // namespace detail + +/// @brief This function is used in cases a fatal failure is expected. The function only works in combination with the +/// iceoryx error handler. +/// @tparam[in] ErrorType The error type which is expected, e.g. 'iox::HoofsError' +/// @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler +/// @param[in] expectedError The error value which triggered the fatal failure +/// @return true if a fatal failure occurs, false otherwise +template +bool EXPECT_FATAL_FAILURE(const std::function& testFunction, + const ErrorType expectedError, + const iox::ErrorLevel) +{ + return detail::FATAL_FAILURE_TEST( + testFunction, + [&](const auto error, const auto errorLevel) { + EXPECT_THAT(error, ::testing::Eq(expectedError)); + EXPECT_THAT(errorLevel, ::testing::Eq(iox::ErrorLevel::FATAL)); + }, + [&] { GTEST_FAIL() << "Expected fatal failure but execution continued!"; }); +} + +/// @brief This function is used in cases no fatal failure is expected but could potentially occur. The function only +/// works in combination with the iceoryx error handler. +/// @tparam[in] ErrorType The error type which is expected if the test fails, e.g. 'iox::HoofsError' +/// @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler +/// @return true if no fatal failure occurs, false otherwise +template +bool IOX_EXPECT_NO_FATAL_FAILURE(const std::function& testFunction) +{ + return !detail::FATAL_FAILURE_TEST( + testFunction, + [&](const auto error, const auto errorLevel) { + GTEST_FAIL() << "Expected no fatal failure but execution failed! Error code: " << error + << "; Error level: " << errorLevel; + }, + [&] {}); + return false; } + } // namespace testing } // namespace iox + +#endif // IOX_HOOFS_TESTING_FATAL_FAILURE_HPP From f5c07376c5bd04ee3da2a6e185cedbccb22aa703 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 21:40:29 +0100 Subject: [PATCH 05/15] iox-#1613 Add IOX prefix to EXPECT_FATAL_FAILURE and remove superfluous parameter --- .../moduletests/test_concurrent_loffli.cpp | 13 ++-- .../moduletests/test_cxx_function_ref.cpp | 3 +- .../test/moduletests/test_cxx_list.cpp | 71 ++++++++----------- ...est_design_functional_interface_expect.cpp | 3 +- .../moduletests/test_vocabulary_expected.cpp | 43 +++++------ .../moduletests/test_vocabulary_string.cpp | 27 +++---- .../iceoryx_hoofs/testing/fatal_failure.hpp | 4 +- 7 files changed, 66 insertions(+), 98 deletions(-) diff --git a/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp b/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp index 2d6d654373..2bce21af8c 100644 --- a/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp +++ b/iceoryx_hoofs/test/moduletests/test_concurrent_loffli.cpp @@ -59,8 +59,8 @@ TYPED_TEST(LoFFLi_test, Misuse_NullptrMemory) decltype(this->m_loffli) loFFLi; - EXPECT_FATAL_FAILURE( - [&] { loFFLi.init(nullptr, 1); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { loFFLi.init(nullptr, 1); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(LoFFLi_test, Misuse_ZeroSize) @@ -71,8 +71,8 @@ TYPED_TEST(LoFFLi_test, Misuse_ZeroSize) uint32_t memoryLoFFLi[4]; decltype(this->m_loffli) loFFLi; - EXPECT_FATAL_FAILURE( - [&] { loFFLi.init(&memoryLoFFLi[0], 0); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { loFFLi.init(&memoryLoFFLi[0], 0); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); // NOLINTEND(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) } @@ -84,9 +84,8 @@ TYPED_TEST(LoFFLi_test, Misuse_SizeToLarge) uint32_t memoryLoFFLi[4]; decltype(this->m_loffli) loFFLi; - EXPECT_FATAL_FAILURE([&] { loFFLi.init(&memoryLoFFLi[0], UINT32_MAX - 1); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { loFFLi.init(&memoryLoFFLi[0], UINT32_MAX - 1); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); // NOLINTEND(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) } diff --git a/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp b/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp index 387b8f2cd8..7bd2fcd895 100644 --- a/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp +++ b/iceoryx_hoofs/test/moduletests/test_cxx_function_ref.cpp @@ -171,8 +171,7 @@ TEST_F(function_refDeathTest, CallMovedFromLeadsToTermination) // NOLINTJUSTIFICATION Use after move is tested here // NOLINTBEGIN(bugprone-use-after-move, hicpp-invalid-access-moved) - EXPECT_FATAL_FAILURE( - [&] { sut1(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut1(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); // NOLINTEND(bugprone-use-after-move, hicpp-invalid-access-moved) } diff --git a/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp b/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp index a8b90a11c8..7564c2edf3 100644 --- a/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp +++ b/iceoryx_hoofs/test/moduletests/test_cxx_list.cpp @@ -267,7 +267,7 @@ TEST_F(list_test, FullWhenFilledWithMoreThanCapacityElements) { ::testing::Test::RecordProperty("TEST_ID", "585bb3d9-112c-4db8-af5e-e4c646723515"); - EXPECT_FATAL_FAILURE( + IOX_EXPECT_FATAL_FAILURE( [&] { for (uint64_t i = 0U; i < sut.capacity(); ++i) { @@ -277,8 +277,7 @@ TEST_F(list_test, FullWhenFilledWithMoreThanCapacityElements) EXPECT_THAT(sut.full(), Eq(true)); sut.emplace_front(); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, NotFullWhenFilledWithCapacityAndEraseOneElements) { @@ -725,8 +724,8 @@ TEST_F(list_test, EmplaceBackWithMoreThanCapacityElements) } else { - EXPECT_FATAL_FAILURE( - [&] { sut1.emplace_back(cnt); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut1.emplace_back(cnt); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } ++cnt; } @@ -760,8 +759,8 @@ TEST_F(list_test, EmplaceWithWrongListIterator) ++cnt; } - EXPECT_FATAL_FAILURE( - [&] { sut11.emplace(iterOfSut2, cnt); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut11.emplace(iterOfSut2, cnt); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, PushFrontConstCustomSuccessfullWhenSpaceAvailableLValue) @@ -1496,44 +1495,38 @@ TEST_F(list_test, IteratorComparisonOfDifferentLists) auto iterSut1 = sut11.begin(); auto iterSut2 = sut12.begin(); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.end(); iterSut2 = sut12.end(); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.end(); iterSut2 = sut12.end(); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } @@ -2316,8 +2309,7 @@ TEST_F(list_test, invalidIteratorErase) sut.erase(iter); - EXPECT_FATAL_FAILURE( - [&] { sut.erase(iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, invalidIteratorIncrement) @@ -2333,8 +2325,7 @@ TEST_F(list_test, invalidIteratorIncrement) ++iter; sut.erase(iter); - EXPECT_FATAL_FAILURE( - [&] { ++iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { ++iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, invalidIteratorDecrement) @@ -2350,8 +2341,7 @@ TEST_F(list_test, invalidIteratorDecrement) ++iter; sut.erase(iter); - EXPECT_FATAL_FAILURE( - [&] { --iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { --iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, invalidIteratorComparison) @@ -2368,9 +2358,8 @@ TEST_F(list_test, invalidIteratorComparison) auto iter2 IOX_MAYBE_UNUSED = sut.erase(iter); - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut.cbegin() == iter); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut.cbegin() == iter); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, invalidIteratorComparisonUnequal) @@ -2387,8 +2376,8 @@ TEST_F(list_test, invalidIteratorComparisonUnequal) auto iter2 = sut.erase(iter); - EXPECT_FATAL_FAILURE( - [&] { IOX_DISCARD_RESULT(iter2 != iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iter2 != iter); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, invalidIteratorDereferencing) @@ -2404,8 +2393,8 @@ TEST_F(list_test, invalidIteratorDereferencing) ++iter; auto iter2 IOX_MAYBE_UNUSED = sut.erase(iter); - EXPECT_FATAL_FAILURE( - [&] { IOX_DISCARD_RESULT((*iter).m_value); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT((*iter).m_value); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, invalidIteratorAddressOfOperator) @@ -2421,10 +2410,8 @@ TEST_F(list_test, invalidIteratorAddressOfOperator) ++iter; auto iter2 IOX_MAYBE_UNUSED = sut.erase(iter); - - EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iter->m_value == 12U); }, - iox::HoofsError::EXPECTS_ENSURES_FAILED, - iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iter->m_value == 12U); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(list_test, ListIsCopyableViaMemcpy) diff --git a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp index 6c7fbb271d..235e0b05bc 100644 --- a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp +++ b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp @@ -84,8 +84,7 @@ void ExpectDoesCallTerminateWhenObjectIsInvalid(const ExpectCall& callExpect) { SutType sut = FactoryType::createInvalidObject(); { - EXPECT_FATAL_FAILURE( - [&] { callExpect(sut); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { callExpect(sut); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } } diff --git a/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp b/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp index 54c0dde131..51e68d24c5 100644 --- a/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp +++ b/iceoryx_hoofs/test/moduletests/test_vocabulary_expected.cpp @@ -589,8 +589,7 @@ TEST_F(expected_test, AccessingErrorOfLValueErrorOnlyExpectedWhichContainsValueL auto sut = expected::create_value(); - EXPECT_FATAL_FAILURE( - [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingErrorOfConstLValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall) @@ -599,8 +598,7 @@ TEST_F(expected_test, AccessingErrorOfConstLValueErrorOnlyExpectedWhichContainsV const auto sut = expected::create_value(); - EXPECT_FATAL_FAILURE( - [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingErrorOfRValueErrorOnlyExpectedWhichContainsValueLeadsToErrorHandlerCall) @@ -609,8 +607,8 @@ TEST_F(expected_test, AccessingErrorOfRValueErrorOnlyExpectedWhichContainsValueL auto sut = expected::create_value(); - EXPECT_FATAL_FAILURE( - [&] { std::move(sut).get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { std::move(sut).get_error(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithArrowOpLeadsToErrorHandlerCall) @@ -619,8 +617,8 @@ TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithArrowO auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { IOX_DISCARD_RESULT(sut->m_a); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut->m_a); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithArrowOpLeadsToErrorHandlerCall) @@ -629,8 +627,8 @@ TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithA const auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { IOX_DISCARD_RESULT(sut->m_a); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut->m_a); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithDerefOpLeadsToErrorHandlerCall) @@ -639,8 +637,7 @@ TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorWithDerefO auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { *sut; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { *sut; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithDerefOpLeadsToErrorHandlerCall) @@ -649,8 +646,7 @@ TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorWithD const auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { *sut; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { *sut; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorLeadsToErrorHandlerCall) @@ -659,8 +655,7 @@ TEST_F(expected_test, AccessingValueOfLValueExpectedWhichContainsErrorLeadsToErr auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorLeadsToErrorHandlerCall) @@ -669,8 +664,7 @@ TEST_F(expected_test, AccessingValueOfConstLValueExpectedWhichContainsErrorLeads const auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingValueOfRValueExpectedWhichContainsErrorLeadsToErrorHandlerCall) @@ -679,8 +673,7 @@ TEST_F(expected_test, AccessingValueOfRValueExpectedWhichContainsErrorLeadsToErr auto sut = expected::create_error(TestError::ERROR1); - EXPECT_FATAL_FAILURE( - [&] { std::move(sut).value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { std::move(sut).value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingErrorOfLValueExpectedWhichContainsValueLeadsToErrorHandlerCall) @@ -690,8 +683,7 @@ TEST_F(expected_test, AccessingErrorOfLValueExpectedWhichContainsValueLeadsToErr constexpr int VALID_VALUE{42}; auto sut = expected::create_value(VALID_VALUE, VALID_VALUE); - EXPECT_FATAL_FAILURE( - [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingErrorOfConstLValueExpectedWhichContainsValueLeadsToErrorHandlerCall) @@ -701,8 +693,7 @@ TEST_F(expected_test, AccessingErrorOfConstLValueExpectedWhichContainsValueLeads constexpr int VALID_VALUE{42}; const auto sut = expected::create_value(VALID_VALUE, VALID_VALUE); - EXPECT_FATAL_FAILURE( - [&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, AccessingErrorOfRValueExpectedWhichContainsValueLeadsToErrorHandlerCall) @@ -712,8 +703,8 @@ TEST_F(expected_test, AccessingErrorOfRValueExpectedWhichContainsValueLeadsToErr constexpr int VALID_VALUE{42}; auto sut = expected::create_value(VALID_VALUE, VALID_VALUE); - EXPECT_FATAL_FAILURE( - [&] { std::move(sut).get_error(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { std::move(sut).get_error(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(expected_test, TwoErrorOnlyExpectedWithEqualErrorAreEqual) diff --git a/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp b/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp index 60abeda4d6..2f45c756c0 100644 --- a/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp +++ b/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp @@ -3144,8 +3144,8 @@ TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaAtFails) { ::testing::Test::RecordProperty("TEST_ID", "89817818-f05a-4ceb-8663-9727d227048c"); - EXPECT_FATAL_FAILURE( - [&] { this->testSubject.at(0U); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { this->testSubject.at(0U); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaAtFails) @@ -3155,8 +3155,8 @@ TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaAtFails) using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); - EXPECT_FATAL_FAILURE( - [&] { this->testSubject.at(STRINGCAP); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { this->testSubject.at(STRINGCAP); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNonEmptyStringViaAtReturnsCorrectCharacter) @@ -3191,8 +3191,7 @@ TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaConstAtFails) constexpr auto STRINGCAP = MyString().capacity(); const string sut; - EXPECT_FATAL_FAILURE( - [&] { sut.at(0U); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.at(0U); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaConstAtFails) @@ -3203,8 +3202,7 @@ TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaConstAtFails) constexpr auto STRINGCAP = MyString().capacity(); const string sut; - EXPECT_FATAL_FAILURE( - [&] { sut.at(STRINGCAP); }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut.at(STRINGCAP); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNotEmptyStringViaConstAtReturnsCorrectCharacter) @@ -3233,8 +3231,7 @@ TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaSubscriptOperatorFail { ::testing::Test::RecordProperty("TEST_ID", "95ced457-1aec-47e9-a496-0197ea3f4600"); - EXPECT_FATAL_FAILURE( - [&] { this->testSubject[0U]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { this->testSubject[0U]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaSubscriptOperatorFails) @@ -3244,8 +3241,8 @@ TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaSubscriptOperatorFails) using MyString = typename TestFixture::stringType; constexpr auto STRINGCAP = MyString().capacity(); - EXPECT_FATAL_FAILURE( - [&] { this->testSubject[STRINGCAP]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { this->testSubject[STRINGCAP]; }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNotEmptyStringViaSubscriptOperatorReturnsCorrectCharacter) @@ -3280,8 +3277,7 @@ TYPED_TEST(stringTyped_test, AccessPositionOfEmptyStringViaConstSubscriptOperato constexpr auto STRINGCAP = MyString().capacity(); const string sut; - EXPECT_FATAL_FAILURE( - [&] { sut[0U]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut[0U]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaConstSubscriptOperatorFails) @@ -3292,8 +3288,7 @@ TYPED_TEST(stringTyped_test, AccessPositionOutOfBoundsViaConstSubscriptOperatorF constexpr auto STRINGCAP = MyString().capacity(); const string sut; - EXPECT_FATAL_FAILURE( - [&] { sut[STRINGCAP]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED, iox::ErrorLevel::FATAL); + IOX_EXPECT_FATAL_FAILURE([&] { sut[STRINGCAP]; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(stringTyped_test, AccessFirstPositionOfNotEmptyStringViaConstSubscriptOperatorReturnsCorrectCharacter) diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp index 9496d5af18..477f040832 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp @@ -89,9 +89,7 @@ bool FATAL_FAILURE_TEST(const std::function& testFunction, /// @param[in] expectedError The error value which triggered the fatal failure /// @return true if a fatal failure occurs, false otherwise template -bool EXPECT_FATAL_FAILURE(const std::function& testFunction, - const ErrorType expectedError, - const iox::ErrorLevel) +bool IOX_EXPECT_FATAL_FAILURE(const std::function& testFunction, const ErrorType expectedError) { return detail::FATAL_FAILURE_TEST( testFunction, From 40d9df763e3499124a5f8eba0ab3f06e83f476dd Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 22:03:54 +0100 Subject: [PATCH 06/15] iox-#1613 Extend error handling design document and add example code --- doc/design/error-handling.md | 17 +++++++++++++++++ .../iceoryx_hoofs/testing/fatal_failure.hpp | 16 ++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/doc/design/error-handling.md b/doc/design/error-handling.md index f63513405a..c600d03985 100644 --- a/doc/design/error-handling.md +++ b/doc/design/error-handling.md @@ -264,6 +264,23 @@ auto errorFunc = [](Error& error) { func(arg).and_then(successFunc).or_else(errorFunc); ``` +### Testing fatal error + +For fatal errors the error handler will terminate the execution of the binary. In order to test these paths the +`iox::testing::IOX_EXPECT_FATAL_FAILURE` function should be used instead of the `EXPECT_DEATH` gTest macro. +The `EXPECT_DEATH` gTest macro forks the process which slows down the test execution (especially with the ThreadSanitizer enabled) +and causes issues with running thread. The `IOX_EXPECT_FATAL_FAILURE` registers a temporary error handler and runs the provided +function in a separate thread. When the error handler is called `longjmp` is used to prevent the termination and instead ensures +to gracefully shutdown the thread. + +```cpp +#include "iceoryx_hoofs/testing/fatal_failure.hpp" +TEST(MyTest, valueOnNulloptIsFatal) { + iox::optional sut; + IOX_EXPECT_FATAL_FAILURE([&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} +``` + ## Open points ### Centralized error handling diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp index 477f040832..4b06951790 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp @@ -84,6 +84,12 @@ bool FATAL_FAILURE_TEST(const std::function& testFunction, /// @brief This function is used in cases a fatal failure is expected. The function only works in combination with the /// iceoryx error handler. +/// @code +/// TEST(MyTest, valueOnNulloptIsFatal) { +/// iox::optional sut; +/// IOX_EXPECT_FATAL_FAILURE([&] { sut.value(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED)); +/// } +/// @endcode /// @tparam[in] ErrorType The error type which is expected, e.g. 'iox::HoofsError' /// @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler /// @param[in] expectedError The error value which triggered the fatal failure @@ -102,6 +108,12 @@ bool IOX_EXPECT_FATAL_FAILURE(const std::function& testFunction, const E /// @brief This function is used in cases no fatal failure is expected but could potentially occur. The function only /// works in combination with the iceoryx error handler. +/// @code +/// TEST(MyTest, valueIsNotFatal) { +/// iox::optional sut{false}; +/// IOX_EXPECT_NO_FATAL_FAILURE([&] { sut.value(); }); +/// } +/// @endcode /// @tparam[in] ErrorType The error type which is expected if the test fails, e.g. 'iox::HoofsError' /// @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler /// @return true if no fatal failure occurs, false otherwise @@ -111,8 +123,8 @@ bool IOX_EXPECT_NO_FATAL_FAILURE(const std::function& testFunction) return !detail::FATAL_FAILURE_TEST( testFunction, [&](const auto error, const auto errorLevel) { - GTEST_FAIL() << "Expected no fatal failure but execution failed! Error code: " << error - << "; Error level: " << errorLevel; + GTEST_FAIL() << "Expected no fatal failure but execution failed! Error code: " + << static_cast(error) << "; Error level: " << static_cast(errorLevel); }, [&] {}); return false; From a6ffe88ff0ca6520646184d9e1b24d1748fe4b9c Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 22:07:33 +0100 Subject: [PATCH 07/15] iox-#1613 Move implementation to inl file --- .../iceoryx_hoofs/testing/fatal_failure.hpp | 69 ++---------- .../iceoryx_hoofs/testing/fatal_failure.inl | 100 ++++++++++++++++++ 2 files changed, 108 insertions(+), 61 deletions(-) create mode 100644 iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.inl diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp index 4b06951790..fd3afe1499 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp @@ -40,46 +40,9 @@ namespace detail /// @param[in] onNonFatalFailurePath This function will be executed on the non-failure path if no failure was detected /// @return true if a fatal failure occurs, false otherwise template -bool FATAL_FAILURE_TEST(const std::function& testFunction, - const std::function& onFatalFailurePath, - const std::function& onNonFatalFailurePath) -{ - std::atomic hasFatalFailure{false}; - auto th = std::thread([&] { - constexpr int JMP_VALUE{1}; - std::jmp_buf jmpBuffer; - - optional detectedError; - optional detectedErrorLevel; - - auto errorHandlerGuard = - iox::ErrorHandlerMock::setTemporaryErrorHandler([&](const auto error, const auto errorLevel) { - detectedError.emplace(error); - detectedErrorLevel.emplace(errorLevel); - - // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback - std::longjmp(&jmpBuffer[0], JMP_VALUE); - }); - - // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback - if (setjmp(&jmpBuffer[0]) == JMP_VALUE) - { - hasFatalFailure = true; - // using value directly is save since this path is only executed if the error handler was called and the - // respective values were set - onFatalFailurePath(detectedError.value(), detectedErrorLevel.value()); - return; - } - - testFunction(); - - onNonFatalFailurePath(); - }); - - th.join(); - - return hasFatalFailure.load(std::memory_order_relaxed); -} +bool IOX_FATAL_FAILURE_TEST(const std::function& testFunction, + const std::function& onFatalFailurePath, + const std::function& onNonFatalFailurePath); } // namespace detail /// @brief This function is used in cases a fatal failure is expected. The function only works in combination with the @@ -95,16 +58,7 @@ bool FATAL_FAILURE_TEST(const std::function& testFunction, /// @param[in] expectedError The error value which triggered the fatal failure /// @return true if a fatal failure occurs, false otherwise template -bool IOX_EXPECT_FATAL_FAILURE(const std::function& testFunction, const ErrorType expectedError) -{ - return detail::FATAL_FAILURE_TEST( - testFunction, - [&](const auto error, const auto errorLevel) { - EXPECT_THAT(error, ::testing::Eq(expectedError)); - EXPECT_THAT(errorLevel, ::testing::Eq(iox::ErrorLevel::FATAL)); - }, - [&] { GTEST_FAIL() << "Expected fatal failure but execution continued!"; }); -} +bool IOX_EXPECT_FATAL_FAILURE(const std::function& testFunction, const ErrorType expectedError); /// @brief This function is used in cases no fatal failure is expected but could potentially occur. The function only /// works in combination with the iceoryx error handler. @@ -118,19 +72,12 @@ bool IOX_EXPECT_FATAL_FAILURE(const std::function& testFunction, const E /// @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler /// @return true if no fatal failure occurs, false otherwise template -bool IOX_EXPECT_NO_FATAL_FAILURE(const std::function& testFunction) -{ - return !detail::FATAL_FAILURE_TEST( - testFunction, - [&](const auto error, const auto errorLevel) { - GTEST_FAIL() << "Expected no fatal failure but execution failed! Error code: " - << static_cast(error) << "; Error level: " << static_cast(errorLevel); - }, - [&] {}); - return false; -} +bool IOX_EXPECT_NO_FATAL_FAILURE(const std::function& testFunction); } // namespace testing } // namespace iox + +#include "iceoryx_hoofs/testing/fatal_failure.inl" + #endif // IOX_HOOFS_TESTING_FATAL_FAILURE_HPP diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.inl b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.inl new file mode 100644 index 0000000000..e37ed9b936 --- /dev/null +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.inl @@ -0,0 +1,100 @@ +// Copyright (c) 2023 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_HOOFS_TESTING_FATAL_FAILURE_INL +#define IOX_HOOFS_TESTING_FATAL_FAILURE_INL + +#include "iceoryx_hoofs/testing/fatal_failure.hpp" + +namespace iox +{ +namespace testing +{ +namespace detail +{ +template +inline bool +IOX_FATAL_FAILURE_TEST(const std::function& testFunction, + const std::function& onFatalFailurePath, + const std::function& onNonFatalFailurePath) +{ + std::atomic hasFatalFailure{false}; + auto th = std::thread([&] { + constexpr int JMP_VALUE{1}; + std::jmp_buf jmpBuffer; + + optional detectedError; + optional detectedErrorLevel; + + auto errorHandlerGuard = + iox::ErrorHandlerMock::setTemporaryErrorHandler([&](const auto error, const auto errorLevel) { + detectedError.emplace(error); + detectedErrorLevel.emplace(errorLevel); + + // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback + std::longjmp(&jmpBuffer[0], JMP_VALUE); + }); + + // NOLINTNEXTLINE(cert-err52-cpp) exception cannot be used and longjmp/setjmp is a working fallback + if (setjmp(&jmpBuffer[0]) == JMP_VALUE) + { + hasFatalFailure = true; + // using value directly is save since this path is only executed if the error handler was called and the + // respective values were set + onFatalFailurePath(detectedError.value(), detectedErrorLevel.value()); + return; + } + + testFunction(); + + onNonFatalFailurePath(); + }); + + th.join(); + + return hasFatalFailure.load(std::memory_order_relaxed); +} +} // namespace detail + +template +inline bool IOX_EXPECT_FATAL_FAILURE(const std::function& testFunction, const ErrorType expectedError) +{ + return detail::IOX_FATAL_FAILURE_TEST( + testFunction, + [&](const auto error, const auto errorLevel) { + EXPECT_THAT(error, ::testing::Eq(expectedError)); + EXPECT_THAT(errorLevel, ::testing::Eq(iox::ErrorLevel::FATAL)); + }, + [&] { GTEST_FAIL() << "Expected fatal failure but execution continued!"; }); +} + +template +inline bool IOX_EXPECT_NO_FATAL_FAILURE(const std::function& testFunction) +{ + return !detail::IOX_FATAL_FAILURE_TEST( + testFunction, + [&](const auto error, const auto errorLevel) { + GTEST_FAIL() << "Expected no fatal failure but execution failed! Error code: " + << static_cast(error) << "; Error level: " << static_cast(errorLevel); + }, + [&] { GTEST_SUCCEED() << "Non-fatal path taken!"; }); + return false; +} + +} // namespace testing +} // namespace iox + +#endif // IOX_HOOFS_TESTING_FATAL_FAILURE_INL From 276936b1332988a73f3b36c993d406eeaa6cea8b Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 22:39:06 +0100 Subject: [PATCH 08/15] iox-#1613 Add test for IOX_FATAL_FAILURE --- .../test/mocktests/test_fatal_failure.cpp | 73 +++++++++++++++++++ .../test/mocktests/test_hoofs_mock.cpp | 5 ++ 2 files changed, 78 insertions(+) create mode 100644 iceoryx_hoofs/test/mocktests/test_fatal_failure.cpp diff --git a/iceoryx_hoofs/test/mocktests/test_fatal_failure.cpp b/iceoryx_hoofs/test/mocktests/test_fatal_failure.cpp new file mode 100644 index 0000000000..1d7487e623 --- /dev/null +++ b/iceoryx_hoofs/test/mocktests/test_fatal_failure.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "iceoryx_hoofs/cxx/requires.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" + +#include "test.hpp" + +namespace +{ +using namespace ::testing; +using namespace ::iox::testing; + +TEST(FatalFailure, TriggeringFatalFailureIsDetectedAndDoesNotTerminate) +{ + ::testing::Test::RecordProperty("TEST_ID", "5463f1c9-eb30-4fd1-85ce-351f03c37fe0"); + + auto hasFatalFailure = detail::IOX_FATAL_FAILURE_TEST( + [&] { iox::cxx::Expects(false); }, + [&](const auto error, const auto errorLevel) { + EXPECT_THAT(error, Eq(iox::HoofsError::EXPECTS_ENSURES_FAILED)); + EXPECT_THAT(errorLevel, Eq(iox::ErrorLevel::FATAL)); + }, + [&] { GTEST_FAIL() << "This is the non-fatal path and should therefore not be called"; }); + + EXPECT_TRUE(hasFatalFailure); +} + +TEST(FatalFailure, ExpectingFatalFailureWhichDoesNotOccurIsDetected) +{ + ::testing::Test::RecordProperty("TEST_ID", "f6c1d4f2-cafe-45e3-bbb7-c1373b2e15a8"); + + auto hasFatalFailure = detail::IOX_FATAL_FAILURE_TEST( + [&] {}, + [&](const auto, const auto) { GTEST_FAIL() << "This is the fatal path and should therefore not be called"; }, + [&] { GTEST_SUCCEED() << "This is the non-fatal path and should be called"; }); + + EXPECT_FALSE(hasFatalFailure); +} + +TEST(FatalFailure, UsingExpectFatalFailureWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "26393210-9738-462f-9d35-dbd53fbae9d2"); + + auto hasFatalFailure = IOX_EXPECT_FATAL_FAILURE([&] { iox::cxx::Expects(false); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); + + EXPECT_TRUE(hasFatalFailure); +} + +TEST(FatalFailure, UsingExpectNoFatalFailureWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "80bf8050-bfaa-4482-b69c-d0c80699bd4b"); + + auto hasNoFatalFailure = IOX_EXPECT_NO_FATAL_FAILURE([&] {}); + + EXPECT_TRUE(hasNoFatalFailure); +} +} // namespace diff --git a/iceoryx_hoofs/test/mocktests/test_hoofs_mock.cpp b/iceoryx_hoofs/test/mocktests/test_hoofs_mock.cpp index 4335565a1f..2ec14def32 100644 --- a/iceoryx_hoofs/test/mocktests/test_hoofs_mock.cpp +++ b/iceoryx_hoofs/test/mocktests/test_hoofs_mock.cpp @@ -15,6 +15,8 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/testing/testing_logger.hpp" + #include "test.hpp" using ::testing::_; @@ -22,5 +24,8 @@ using ::testing::_; int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); + + iox::testing::TestingLogger::init(); + return RUN_ALL_TESTS(); } From 5469b8635aec91a08652950e128eb3b5f03eab6e Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 23:33:19 +0100 Subject: [PATCH 09/15] iox-#1613 Use IOX_EXPECT_FATAL_FAILURE in iceoryx_dust tests --- .../moduletests/test_cxx_forward_list.cpp | 84 ++++++++----------- .../test/moduletests/test_file_reader.cpp | 1 + 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/iceoryx_dust/test/moduletests/test_cxx_forward_list.cpp b/iceoryx_dust/test/moduletests/test_cxx_forward_list.cpp index 9292112930..596346fbfd 100644 --- a/iceoryx_dust/test/moduletests/test_cxx_forward_list.cpp +++ b/iceoryx_dust/test/moduletests/test_cxx_forward_list.cpp @@ -16,12 +16,15 @@ #include "iceoryx_dust/cxx/forward_list.hpp" #include "iceoryx_hoofs/cxx/attributes.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "test.hpp" namespace { using namespace ::testing; using namespace iox::cxx; +using namespace iox::testing; constexpr uint64_t TESTLISTCAPACITY{10U}; constexpr int64_t TEST_LIST_ELEMENT_DEFAULT_VALUE{-99L}; @@ -142,15 +145,6 @@ int64_t iteratorTraitReturnDoubleValue(IterType iter) IterValueType m_value = *iter; return (2 * m_value); // will only work for integer-convertible m_value types } - -// in context of EXPECT_DEATH tests, dummyFunc() shall help suppressing following warning : -// -Wunused-comparison -// reason: the warning is already addressed with the internal handling, which shall be tested here -bool dummyFunc(bool whatever) -{ - std::cerr << "Never get here - ever " << whatever << std::endl; - return whatever; -} } // namespace @@ -292,9 +286,7 @@ TEST_F(forward_list_test, FullWhenFilledWithMoreThanCapacityElements) } EXPECT_THAT(sut.full(), Eq(true)); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut.emplace_front(), ""); + IOX_EXPECT_FATAL_FAILURE([&] { sut.emplace_front(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, NotFullWhenFilledWithCapacityAndEraseOneElements) { @@ -666,9 +658,8 @@ TEST_F(forward_list_test, EmplaceAfterWithWrongListIterator) ++cnt; } - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut11.emplace_after(iterOfSut12, cnt), ""); + IOX_EXPECT_FATAL_FAILURE([&] { sut11.emplace_after(iterOfSut12, cnt); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, PushFrontConstCustomSuccessfullWhenSpaceAvailableLValue) @@ -1166,39 +1157,39 @@ TEST_F(forward_list_test, IteratorComparisonOfDifferentLists) auto iterSut1 = sut11.begin(); auto iterSut2 = sut12.begin(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), ""); + + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.before_begin(); iterSut2 = sut12.before_begin(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), ""); + + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.end(); iterSut2 = sut12.end(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 == iterSut2), ""); + + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 == iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.begin(); iterSut2 = sut12.begin(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), ""); + + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.before_begin(); iterSut2 = sut12.before_begin(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), ""); + + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); iterSut1 = sut11.end(); iterSut2 = sut12.end(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iterSut1 != iterSut2), ""); + + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iterSut1 != iterSut2); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } @@ -1988,9 +1979,7 @@ TEST_F(forward_list_test, invalidIteratorErase) auto iter = sut.begin(); sut.pop_front(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut.erase_after(iter), ""); + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase_after(iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, invalidIteratorIncrement) @@ -2005,9 +1994,7 @@ TEST_F(forward_list_test, invalidIteratorIncrement) auto iter = sut.cbegin(); sut.pop_front(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(++iter, ""); + IOX_EXPECT_FATAL_FAILURE([&] { ++iter; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, invalidIteratorComparison) @@ -2022,9 +2009,8 @@ TEST_F(forward_list_test, invalidIteratorComparison) auto iter = sut.cbegin(); sut.pop_front(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(sut.cbegin() == iter), ""); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut.cbegin() == iter); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, invalidIteratorComparisonUnequal) @@ -2039,9 +2025,8 @@ TEST_F(forward_list_test, invalidIteratorComparisonUnequal) sut.pop_front(); auto iter2 = sut.cbegin(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iter2 != iter), ""); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iter2 != iter); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, invalidIteratorDereferencing) @@ -2056,9 +2041,7 @@ TEST_F(forward_list_test, invalidIteratorDereferencing) auto iter = sut.cbegin(); sut.pop_front(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(sut.remove(*iter), ""); + IOX_EXPECT_FATAL_FAILURE([&] { sut.remove(*iter); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, invalidIteratorAddressOfOperator) @@ -2073,9 +2056,8 @@ TEST_F(forward_list_test, invalidIteratorAddressOfOperator) auto iter = sut.cbegin(); sut.pop_front(); - // @todo iox-#1613 remove EXPECT_DEATH - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) - EXPECT_DEATH(dummyFunc(iter->m_value == 12U), ""); + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(iter->m_value == 12U); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(forward_list_test, ListIsCopyableViaMemcpy) diff --git a/iceoryx_dust/test/moduletests/test_file_reader.cpp b/iceoryx_dust/test/moduletests/test_file_reader.cpp index 58e095d195..c0303aed42 100644 --- a/iceoryx_dust/test/moduletests/test_file_reader.cpp +++ b/iceoryx_dust/test/moduletests/test_file_reader.cpp @@ -160,6 +160,7 @@ TEST_F(FileReader_test, errorTerminateMode) std::set_terminate([]() { std::cout << "", std::abort(); }); // @todo iox-#1613 remove EXPECT_DEATH + // using IOX_EXPECT_FATAL_FAILURE currently causes issues with the leak sanitizer with this test // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-avoid-goto, cert-err33-c) EXPECT_DEATH( { From 6858160e45a140dbfee0cf4546518f6e14365225 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Tue, 7 Feb 2023 23:41:13 +0100 Subject: [PATCH 10/15] iox-#1613 Use IOX_EXPECT_FATAL_FAILURE in some iceoryx_posh tests --- iceoryx_posh/test/moduletests/test_capro_service.cpp | 6 +++++- .../test/moduletests/test_mepoo_chunk_header.cpp | 10 +++++++++- iceoryx_posh/test/moduletests/test_mepoo_config.cpp | 9 ++++++++- .../test/moduletests/test_popo_chunk_distributor.cpp | 10 ++++++---- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/iceoryx_posh/test/moduletests/test_capro_service.cpp b/iceoryx_posh/test/moduletests/test_capro_service.cpp index f82006025c..485daacd85 100644 --- a/iceoryx_posh/test/moduletests/test_capro_service.cpp +++ b/iceoryx_posh/test/moduletests/test_capro_service.cpp @@ -19,6 +19,8 @@ #include "iceoryx_dust/cxx/convert.hpp" #include "iceoryx_dust/cxx/serialization.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_hoofs/testing/mocks/logger_mock.hpp" #include "iceoryx_posh/capro/service_description.hpp" #include "iox/string.hpp" @@ -30,6 +32,7 @@ namespace { using namespace ::testing; +using namespace iox::testing; using namespace iox::capro; @@ -129,7 +132,8 @@ TEST_F(ServiceDescription_test, ClassHashSubsriptOperatorOutOfBoundsFails) testHash[2] = 3U; testHash[3] = 4U; - EXPECT_DEATH({ testHash[4] = 5U; }, ".*"); + + IOX_EXPECT_FATAL_FAILURE([&] { testHash[4] = 5U; }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } /// END CLASSHASH TESTS diff --git a/iceoryx_posh/test/moduletests/test_mepoo_chunk_header.cpp b/iceoryx_posh/test/moduletests/test_mepoo_chunk_header.cpp index 8d4eea040c..171fc71098 100644 --- a/iceoryx_posh/test/moduletests/test_mepoo_chunk_header.cpp +++ b/iceoryx_posh/test/moduletests/test_mepoo_chunk_header.cpp @@ -17,6 +17,8 @@ #include "iceoryx_dust/cxx/convert.hpp" #include "iceoryx_hoofs/cxx/type_traits.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_posh/internal/mepoo/mem_pool.hpp" #include "iceoryx_posh/internal/mepoo/memory_manager.hpp" #include "iceoryx_posh/mepoo/chunk_header.hpp" @@ -30,6 +32,7 @@ namespace { using namespace ::testing; using namespace iox::mepoo; +using namespace iox::testing; using UserPayloadOffset_t = ChunkHeader::UserPayloadOffset_t; @@ -367,7 +370,12 @@ TEST(ChunkHeader_test, ConstructorTerminatesWhenUserPayloadSizeExceedsChunkSize) ASSERT_FALSE(chunkSettingsResult.has_error()); auto& chunkSettings = chunkSettingsResult.value(); - EXPECT_DEATH({ ChunkHeader sut(CHUNK_SIZE, chunkSettings); }, ".*"); + IOX_EXPECT_FATAL_FAILURE( + [&] { + ChunkHeader sut(CHUNK_SIZE, chunkSettings); + ; + }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } // BEGIN PARAMETERIZED TESTS FOR CHUNK HEADER diff --git a/iceoryx_posh/test/moduletests/test_mepoo_config.cpp b/iceoryx_posh/test/moduletests/test_mepoo_config.cpp index 1a0f9fbb1f..f853a588d7 100644 --- a/iceoryx_posh/test/moduletests/test_mepoo_config.cpp +++ b/iceoryx_posh/test/moduletests/test_mepoo_config.cpp @@ -14,11 +14,14 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/testing/fatal_failure.hpp" +#include "iceoryx_posh/error_handling/error_handling.hpp" #include "iceoryx_posh/iceoryx_posh_types.hpp" #include "iceoryx_posh/mepoo/mepoo_config.hpp" #include "test.hpp" using namespace ::testing; +using namespace iox::testing; using namespace iox::mepoo; @@ -58,7 +61,11 @@ TEST_F(MePooConfig_Test, AddingMempoolWhenTheMemPoolConfigContainerIsFullReturns { sut.addMemPool({SIZE, CHUNK_COUNT}); } - EXPECT_DEATH({ sut.addMemPool({SIZE, CHUNK_COUNT}); }, ".*"); + IOX_EXPECT_FATAL_FAILURE( + [&] { + sut.addMemPool({SIZE, CHUNK_COUNT}); + }, + iox::PoshError::MEPOO__MAXIMUM_NUMBER_OF_MEMPOOLS_REACHED); } TEST_F(MePooConfig_Test, SetDefaultMethodAddsTheDefaultMemPoolConfigurationToTheMemPoolConfigContainer) diff --git a/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp b/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp index 8887434a57..d8293ff62a 100644 --- a/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp +++ b/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp @@ -16,7 +16,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "iceoryx_hoofs/cxx/variant_queue.hpp" +#include "iceoryx_hoofs/error_handling/error_handling.hpp" #include "iceoryx_hoofs/testing/barrier.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_hoofs/testing/watch_dog.hpp" #include "iceoryx_posh/internal/mepoo/shared_chunk.hpp" #include "iceoryx_posh/internal/popo/building_blocks/chunk_distributor.hpp" @@ -33,6 +35,7 @@ namespace { using namespace ::testing; +using namespace iox::testing; using namespace iox::popo; using namespace iox::cxx; using namespace iox::mepoo; @@ -126,17 +129,16 @@ constexpr std::chrono::milliseconds ChunkDistributor_test::BLOCKING_ template constexpr iox::units::Duration ChunkDistributor_test::DEADLOCK_TIMEOUT; -/// @todo iox-#898: this is broken on macOS and triggers the watchdog, even with 5 seconds timeout -#if !defined(__APPLE__) TYPED_TEST(ChunkDistributor_test, AddingNullptrQueueDoesNotWork) { ::testing::Test::RecordProperty("TEST_ID", "aa7eaa9e-c337-45dc-945a-d097b8916eaa"); auto sutData = this->getChunkDistributorData(); typename TestFixture::ChunkDistributor_t sut(sutData.get()); - EXPECT_DEATH(IOX_DISCARD_RESULT(sut.tryAddQueue(nullptr)), ".*"); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.tryAddQueue(nullptr); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } -#endif TYPED_TEST(ChunkDistributor_test, NewChunkDistributorHasNoQueues) { From bfc4ba9d806e4338b1e8d586f091b64068a6c0a2 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Wed, 8 Feb 2023 00:21:13 +0100 Subject: [PATCH 11/15] iox-#1613 Use IOX_EXPECT_FATAL_FAILURE in iceoryx_binding_c tests --- iceoryx_binding_c/source/c_runtime.cpp | 14 ++++---------- .../test/moduletests/test_publisher.cpp | 6 +++++- .../test/moduletests/test_runtime.cpp | 13 +++++++++++-- .../test/moduletests/test_service_discovery.cpp | 6 +++++- .../test/moduletests/test_subscriber.cpp | 9 ++++++--- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/iceoryx_binding_c/source/c_runtime.cpp b/iceoryx_binding_c/source/c_runtime.cpp index 4dd491b049..15f9b1551c 100644 --- a/iceoryx_binding_c/source/c_runtime.cpp +++ b/iceoryx_binding_c/source/c_runtime.cpp @@ -15,6 +15,7 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/cxx/requires.hpp" #include "iceoryx_posh/runtime/posh_runtime.hpp" using namespace iox; @@ -26,16 +27,9 @@ extern "C" { void iox_runtime_init(const char* const name) { - if (name == nullptr) - { - LogError() << "Runtime name is a nullptr!"; - std::terminate(); - } - else if (strnlen(name, iox::MAX_RUNTIME_NAME_LENGTH + 1) > MAX_RUNTIME_NAME_LENGTH) - { - LogError() << "Runtime name has more than 100 characters!"; - std::terminate(); - } + iox::cxx::Expects(name != nullptr && "Runtime name is a nullptr!"); + iox::cxx::Expects(strnlen(name, iox::MAX_RUNTIME_NAME_LENGTH + 1) <= MAX_RUNTIME_NAME_LENGTH + && "Runtime name has more than 100 characters!"); PoshRuntime::initRuntime(RuntimeName_t(iox::TruncateToCapacity, name)); } diff --git a/iceoryx_binding_c/test/moduletests/test_publisher.cpp b/iceoryx_binding_c/test/moduletests/test_publisher.cpp index 7e95439526..bd8c67d79e 100644 --- a/iceoryx_binding_c/test/moduletests/test_publisher.cpp +++ b/iceoryx_binding_c/test/moduletests/test_publisher.cpp @@ -15,8 +15,10 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_binding_c/error_handling/error_handling.hpp" #include "iceoryx_binding_c/internal/cpp2c_enum_translation.hpp" #include "iceoryx_binding_c/internal/cpp2c_publisher.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp" #include "iceoryx_posh/internal/popo/ports/publisher_port_roudi.hpp" #include "iceoryx_posh/internal/popo/ports/publisher_port_user.hpp" @@ -37,6 +39,7 @@ extern "C" { namespace { using namespace ::testing; +using namespace iox::testing; using namespace iox::capro; using namespace iox::cxx; using namespace iox::mepoo; @@ -137,7 +140,8 @@ TEST(iox_pub_test_DeathTest, initPublisherWithNotInitializedPublisherOptionsTerm iox_pub_options_t options; iox_pub_storage_t storage; - EXPECT_DEATH({ iox_pub_init(&storage, "a", "b", "c", &options); }, ".*"); + IOX_EXPECT_FATAL_FAILURE([&] { iox_pub_init(&storage, "a", "b", "c", &options); }, + iox::CBindingError::BINDING_C__PUBLISHER_OPTIONS_NOT_INITIALIZED); } TEST_F(iox_pub_test, initPublisherWithDefaultOptionsWorks) diff --git a/iceoryx_binding_c/test/moduletests/test_runtime.cpp b/iceoryx_binding_c/test/moduletests/test_runtime.cpp index 28e184a084..75ddc4b64d 100644 --- a/iceoryx_binding_c/test/moduletests/test_runtime.cpp +++ b/iceoryx_binding_c/test/moduletests/test_runtime.cpp @@ -18,6 +18,8 @@ extern "C" { #include "iceoryx_binding_c/runtime.h" } +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_posh/iceoryx_posh_types.hpp" #include "iceoryx_posh/testing/roudi_gtest.hpp" @@ -25,6 +27,7 @@ namespace { using namespace iox; using namespace iox::runtime; +using namespace iox::testing; class BindingC_Runtime_test : public RouDi_GTest { @@ -69,13 +72,19 @@ TEST_F(BindingC_Runtime_test, RuntimeNameLengthIsOutOfLimit) ::testing::Test::RecordProperty("TEST_ID", "8fd6735d-f331-4c9c-9a91-3f06d3856d15"); std::string tooLongName(iox::MAX_RUNTIME_NAME_LENGTH + 1, 's'); - EXPECT_DEATH({ iox_runtime_init(tooLongName.c_str()); }, ".*"); + IOX_EXPECT_FATAL_FAILURE( + [&] { + iox_runtime_init(tooLongName.c_str()); + ; + }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(BindingC_Runtime_test, RuntimeNameIsNullptr) { ::testing::Test::RecordProperty("TEST_ID", "eb1b76c9-5420-42a9-88b3-db2e36e332de"); - EXPECT_DEATH({ iox_runtime_init(nullptr); }, ".*"); + IOX_EXPECT_FATAL_FAILURE([&] { iox_runtime_init(nullptr); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } TEST_F(BindingC_Runtime_test, GetInstanceNameIsNullptr) diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp index c1d6d9719f..d4dbe63291 100644 --- a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -14,11 +14,14 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_posh/runtime/service_discovery.hpp" #include "iceoryx_posh/testing/roudi_gtest.hpp" using namespace iox; using namespace iox::runtime; +using namespace iox::testing; extern "C" { #include "iceoryx_binding_c/publisher.h" @@ -63,7 +66,8 @@ description_vector iox_service_discovery_test::searchResult; TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageTerminates) { ::testing::Test::RecordProperty("TEST_ID", "be551a9e-7dcf-406a-a74c-7dcb1ee16c30"); - EXPECT_DEATH({ iox_service_discovery_init(nullptr); }, ".*"); + IOX_EXPECT_FATAL_FAILURE([&] { iox_service_discovery_init(nullptr); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); } /// @note We test only if the arguments of iox_service_discovery_find_service are correctly passed to diff --git a/iceoryx_binding_c/test/moduletests/test_subscriber.cpp b/iceoryx_binding_c/test/moduletests/test_subscriber.cpp index e3b95c3fe6..55fc6abe9e 100644 --- a/iceoryx_binding_c/test/moduletests/test_subscriber.cpp +++ b/iceoryx_binding_c/test/moduletests/test_subscriber.cpp @@ -15,8 +15,10 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_binding_c/error_handling/error_handling.hpp" #include "iceoryx_binding_c/internal/cpp2c_enum_translation.hpp" #include "iceoryx_binding_c/internal/cpp2c_subscriber.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iceoryx_posh/internal/mepoo/memory_manager.hpp" #include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp" #include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_pusher.hpp" @@ -28,6 +30,7 @@ using namespace iox; using namespace iox::popo; +using namespace iox::testing; extern "C" { #include "iceoryx_binding_c/chunk.h" @@ -130,14 +133,14 @@ TEST_F(iox_sub_test, initSubscriberWithNullptrForStorageReturnsNullptr) EXPECT_EQ(iox_sub_init(nullptr, "all", "glory", "hypnotoad", &options), nullptr); } -// this crashes if the fixture is used, therefore a test without a fixture -TEST(iox_sub_test_DeathTest, initSubscriberWithNotInitializedPublisherOptionsTerminates) +TEST_F(iox_sub_test, initSubscriberWithNotInitializedSubscriberOptionsTerminates) { ::testing::Test::RecordProperty("TEST_ID", "6a33309e-fe21-45f6-815a-eebe0136c572"); iox_sub_options_t options; iox_sub_storage_t storage; - EXPECT_DEATH({ iox_sub_init(&storage, "a", "b", "c", &options); }, ".*"); + IOX_EXPECT_FATAL_FAILURE([&] { iox_sub_init(&storage, "a", "b", "c", &options); }, + iox::CBindingError::BINDING_C__SUBSCRIBER_OPTIONS_NOT_INITIALIZED); } TEST_F(iox_sub_test, initSubscriberWithDefaultOptionsWorks) From 949723916bd5c81c220baa8a0213c0fbb9ddc5a8 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Wed, 8 Feb 2023 00:25:07 +0100 Subject: [PATCH 12/15] iox-#1613 Remove dead code --- ...t_design_functional_interface_and_then.cpp | 2 +- ...st_design_functional_interface_or_else.cpp | 2 +- .../iceoryx_hoofs/testing/expect_no_death.hpp | 52 ------------------- 3 files changed, 2 insertions(+), 54 deletions(-) delete mode 100644 iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/expect_no_death.hpp diff --git a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_and_then.cpp b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_and_then.cpp index 4040c44671..a955fb7f5d 100644 --- a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_and_then.cpp +++ b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_and_then.cpp @@ -13,7 +13,7 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 -#include "iceoryx_hoofs/testing/expect_no_death.hpp" + #include "test_design_functional_interface_types.hpp" namespace diff --git a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_or_else.cpp b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_or_else.cpp index 9cc9e82c31..2ac934b394 100644 --- a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_or_else.cpp +++ b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_or_else.cpp @@ -13,7 +13,7 @@ // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 -#include "iceoryx_hoofs/testing/expect_no_death.hpp" + #include "test_design_functional_interface_types.hpp" namespace diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/expect_no_death.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/expect_no_death.hpp deleted file mode 100644 index a4171be4f4..0000000000 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/expect_no_death.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. -// -// 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. -// -// SPDX-License-Identifier: Apache-2.0 - -#ifndef IOX_HOOFS_TESTUTILS_EXPECT_NO_DEATH_HPP -#define IOX_HOOFS_TESTUTILS_EXPECT_NO_DEATH_HPP - -/// @brief gtest offers EXPECT_DEATH as test but no alternative to test the opposite, that -/// the program does not terminate. -/// EXPECT_NO_DEATH offers to verify that something does not terminate. -/// @param[in] callable The callable which should not lead to termination -#define EXPECT_NO_DEATH(callable) \ - EXPECT_EXIT( \ - { \ - callable(); \ - /* Use fprintf here instead of std::cerr. cerr can be rerouted to another stream which can lead to failing \ - * tests in combination with internal::CaptureStderr() for instance. */ \ - fprintf(stderr, "callable did not terminate"); \ - exit(0); \ - }, \ - ::testing::ExitedWithCode(0), \ - "callable did not terminate"); - -/// @brief gtest offers ASSERT_DEATH as test but no alternative to test the opposite, that -/// the program does not terminate. -/// ASSERT_NO_DEATH offers to verify that something does not terminate. -/// @param[in] callable The callable which should not lead to termination -#define ASSERT_NO_DEATH(callable) \ - ASSERT_EXIT( \ - { \ - callable(); \ - /* Use fprintf here instead of std::cerr. cerr can be rerouted to another stream which can lead to failing \ - * tests in combination with internal::CaptureStderr() for instance. */ \ - fprintf(stderr, "callable did not terminate"); \ - exit(0); \ - }, \ - ::testing::ExitedWithCode(0), \ - "callable did not terminate"); - -#endif From 5c3916fe26081fed92da3ee617a764f934417816 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Wed, 8 Feb 2023 00:48:29 +0100 Subject: [PATCH 13/15] iox-#1613 Fix macOS build --- iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp b/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp index d8293ff62a..f80166eada 100644 --- a/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp +++ b/iceoryx_posh/test/moduletests/test_popo_chunk_distributor.cpp @@ -135,8 +135,7 @@ TYPED_TEST(ChunkDistributor_test, AddingNullptrQueueDoesNotWork) auto sutData = this->getChunkDistributorData(); typename TestFixture::ChunkDistributor_t sut(sutData.get()); - - IOX_EXPECT_FATAL_FAILURE([&] { sut.tryAddQueue(nullptr); }, + IOX_EXPECT_FATAL_FAILURE([&] { IOX_DISCARD_RESULT(sut.tryAddQueue(nullptr)); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } From 38bbee149e39127cb111b07a05cdaa3d8cb3cc9f Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Thu, 9 Feb 2023 15:43:01 +0100 Subject: [PATCH 14/15] iox-#1613 Fix documentation --- .../testing/include/iceoryx_hoofs/testing/fatal_failure.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp index fd3afe1499..40782a086d 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/fatal_failure.hpp @@ -54,7 +54,7 @@ bool IOX_FATAL_FAILURE_TEST(const std::function& testFunction, /// } /// @endcode /// @tparam[in] ErrorType The error type which is expected, e.g. 'iox::HoofsError' -/// @param[in] testFunction This function will be executed as SUT and is not expected to call the error handler +/// @param[in] testFunction This function will be executed as SUT and is expected to call the error handler /// @param[in] expectedError The error value which triggered the fatal failure /// @return true if a fatal failure occurs, false otherwise template From efc7d2e1024715b85d58718e1c219c6e9cefa1f9 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Thu, 9 Feb 2023 15:45:37 +0100 Subject: [PATCH 15/15] iox-#1613 Use IOX_EXPECT_NO_FATAL_FAILURE in functional interface test --- .../test_design_functional_interface_expect.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp index 235e0b05bc..4a36c01752 100644 --- a/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp +++ b/iceoryx_hoofs/test/moduletests/test_design_functional_interface_expect.cpp @@ -39,15 +39,9 @@ using namespace iox::testing; template void ExpectDoesNotCallTerminateWhenObjectIsValid(const ExpectCall& callExpect) { - bool wasErrorHandlerCalled = false; SutType sut = FactoryType::createValidObject(); - { - auto handle = iox::ErrorHandlerMock::setTemporaryErrorHandler( - [&](auto, auto) { wasErrorHandlerCalled = true; }); - callExpect(sut); - } - EXPECT_FALSE(wasErrorHandlerCalled); + IOX_EXPECT_NO_FATAL_FAILURE([&] { callExpect(sut); }); } TYPED_TEST(FunctionalInterface_test, ExpectDoesNotCallTerminateWhenObjectIsValid_LValueCase) @@ -83,9 +77,8 @@ template void ExpectDoesCallTerminateWhenObjectIsInvalid(const ExpectCall& callExpect) { SutType sut = FactoryType::createInvalidObject(); - { - IOX_EXPECT_FATAL_FAILURE([&] { callExpect(sut); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); - } + + IOX_EXPECT_FATAL_FAILURE([&] { callExpect(sut); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); } TYPED_TEST(FunctionalInterface_test, ExpectDoesCallTerminateWhenObjectIsInvalid_LValueCase)