diff --git a/.clang-tidy b/.clang-tidy index 9b9e19ae27..f7f384c32d 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -5,6 +5,9 @@ # - hicpp-member-init (duplicate of cppcoreguidelines-pro-type-member-init) # - performance-move-const-arg (duplicate of hicpp-move-const-arg) # - bugprone-use-after-move (duplicate of hicpp-move-const-arg) +# +# NOTE: following checks are disabled because they are deprecated +# - cert-dcl21-cpp Checks: ' -*, @@ -32,6 +35,8 @@ hicpp-*, -readability-use-anyofallof, -readability-named-parameter, +-cert-dcl21-cpp + ' ### Temporarily disabled because massive API changes: diff --git a/doc/website/release-notes/iceoryx-unreleased.md b/doc/website/release-notes/iceoryx-unreleased.md index 1b38ff2d26..8bd35726d1 100644 --- a/doc/website/release-notes/iceoryx-unreleased.md +++ b/doc/website/release-notes/iceoryx-unreleased.md @@ -162,6 +162,7 @@ - Speed up posh tests [#1030](https://github.com/eclipse-iceoryx/iceoryx/issues/1030) - Roudi Environment independent from Googletest [#1533](https://github.com/eclipse-iceoryx/iceoryx/issues/1533) - Move test class for ctor and assignment operators to hoofs testing [#2041](https://github.com/eclipse-iceoryx/iceoryx/issues/2041) +- Refactor `FixdePositionContainer` and move to `dust` [#2044](https://github.com/eclipse-iceoryx/iceoryx/issues/2044) **Workflow:** diff --git a/iceoryx_dust/BUILD.bazel b/iceoryx_dust/BUILD.bazel index aa0600c91b..996761179e 100644 --- a/iceoryx_dust/BUILD.bazel +++ b/iceoryx_dust/BUILD.bazel @@ -33,10 +33,11 @@ cc_library( "source/**/*.cpp", "source/**/*.hpp", ]), - hdrs = glob(["include/**"] + glob(["vocabulary/**"])) + [ + hdrs = glob(["include/**"]) + glob(["container/**"]) + glob(["vocabulary/**"]) + [ ":iceoryx_dust_deployment_hpp", ], includes = [ + "container/include/", "include", "vocabulary/include/", ], diff --git a/iceoryx_dust/CMakeLists.txt b/iceoryx_dust/CMakeLists.txt index 1ee495e741..24dee2bb42 100644 --- a/iceoryx_dust/CMakeLists.txt +++ b/iceoryx_dust/CMakeLists.txt @@ -47,10 +47,12 @@ iox_add_library( PRIVATE_LIBS_LINUX ${CODE_COVERAGE_LIBS} PUBLIC_LIBS iceoryx_hoofs::iceoryx_hoofs BUILD_INTERFACE ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}/container/include ${PROJECT_SOURCE_DIR}/vocabulary/include ${CMAKE_BINARY_DIR}/generated/iceoryx/include INSTALL_INTERFACE include/${PREFIX} EXPORT_INCLUDE_DIRS include/ + container/include/ vocabulary/include/ FILES source/cli/arguments.cpp diff --git a/iceoryx_dust/README.md b/iceoryx_dust/README.md index da5f6d5494..a374afe728 100644 --- a/iceoryx_dust/README.md +++ b/iceoryx_dust/README.md @@ -12,6 +12,7 @@ grouped together in categories or namespace, depending on where or how they are |`forward_list` | Heap and exception free, relocatable implementation of `std::forward_list` | |`ObjectPool` | Container which stores raw objects without calling the ctor of the objects. | |`FileReader` | Wrapper for opening files and reading them. | +|`FixedPositionContainer` | A fixed-position container is similar to a list but is optimized for iterating over its elements without the back-and-forth jumping that can occur during iteration in a list. | |`MessageQueue` | Interface for Message Queues, see [ManPage mq_overview](https://www.man7.org/linux/man-pages/man7/mq_overview.7.html). | |`SignalWatcher` | Batteries included signal handling with polling and optional blocking wait for `SIGINT` and `SIGTERM`. | |`NamedPipe` | Shared memory based IPC channel. Mainly a `UnixDomainSocket` replacement on Windows. | diff --git a/iceoryx_dust/container/include/iox/detail/fixed_position_container.inl b/iceoryx_dust/container/include/iox/detail/fixed_position_container.inl new file mode 100644 index 0000000000..96beac3765 --- /dev/null +++ b/iceoryx_dust/container/include/iox/detail/fixed_position_container.inl @@ -0,0 +1,486 @@ +// Copyright (c) 2023 by Mathias Kraus . 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_DUST_CONTAINER_DETAIL_FIXED_POSITION_CONTAINER_INL +#define IOX_DUST_CONTAINER_DETAIL_FIXED_POSITION_CONTAINER_INL + +#include "iox/fixed_position_container.hpp" + +namespace iox +{ + +template +inline FixedPositionContainer::FixedPositionContainer() noexcept +{ + for (IndexType i = 0; i < CAPACITY;) + { + m_status[i] = SlotStatus::FREE; + + IndexType next = static_cast(i + 1U); + m_next[i] = next; + i = next; + } + m_next[Index::LAST] = Index::INVALID; + + m_begin_free = Index::FIRST; + m_begin_used = Index::INVALID; +} + +template +inline FixedPositionContainer::~FixedPositionContainer() noexcept +{ + for (IndexType i = 0; i < CAPACITY; ++i) + { + if (m_status[i] == SlotStatus::USED) + { + m_data[i].~T(); + } + } +} + +template +inline void FixedPositionContainer::clear() noexcept +{ + for (IndexType i = 0; i < CAPACITY;) + { + if (m_status[i] == SlotStatus::USED) + { + m_data[i].~T(); + } + + m_status[i] = SlotStatus::FREE; + + IndexType next = static_cast(i + 1U); + m_next[i] = next; + i = next; + } + m_next[Index::LAST] = Index::INVALID; + + m_size = 0; + m_begin_free = Index::FIRST; + m_begin_used = Index::INVALID; +} + +template +inline typename FixedPositionContainer::Iterator +FixedPositionContainer::insert(const T& data) noexcept +{ + // NOTE: if the implementation changes from simply forwarding to 'emplace' tests need to be written + return emplace(data); +} + +template +template +inline typename FixedPositionContainer::Iterator +FixedPositionContainer::emplace(Targs&&... args) noexcept +{ + if (full()) + { + return end(); + } + + // adding data to the container + // + // terminology + // + // slot + // ᵛ + // +---+ + // | 0 | <- index of current slot + // +---+ + // | S | <- current slot status + // +---+ + // | # | <- index of next slot with same status + // +---+ + // S: slot status; can be F(free) or U(used) + // #: index of next slot with same status; can be a number or I(Index::INVALID) if there are no further slots + // + // scenario 1 (begin_used is ahead of begin_free) + // before insertion + // begin_free and index to insert + // | + // | begin_used + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | F | F | U | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 1 | 5 | 3 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // after insertion + // begin_used + // | + // | begin_free + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | U | F | U | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 2 | 5 | 3 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // + // scenario 2 (begin_free is ahead of begin_used) + // before insertion + // begin_used + // | + // | begin_free and index to insert + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | U | F | F | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 3 | 2 | 5 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // after insertion + // begin_used + // | + // | begin_free + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | U | U | F | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 1 | 3 | 5 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + + const auto index = m_begin_free; + m_begin_free = m_next[m_begin_free]; + + new (&m_data[index]) T(std::forward(args)...); + m_status[index] = SlotStatus::USED; + ++m_size; + + if (index < m_begin_used) + { + m_next[index] = m_begin_used; + m_begin_used = index; + } + else + { + iox::cxx::EnsuresWithMsg(index != 0, "Corruption detected!"); + for (IndexType i = static_cast(index - 1U);; --i) + { + if (m_status[i] == SlotStatus::USED) + { + m_next[index] = m_next[i]; + m_next[i] = index; + break; + } + iox::cxx::EnsuresWithMsg(i != 0, "Corruption detected!"); + } + } + + return Iterator{index, *this}; +} + +template +inline typename FixedPositionContainer::Iterator +FixedPositionContainer::erase(const IndexType index) noexcept +{ + iox::cxx::ExpectsWithMsg(index <= Index::LAST, "Index out of range"); + + iox::cxx::EnsuresWithMsg(m_status[index] == SlotStatus::USED, + "Trying to erase from index pointing to an empty slot!"); + + const auto it = Iterator{m_next[index], *this}; + + // removing data from the container + // + // terminology + // + // slot + // ᵛ + // +---+ + // | 0 | <- index of current slot + // +---+ + // | S | <- current slot status + // +---+ + // | # | <- index of next slot with same status + // +---+ + // S: slot status; can be F(free) or U(used) + // #: index of next slot with same status; can be a number or I(Index::INVALID) if there are no further slots + // + // scenario 1 (remove at begin_used and begin_free is ahead of remove index) + // before removal + // begin_used and index to remove + // | + // | begin_free + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | U | F | U | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 2 | 5 | 3 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // after removal + // begin_free + // | + // | begin_used + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | F | F | U | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 1 | 5 | 3 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // + // scenario 2 (remove at begin_used and remove index is ahead of begin_free) + // before removal + // begin_free + // | + // | begin_used and index to remove + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | F | U | F | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 2 | 3 | 5 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // after removal + // begin_free + // | + // | begin_used + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | F | F | F | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 1 | 2 | 5 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // + // scenario 3 (remove ahead of begin_used and begin_free) + // before removal + // begin_free + // | + // | begin_used + // | | + // | | index to remove + // | | | + // | | | Index::INVALID + // ᵛ ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | F | U | F | U | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 2 | 3 | 5 | 4 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + // after removal + // begin_free + // | + // | begin_used + // | | Index::INVALID + // ᵛ ᵛ ᵛ + // +---+---+---+---+---+---+ - + + // | 0 | 1 | 2 | 3 | 4 | 5 | I | <- index + // +---+---+---+---+---+---+ - + + // | F | U | F | F | U | F | | <- status + // +---+---+---+---+---+---+ - + + // | 2 | 4 | 3 | 5 | I | I | | <- next index with same status + // +---+---+---+---+---+---+ - + + + m_data[index].~T(); + m_status[index] = SlotStatus::FREE; + --m_size; + + auto next_used = m_next[index]; + bool is_removed_from_used_list{false}; + bool is_added_to_free_list{false}; + + if (index == m_begin_used) + { + m_begin_used = next_used; + is_removed_from_used_list = true; + } + + if (index < m_begin_free) + { + m_next[index] = m_begin_free; + m_begin_free = index; + is_added_to_free_list = true; + } + + if (is_removed_from_used_list && is_added_to_free_list) + { + return it; + } + + iox::cxx::EnsuresWithMsg(index != 0, "Corruption detected! Index cannot be 0 at this location!"); + for (IndexType i = static_cast(index - 1U); !is_removed_from_used_list || !is_added_to_free_list; --i) + { + if (!is_removed_from_used_list && m_status[i] == SlotStatus::USED) + { + m_next[i] = next_used; + is_removed_from_used_list = true; + } + + if (!is_added_to_free_list && m_status[i] == SlotStatus::FREE) + { + m_next[index] = m_next[i]; + m_next[i] = index; + is_added_to_free_list = true; + } + + if (i == 0) + { + break; + } + } + iox::cxx::EnsuresWithMsg(is_removed_from_used_list && is_added_to_free_list, + "Corruption detected! The container is in a corrupt state!"); + + return it; +} + +template +inline typename FixedPositionContainer::Iterator +FixedPositionContainer::erase(const T* ptr) noexcept +{ + iox::cxx::ExpectsWithMsg(ptr != nullptr, "Pointer is a nullptr!"); + + const T* const firstElement = &m_data[0]; + iox::cxx::ExpectsWithMsg(ptr >= firstElement, "Pointer pointing out of the container!"); + + const auto index = static_cast(ptr - firstElement); + iox::cxx::ExpectsWithMsg(index <= Index::LAST, "Pointer pointing out of the container!"); + + iox::cxx::ExpectsWithMsg(ptr == &m_data[index], "Pointer is not aligned to an element in the container!"); + + // NOTE: if the implementation changes from simply forwarding to 'erase(IndexType)' tests need to be written + return erase(index); +} + +template +inline typename FixedPositionContainer::Iterator +FixedPositionContainer::erase(Iterator it) noexcept +{ + iox::cxx::ExpectsWithMsg(it.origins_from(*this), "Iterator belongs to a different container!"); + + // NOTE: if the implementation changes from simply forwarding to 'erase(IndexType)' tests need to be written + return erase(it.to_index()); +} + +template +inline typename FixedPositionContainer::ConstIterator +FixedPositionContainer::erase(ConstIterator it) noexcept +{ + iox::cxx::ExpectsWithMsg(it.origins_from(*this), "Iterator belongs to a different container!"); + + // NOTE: if the implementation changes from simply forwarding to 'erase(IndexType)' tests need to be written + return erase(it.to_index()); +} + +template +inline bool FixedPositionContainer::empty() const noexcept +{ + return m_size == 0; +} + +template +inline bool FixedPositionContainer::full() const noexcept +{ + return m_begin_free >= Index::INVALID; +} + +template +inline uint64_t FixedPositionContainer::size() const noexcept +{ + return m_size; +} + +template +inline constexpr uint64_t FixedPositionContainer::capacity() const noexcept +{ + return CAPACITY; +} + +template +inline typename FixedPositionContainer::Iterator +FixedPositionContainer::iter_from_index(const IndexType index) +{ + const auto it = static_cast(this)->iter_from_index(index); + return Iterator(it.to_index(), *this); +} + +template +inline typename FixedPositionContainer::ConstIterator +FixedPositionContainer::iter_from_index(const IndexType index) const +{ + if (index > Index::LAST || m_status[index] != SlotStatus::USED) + { + return end(); + } + return ConstIterator(index, *this); +} + +template +inline typename FixedPositionContainer::Iterator FixedPositionContainer::begin() noexcept +{ + return Iterator{m_begin_used, *this}; +} + +template +inline typename FixedPositionContainer::ConstIterator +FixedPositionContainer::begin() const noexcept +{ + return ConstIterator{m_begin_used, *this}; +} + +template +inline typename FixedPositionContainer::ConstIterator +FixedPositionContainer::cbegin() const noexcept +{ + return ConstIterator{m_begin_used, *this}; +} + +template +inline typename FixedPositionContainer::Iterator FixedPositionContainer::end() noexcept +{ + return Iterator{Index::INVALID, *this}; +} + +template +inline typename FixedPositionContainer::ConstIterator +FixedPositionContainer::end() const noexcept +{ + return ConstIterator{Index::INVALID, *this}; +} + +template +inline typename FixedPositionContainer::ConstIterator +FixedPositionContainer::cend() const noexcept +{ + return ConstIterator{Index::INVALID, *this}; +} +} // namespace iox + +#endif // IOX_DUST_CONTAINER_DETAIL_FIXED_POSITION_CONTAINER_INL diff --git a/iceoryx_dust/container/include/iox/fixed_position_container.hpp b/iceoryx_dust/container/include/iox/fixed_position_container.hpp new file mode 100644 index 0000000000..6f2c9c9491 --- /dev/null +++ b/iceoryx_dust/container/include/iox/fixed_position_container.hpp @@ -0,0 +1,333 @@ +// Copyright (c) 2023 by Mathias Kraus . 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_DUST_CONTAINER_FIXED_POSITION_CONTAINER_HPP +#define IOX_DUST_CONTAINER_FIXED_POSITION_CONTAINER_HPP + +#include "iceoryx_hoofs/cxx/requires.hpp" +#include "iox/algorithm.hpp" +#include "iox/uninitialized_array.hpp" + +#include +#include +#include + +namespace iox +{ +/// @brief Implementation of a fixed position container. The elements remain at fixed positions in the container, and +/// inserting or removing elements does not change their positions. The container is optimized for efficient iteration +/// over the elements by always having the 'next' index point to the closest element in memory, which prevents +/// unnecessary back-and-forth jumps. +/// @tparam T is the type the container holds +/// @tparam CAPACITY is the maximum number of elements the container can hold +template +class FixedPositionContainer final +{ + private: + enum class IterMutability + { + ITER_MUT, + ITER_CONST + }; + + template + class IteratorBase; + + public: + using ValueType = T; + using Reference = ValueType&; + using const_Reference = const ValueType&; + using Iterator = IteratorBase; + using ConstIterator = IteratorBase; + + using IndexType = BestFittingType_t; + + struct Index + { + static constexpr IndexType FIRST{0}; + static constexpr IndexType LAST{CAPACITY - 1}; + static constexpr IndexType INVALID{CAPACITY}; + }; + + FixedPositionContainer() noexcept; + ~FixedPositionContainer() noexcept; + + FixedPositionContainer(const FixedPositionContainer&) noexcept = delete; + FixedPositionContainer(FixedPositionContainer&&) noexcept = delete; + + FixedPositionContainer& operator=(const FixedPositionContainer&) noexcept = delete; + FixedPositionContainer& operator=(FixedPositionContainer&&) noexcept = delete; + + /// @brief Clears the container and calls the destructor on all contained elements + void clear() noexcept; + + /// @brief Inserts a new element at the next free position by copying the data into the container + /// @param[in] data the data to be inserted into the container + /// @return iterator pointing to the inserted element or 'end' iterator if the container was full and 'insert' + /// failed + Iterator insert(const T& data) noexcept; + + /// @brief Creates a new element at the next free position directly in-place by forwarding all arguments to the + /// constructor + /// @tparam Targs template parameter pack for the perfectly forwarded arguments + /// @param[in] args arguments which are used by the constructor of the newly emplaced element + /// @return iterator pointing to the emplaced element or 'end' iterator if the container was full and 'emplace' + /// failed + template + Iterator emplace(Targs&&... args) noexcept; + + /// @brief Erases the specified element from the container + /// @param[in] index an index to an element to erase + /// @return iterator to the element after the removed element or 'end' iterator if the last element was removed + /// @attention aborts if the index + /// - is out of range + /// - points to an empty slot + Iterator erase(const IndexType index) noexcept; + + /// @brief Erases the specified element from the container + /// @param[in] ptr a pointer to an element to erase + /// @return iterator to the element after the removed element or 'end' iterator if the last element was removed + /// @attention aborts if the pointer + /// - points outside of the container + /// - is not aligned to a slot in the container + /// - points to an empty slot + Iterator erase(const T* ptr) noexcept; + + /// @brief Erases the specified element from the container + /// @param[in] it an iterator to an element to erase + /// @return iterator to the element after the removed element or 'end' iterator if the last element was removed + /// @attention aborts if the iterator + /// - is invalid + /// - points to a different container + /// - points to an empty slot + Iterator erase(Iterator it) noexcept; + + /// @brief Erases the specified element from the container + /// @param[in] it an iterator to an element to erase + /// @return iterator to the element after the removed element or 'end' iterator if the last element was removed + /// @attention aborts if the iterator + /// - is invalid + /// - points to a different container + /// - points to an empty slot + ConstIterator erase(ConstIterator it) noexcept; + + /// @brief Checks if the container is empty + /// @return 'true' if the container is empty, 'false' otherwise + IOX_NO_DISCARD bool empty() const noexcept; + + /// @brief Checks if the container is full + /// @return 'true' if the container is full, 'false' otherwise + IOX_NO_DISCARD bool full() const noexcept; + + /// @brief Get the number of used slots in the container + /// @return the number of used slots + IOX_NO_DISCARD uint64_t size() const noexcept; + + /// @brief Get the capacity of the container + /// @return the number of available slots + IOX_NO_DISCARD constexpr uint64_t capacity() const noexcept; + + /// @brief Get the iterator to the element pointed to by the index + /// @param[in] index of the element the for the iterator + /// @return iterator pointing to the element at index or end iterator if index was out of bounds or index pointed to + /// an empty slot + IOX_NO_DISCARD Iterator iter_from_index(const IndexType index); + + /// @brief Get the const iterator to the element pointed to by the index + /// @param[in] index of the element the for the iterator + /// @return iterator pointing to the element at index or end iterator if index was out of bounds or index pointed to + /// an empty slot + IOX_NO_DISCARD ConstIterator iter_from_index(const IndexType index) const; + + /// @brief Get an iterator pointing to the beginning of the container + /// @return iterator pointing to the beginning of the container + IOX_NO_DISCARD Iterator begin() noexcept; + + /// @brief Get a const iterator pointing to the beginning of the container + /// @return const iterator pointing to the beginning of the container + IOX_NO_DISCARD ConstIterator begin() const noexcept; + + /// @brief Get a const iterator pointing to the beginning of the container + /// @return const iterator pointing to the beginning of the container + IOX_NO_DISCARD ConstIterator cbegin() const noexcept; + + /// @brief Get an iterator pointing to the end of the container + /// @return iterator pointing to the end of the container + IOX_NO_DISCARD Iterator end() noexcept; + + /// @brief Get a const iterator pointing to the end of the container + /// @return const iterator pointing to the end of the container + IOX_NO_DISCARD ConstIterator end() const noexcept; + + /// @brief Get a const iterator pointing to the end of the container + /// @return const iterator pointing to the end of the container + IOX_NO_DISCARD ConstIterator cend() const noexcept; + + private: + enum class SlotStatus : uint8_t + { + FREE, + USED, + }; + + template + class IteratorBase + { + public: + using Container = typename std::conditional::type; + using Value = typename std::conditional::type; + + friend class FixedPositionContainer; + + template + friend class IteratorBase; + + /// @brief Construct a const iterator from an iterator + // NOLINTJUSTIFICATION conversion from non const iterator to const iterator follows the STL behavior + // NOLINTNEXTLINE(hicpp-explicit-conversions) + IteratorBase(const IteratorBase& other) noexcept + : m_container(other.m_container.get()) + , m_index(other.m_index) + { + } + + /// @brief Assigns an iterator to a const iterator + IteratorBase& operator=(const IteratorBase& rhs) noexcept + { + m_container = rhs.m_container.get(); + m_index = rhs.m_index; + return *this; + } + + /// @brief Increment the iterator to point to the next element in the container + /// @return reference to the iterator after the increment + IteratorBase& operator++() noexcept + { + if (m_index <= Index::LAST) + { + m_index = m_container.get().m_next[m_index]; + } + return *this; + } + + /// @brief Increment the iterator to point to the next element in the container + /// @return iterator pointing to the value before the increment + IteratorBase operator++(int) noexcept + { + auto ret = *this; + ++(*this); + return ret; + } + + /// @brief Dereference the iterator to access the value it points to + /// @return reference to the value the iterator points to + /// @attention aborts if the iterator + /// - is an 'end' iterator + /// - the slot the iterator point to is not in use + IOX_NO_DISCARD Value& operator*() const + { + iox::cxx::EnsuresWithMsg(m_index <= Index::LAST, "Access with invalid index!"); + iox::cxx::EnsuresWithMsg(m_container.get().m_status[m_index] == SlotStatus::USED, + "Invalid access! Slot not in use!"); + return m_container.get().m_data[m_index]; + } + + /// @brief Access the value pointed to by the iterator using the arrow operator + /// @return pointer to the value pointed to by the iterator + /// @attention aborts if the iterator + /// - is an 'end' iterator + /// - the slot the iterator point to is not in use + IOX_NO_DISCARD Value* operator->() const + { + iox::cxx::EnsuresWithMsg(m_index <= Index::LAST, "Access with invalid index!"); + iox::cxx::EnsuresWithMsg(m_container.get().m_status[m_index] == SlotStatus::USED, + "Invalid access! Slot not in use!"); + return &m_container.get().m_data[m_index]; + } + + /// @brief Get the pointer to the element the iterator points to + /// @return pointer to the element the iterator points to + /// @attention aborts if the iterator + /// - is an 'end' iterator + /// - the slot the iterator point to is not in use + IOX_NO_DISCARD Value* to_ptr() const + { + iox::cxx::EnsuresWithMsg(m_index <= Index::LAST, "Access with invalid index!"); + iox::cxx::EnsuresWithMsg(m_container.get().m_status[m_index] == SlotStatus::USED, + "Invalid access! Slot not in use!"); + return &m_container.get().m_data[m_index]; + } + + /// @brief Get the index of the element the iterator points to + /// @return index of the element the iterator points to + /// @attention this can point out of the container in case of the 'end' iterator + IOX_NO_DISCARD IndexType to_index() const + { + return m_index; + } + + /// @brief Check if the iterator origins from the provided container + /// @param[in] container to determine the origin of the iterator + /// @return 'true' if the iterator origins from the provide container, 'false' otherwise + IOX_NO_DISCARD bool origins_from(const Container& container) const + { + return &m_container.get() == &container; + } + + /// @brief Compares iterators for equality + /// @return 'true' if iterators are the same, 'false' otherwise + template + IOX_NO_DISCARD bool operator==(const IteratorBase& rhs) const + { + return origins_from(rhs.m_container.get()) && (m_index == rhs.m_index); + } + + /// @brief Compares iterators for non-equality + /// @return 'true' if iterators are not the same, 'false' otherwise + template + IOX_NO_DISCARD bool operator!=(const IteratorBase& rhs) const + { + return !(*this == rhs); + } + + private: + IteratorBase(IndexType index, Container& container) noexcept + : m_container(container) + , m_index(index) + { + } + + private: + std::reference_wrapper m_container; + IndexType m_index; + }; + + private: + UninitializedArray m_data; + UninitializedArray m_status; + UninitializedArray m_next; + IndexType m_size{0}; + IndexType m_begin_free{Index::FIRST}; + IndexType m_begin_used{Index::INVALID}; +}; + +} // namespace iox + +#include "iox/detail/fixed_position_container.inl" + +#endif // IOX_DUST_CONTAINER_FIXED_POSITION_CONTAINER_HPP diff --git a/iceoryx_dust/test/CMakeLists.txt b/iceoryx_dust/test/CMakeLists.txt index 5eb6568de8..a58f1f5149 100644 --- a/iceoryx_dust/test/CMakeLists.txt +++ b/iceoryx_dust/test/CMakeLists.txt @@ -25,6 +25,7 @@ find_package(iceoryx_hoofs_testing REQUIRED) set(PROJECT_PREFIX "dust") file(GLOB_RECURSE MODULETESTS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/moduletests/*.cpp") +file(GLOB_RECURSE INTEGRATIONTESTS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/integrationtests/*.cpp") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_PREFIX}/test) @@ -44,4 +45,12 @@ iox_add_executable( TARGET ${PROJECT_PREFIX}_moduletests FILES ${MODULETESTS_SRC} ) +iox_add_executable( TARGET ${PROJECT_PREFIX}_integrationtests + INCLUDE_DIRECTORIES . + LIBS ${TEST_LINK_LIBS} + LIBS_LINUX acl dl rt + FILES ${INTEGRATIONTESTS_SRC} +) + target_compile_options(${PROJECT_PREFIX}_moduletests PRIVATE ${TEST_CXX_FLAGS}) +target_compile_options(${PROJECT_PREFIX}_integrationtests PRIVATE ${TEST_CXX_FLAGS}) diff --git a/iceoryx_dust/test/integrationtests/test_dust_integration.cpp b/iceoryx_dust/test/integrationtests/test_dust_integration.cpp new file mode 100644 index 0000000000..21fe025c35 --- /dev/null +++ b/iceoryx_dust/test/integrationtests/test_dust_integration.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved. +// Copyright (c) 2021 - 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/testing/testing_logger.hpp" + +#include "test.hpp" + +using namespace ::testing; + +int main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + + iox::testing::TestingLogger::init(); + + return RUN_ALL_TESTS(); +} diff --git a/iceoryx_dust/test/moduletests/test_container_fixed_position_container.cpp b/iceoryx_dust/test/moduletests/test_container_fixed_position_container.cpp new file mode 100644 index 0000000000..e66ddfd934 --- /dev/null +++ b/iceoryx_dust/test/moduletests/test_container_fixed_position_container.cpp @@ -0,0 +1,1708 @@ +// Copyright (c) 2023 by Mathias Kraus . 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 "iox/fixed_position_container.hpp" + +#include "iceoryx_hoofs/error_handling/error_handling.hpp" +#include "iceoryx_hoofs/testing/ctor_and_assignment_operator_test_class.hpp" +#include "iceoryx_hoofs/testing/fatal_failure.hpp" + +#include "test.hpp" + +namespace +{ +using namespace ::testing; +using namespace iox; +using namespace iox::testing; + +struct FixedPositionContainer_test : public Test +{ + using DataType = uint64_t; + static constexpr DataType CAPACITY{10}; + + using Sut = FixedPositionContainer; + + using ComplexType = CTorAndAssignmentOperatorTestClass; + using SutComplex = FixedPositionContainer; + + void SetUp() override + { + stats.reset(); + } + + void fillSut() + { + for (DataType i = 0; i < CAPACITY; ++i) + { + const auto it = sut.emplace(i); + ASSERT_THAT(it.to_index(), Eq(i)); + } + } + + void fillSutComplex() + { + fillComplex(sut_complex); + } + + void fillComplex(SutComplex& s) + { + for (DataType i = 0; i < CAPACITY; ++i) + { + const auto it = s.emplace(i); + ASSERT_THAT(it.to_index(), Eq(i)); + } + } + + Sut sut; + SutComplex sut_complex; + + ComplexType::Statistics& stats = ComplexType::stats; +}; + +TEST_F(FixedPositionContainer_test, ContainerIsNotMovable) +{ + ::testing::Test::RecordProperty("TEST_ID", "5c05f240-9822-427b-9eb5-69fd43f1ac28"); + EXPECT_FALSE(std::is_move_constructible::value); + EXPECT_FALSE(std::is_move_assignable::value); +} + +TEST_F(FixedPositionContainer_test, ContainerIsNotCopyable) +{ + ::testing::Test::RecordProperty("TEST_ID", "1b421af5-d014-4f9b-98ed-fbfdf5a9beb8"); + EXPECT_FALSE(std::is_copy_constructible::value); + EXPECT_FALSE(std::is_copy_assignable::value); +} + +TEST_F(FixedPositionContainer_test, Capacity) +{ + ::testing::Test::RecordProperty("TEST_ID", "17669b2f-d53b-4ac9-8190-b1c32f8ec4ba"); + EXPECT_THAT(sut.capacity(), Eq(CAPACITY)); +} + +// BEGIN test empty + +TEST_F(FixedPositionContainer_test, NewlyCreatedContainerIsEmpty) +{ + ::testing::Test::RecordProperty("TEST_ID", "c1fb0f86-8c48-4be5-aec6-8d269cdb258c"); + EXPECT_THAT(sut.empty(), Eq(true)); +} + +TEST_F(FixedPositionContainer_test, AddingOneElementResultsInNonEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "4d7d451b-a8e2-460c-b2c2-3b3ee58acfdb"); + + sut.emplace(0U); + EXPECT_THAT(sut.empty(), Eq(false)); +} + +TEST_F(FixedPositionContainer_test, AddingOneElementAndErasingAgainResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "97568d5d-89c0-40a6-8cfa-e12b40ca5115"); + + auto it = sut.emplace(0U); + sut.erase(it); + EXPECT_THAT(sut.empty(), Eq(true)); +} + +TEST_F(FixedPositionContainer_test, FillingUpResultsInNonEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "9d1ddef4-6578-4f3d-adf3-7e739f8f062e"); + + for (DataType i = 0; i < CAPACITY; ++i) + { + sut.emplace(i); + EXPECT_THAT(sut.empty(), Eq(false)); + } +} + +TEST_F(FixedPositionContainer_test, FillingUpAndErasingAgainResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "ec7a25aa-5c28-4ad1-87e0-4c7888915833"); + + fillSut(); + + for (Sut::IndexType i = 0; i < CAPACITY; ++i) + { + EXPECT_THAT(sut.empty(), Eq(false)); + sut.erase(i); + } + EXPECT_THAT(sut.empty(), Eq(true)); +} + +TEST_F(FixedPositionContainer_test, FillingUpAndErasingAgainInReverseOrderResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "e2373a83-d2b9-4305-a6cc-581338163686"); + + fillSut(); + + for (Sut::IndexType i = 0; i < CAPACITY; ++i) + { + EXPECT_THAT(sut.empty(), Eq(false)); + sut.erase(static_cast(Sut::Index::LAST - i)); + } + EXPECT_THAT(sut.empty(), Eq(true)); +} + +// END test empty + + +// BEGIN test full + +TEST_F(FixedPositionContainer_test, NewlyCreatedContainerIsNotFull) +{ + ::testing::Test::RecordProperty("TEST_ID", "69f3e641-3356-4c52-ae3e-fcca4811e329"); + EXPECT_THAT(sut.full(), Eq(false)); +} + +TEST_F(FixedPositionContainer_test, AddingOneElementResultsInNonFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "9752cfe6-e734-465c-8754-cdf8f6fdf13f"); + + sut.emplace(0U); + EXPECT_THAT(sut.full(), Eq(false)); +} + +TEST_F(FixedPositionContainer_test, FillingUpFinallyResultsInFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "4b8ab137-d69b-48a5-a34b-ba721383c186"); + + for (uint64_t i = 0; i < CAPACITY; ++i) + { + EXPECT_THAT(sut.full(), Eq(false)); + sut.emplace(i); + } + EXPECT_THAT(sut.full(), Eq(true)); +} + +TEST_F(FixedPositionContainer_test, FillingUpAndRemovingLastResultsInNonFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "5506f2cf-7de1-4b38-a91e-114dfdd5c55d"); + + fillSut(); + + sut.erase(Sut::Index::LAST); + EXPECT_THAT(sut.full(), Eq(false)); +} + +TEST_F(FixedPositionContainer_test, FillingUpAndRemovingFirstResultsInNonFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "05b52974-f536-454e-a66a-0c95f46b9361"); + + fillSut(); + + sut.erase(Sut::Index::FIRST); + EXPECT_THAT(sut.full(), Eq(false)); +} + +TEST_F(FixedPositionContainer_test, FillingUpAndRemovingMiddleResultsInNonFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "eaa7b1e9-73de-48a9-848d-b11fa62ee3f3"); + + fillSut(); + + sut.erase(Sut::Index::LAST / 2U); + EXPECT_THAT(sut.full(), Eq(false)); +} + +// END test full + + +// BEGIN test size + +TEST_F(FixedPositionContainer_test, NewlyCreatedContainerHasSizeZero) +{ + ::testing::Test::RecordProperty("TEST_ID", "b603f39c-54b9-4312-a3a8-d64590830a7d"); + EXPECT_THAT(sut.size(), Eq(0U)); +} + +TEST_F(FixedPositionContainer_test, AddingOneElementResultsInSizeOfOne) +{ + ::testing::Test::RecordProperty("TEST_ID", "07d884ab-c831-4d31-9d26-b852f528db48"); + + sut.emplace(0U); + EXPECT_THAT(sut.size(), Eq(1)); +} + +TEST_F(FixedPositionContainer_test, FillingUpFinallyResultsSizeOfCapacity) +{ + ::testing::Test::RecordProperty("TEST_ID", "418271b7-e96e-4a9e-bb65-30b26f9005ba"); + + for (uint64_t i = 0; i < CAPACITY; ++i) + { + EXPECT_THAT(sut.size(), Eq(i)); + sut.emplace(i); + } + EXPECT_THAT(sut.size(), Eq(CAPACITY)); +} + +TEST_F(FixedPositionContainer_test, FillingUpAndRemovinOneElementResultsInReducedSize) +{ + ::testing::Test::RecordProperty("TEST_ID", "4c655b05-dbf2-4657-bf30-ac0b07870da3"); + + fillSut(); + + sut.erase(Sut::Index::LAST / 2U); + EXPECT_THAT(sut.size(), Eq(CAPACITY - 1U)); +} + +// END test size + + +// BEGIN test emplace + +TEST_F(FixedPositionContainer_test, EmplaceOnEmptyContainerReturnsIteratorToTheAddedElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "70f31dcc-5395-4c3f-b75f-a44ecd8e385f"); + + constexpr DataType EXPECTED_VALUE{13}; + auto it = sut.emplace(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, + EmplaceWithComplexTypeOnEmptyConatainerReturnsIteratorToTheAddedElementAndCallsCorrectConstructor) +{ + ::testing::Test::RecordProperty("TEST_ID", "e62ad545-1f34-4edf-97ea-2a2aa5f2d15f"); + + constexpr DataType EXPECTED_VALUE{3113}; + auto it = sut_complex.emplace(EXPECTED_VALUE); + + EXPECT_THAT(stats.cTor, Eq(0)); + EXPECT_THAT(stats.customCTor, Eq(1)); + EXPECT_THAT(stats.dTor, Eq(0)); + EXPECT_THAT(stats.copyCTor, Eq(0)); + EXPECT_THAT(stats.moveCTor, Eq(0)); + + // this needs to be at the end to prevent this code changing 'stats' + ASSERT_THAT(it, Ne(sut_complex.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); + constexpr SutComplex::IndexType EXPECTED_INITIAL_INDEX{SutComplex::Index::FIRST}; + EXPECT_THAT(it.to_index(), Eq(EXPECTED_INITIAL_INDEX)); +} + +TEST_F(FixedPositionContainer_test, EmplaceOnFullContainerReturnsEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "a5a41bdd-e42d-4d4c-bdef-53ff1ae4e2a4"); + + constexpr DataType EXPECTED_VALUE{42}; + fillSut(); + + auto it = sut.emplace(EXPECTED_VALUE); + + EXPECT_THAT(it, Eq(sut.end())); +} + +TEST_F(FixedPositionContainer_test, EmplaceWithComplexTypeOnFullContainerReturnsEndIteratorAndDoesNotCallAnyConstructor) +{ + ::testing::Test::RecordProperty("TEST_ID", "af225467-f44b-4866-9714-a5508a226810"); + + constexpr DataType EXPECTED_VALUE{42}; + fillSutComplex(); + stats.reset(); + + auto it = sut_complex.emplace(EXPECTED_VALUE); + + EXPECT_THAT(stats.cTor, Eq(0)); + EXPECT_THAT(stats.customCTor, Eq(0)); + EXPECT_THAT(stats.dTor, Eq(0)); + EXPECT_THAT(stats.copyCTor, Eq(0)); + EXPECT_THAT(stats.moveCTor, Eq(0)); + + EXPECT_THAT(it, Eq(sut_complex.end())); +} + +TEST_F(FixedPositionContainer_test, EmplaceWithPartiallyFilledUpContainerWorksWhenFirstSlotIsFree) +{ + ::testing::Test::RecordProperty("TEST_ID", "38f1635e-e8f1-47af-8887-63511df58673"); + + fillSut(); + + const std::vector erased{1, 5}; + + for (const auto& i : erased) + { + sut.erase(i); + } + constexpr Sut::IndexType INDEX_TO_ERASE_FOR_INSERTION{Sut::Index::FIRST}; + sut.erase(INDEX_TO_ERASE_FOR_INSERTION); + + constexpr DataType EXPECTED_VALUE{0}; + auto it = sut.emplace(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); + EXPECT_THAT(it.to_index(), Eq(INDEX_TO_ERASE_FOR_INSERTION)); +} + +TEST_F(FixedPositionContainer_test, + EmplaceWithComplexTypeWithPartiallyFilledUpContainerWorksWhenFirstSlotIsFreeAndCallsCorrectConstructor) +{ + ::testing::Test::RecordProperty("TEST_ID", "a515c3a4-1dbf-47c5-aa2c-ed74615922e9"); + + fillSutComplex(); + + const std::vector erased{1, 5}; + + for (const auto& i : erased) + { + sut_complex.erase(i); + } + sut_complex.erase(SutComplex::Index::FIRST); + stats.reset(); + + constexpr DataType EXPECTED_VALUE{0}; + auto it = sut_complex.emplace(EXPECTED_VALUE); + + EXPECT_THAT(stats.cTor, Eq(0)); + EXPECT_THAT(stats.customCTor, Eq(1)); + EXPECT_THAT(stats.dTor, Eq(0)); + EXPECT_THAT(stats.copyCTor, Eq(0)); + EXPECT_THAT(stats.moveCTor, Eq(0)); + + // this needs to be at the end to prevent this code changing 'stats' + ASSERT_THAT(it, Ne(sut_complex.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); + + auto iter = sut_complex.begin(); + for (uint64_t i = 0; i < CAPACITY; ++i) + { + if (std::find(erased.begin(), erased.end(), i) == erased.end()) + { + ASSERT_THAT(iter, Ne(sut_complex.end())); + EXPECT_THAT(*iter, Eq(i)); + ++iter; + } + } + EXPECT_THAT(iter, Eq(sut_complex.end())); +} + +TEST_F(FixedPositionContainer_test, EmplaceWithPartiallyFilledUpContainerWorksWhenNotTheFirstSlotIsFree) +{ + ::testing::Test::RecordProperty("TEST_ID", "3caed564-010e-447d-bdb3-899fde04da88"); + + fillSut(); + + const std::vector erased{2, 5}; + + for (const auto& i : erased) + { + sut.erase(i); + } + sut.erase(1); + + constexpr DataType EXPECTED_VALUE{1}; + auto it = sut.emplace(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, + EmplaceWithComplexTypeWithPartiallyFilledUpContainerWorksWhenNotTheFirstSlotIsFreeAndCallsCorrectConstructor) +{ + ::testing::Test::RecordProperty("TEST_ID", "b9034d36-1197-49b9-b1f4-71e6678ad541"); + + fillSutComplex(); + + const std::vector erased{2, 5}; + + for (const auto& i : erased) + { + sut_complex.erase(i); + } + sut_complex.erase(1); + stats.reset(); + + constexpr DataType EXPECTED_VALUE{1}; + auto it = sut_complex.emplace(EXPECTED_VALUE); + + EXPECT_THAT(stats.cTor, Eq(0)); + EXPECT_THAT(stats.customCTor, Eq(1)); + EXPECT_THAT(stats.dTor, Eq(0)); + EXPECT_THAT(stats.copyCTor, Eq(0)); + EXPECT_THAT(stats.moveCTor, Eq(0)); + + // this needs to be at the end to prevent this code changing 'stats' + ASSERT_THAT(it, Ne(sut_complex.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); + + auto iter = sut_complex.begin(); + for (uint64_t i = 0; i < CAPACITY; ++i) + { + if (std::find(erased.begin(), erased.end(), i) == erased.end()) + { + ASSERT_THAT(iter, Ne(sut_complex.end())); + EXPECT_THAT(*iter, Eq(i)); + ++iter; + } + } + EXPECT_THAT(iter, Eq(sut_complex.end())); +} + +// END test emplace + + +// BEGIN test insert + +// NOTE: there is only two test for 'insert' since it simply forwards to 'emplace'; if this changes, more tests need to +// be written; a note at the implementation of 'insert' ensures that this will not be forgotten + +TEST_F(FixedPositionContainer_test, InsertReturnsIteratorToTheAddedElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "275ea2ee-bba9-40e5-a961-c9d3cc73792f"); + + constexpr DataType EXPECTED_VALUE{1331}; + auto it = sut.insert(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, InsertWithComplexTypeReturnsIteratorToTheAddedElementAndCallsCopyConstructor) +{ + ::testing::Test::RecordProperty("TEST_ID", "e537f31b-1a79-4d99-b6ba-e798a3f884eb"); + + constexpr DataType EXPECTED_VALUE{1313}; + const ComplexType value{EXPECTED_VALUE}; + stats.reset(); + + auto it = sut_complex.insert(value); + + EXPECT_THAT(stats.cTor, Eq(0)); + EXPECT_THAT(stats.customCTor, Eq(0)); + EXPECT_THAT(stats.dTor, Eq(0)); + EXPECT_THAT(stats.copyCTor, Eq(1)); + EXPECT_THAT(stats.moveCTor, Eq(0)); + + // this needs to be at the end to prevent this code changing 'stats' + ASSERT_THAT(it, Ne(sut_complex.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); +} + +// END test insert + + +// BEGIN test erase + +TEST_F(FixedPositionContainer_test, EraseOnContainerWithOneElementReturnsEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "bd5229c7-b7d0-4de0-89aa-9b58135249a3"); + + constexpr DataType EXPECTED_VALUE{73}; + const auto it_emplaced = sut_complex.emplace(EXPECTED_VALUE); + stats.reset(); + + auto it = sut_complex.erase(it_emplaced.to_index()); + + EXPECT_THAT(it, Eq(sut_complex.end())); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, EraseOnLastElementOnFullContainerReturnsEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "390504e4-fcae-46b2-8ad9-25d95cf3fed2"); + + fillSutComplex(); + stats.reset(); + + constexpr SutComplex::IndexType INDEX_TO_ERASE{SutComplex::Index::LAST}; + auto it = sut_complex.erase(INDEX_TO_ERASE); + + EXPECT_THAT(it, Eq(sut_complex.end())); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); +} + +TEST_F(FixedPositionContainer_test, EraseOnLastElementOnNonFullContainerReturnsEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "9eee74ce-2490-432a-9967-b24ad6f04121"); + + fillSutComplex(); + sut_complex.erase(SutComplex::Index::LAST); + stats.reset(); + + constexpr SutComplex::IndexType INDEX_TO_ERASE{SutComplex::Index::LAST - 1U}; + auto it = sut_complex.erase(INDEX_TO_ERASE); + + EXPECT_THAT(it, Eq(sut_complex.end())); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); +} + +TEST_F(FixedPositionContainer_test, EraseOnFirstElementOnFullContainerReturnsIteratorToNextElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "da8379dd-8d71-4a30-a698-3df1be6bfb80"); + + fillSutComplex(); + stats.reset(); + + constexpr SutComplex::IndexType INDEX_TO_ERASE{SutComplex::Index::FIRST}; + auto it = sut_complex.erase(INDEX_TO_ERASE); + + EXPECT_THAT(it.to_index(), Eq(INDEX_TO_ERASE + 1)); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); +} + +TEST_F(FixedPositionContainer_test, EraseOnArbitraryNonFirstOrLastElementReturnsIteratorToNextElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "22ab7321-94f3-4060-836d-f4400a63dabd"); + + fillSutComplex(); + stats.reset(); + + constexpr SutComplex::IndexType INDEX_TO_ERASE{SutComplex::Index::LAST / 2U}; + auto it = sut_complex.erase(INDEX_TO_ERASE); + + EXPECT_THAT(it.to_index(), Eq(INDEX_TO_ERASE + 1U)); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); +} + +TEST_F(FixedPositionContainer_test, EraseDoesNotCorruptTheContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "3116beab-53f7-41bd-9cfe-ff186bd8303d"); + + fillSut(); + + const std::vector erased{Sut::Index::FIRST, Sut::Index::LAST / 2, Sut::Index::LAST}; + + for (const auto& i : erased) + { + sut.erase(i); + } + + auto it = sut.begin(); + for (uint64_t i = 0; i < CAPACITY; ++i) + { + if (std::find(erased.begin(), erased.end(), i) == erased.end()) + { + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it, Eq(i)); + ++it; + } + } + EXPECT_THAT(it, Eq(sut.end())); +} + +TEST_F(FixedPositionContainer_test, EraseWithPointerWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "99f6b756-9f24-412f-865d-24d5b5032a22"); + + const std::vector erase{ + SutComplex::Index::FIRST, SutComplex::Index::LAST / 2U, SutComplex::Index::LAST}; + for (const auto INDEX_TO_ERASE : erase) + { + SCOPED_TRACE(std::string("Erase at index: ") + std::to_string(INDEX_TO_ERASE)); + + sut_complex.clear(); + fillSutComplex(); + + const auto it_erase = sut_complex.iter_from_index(INDEX_TO_ERASE); + stats.reset(); + + const auto it = sut_complex.erase(it_erase.to_ptr()); + + EXPECT_THAT(it.to_index(), Eq(INDEX_TO_ERASE + 1U)); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); + } +} + +TEST_F(FixedPositionContainer_test, EraseWithIteratorWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "a31f6a44-1183-475b-8eab-ff8c7b2158c1"); + + const std::vector erase{ + SutComplex::Index::FIRST, SutComplex::Index::LAST / 2U, SutComplex::Index::LAST}; + for (const auto INDEX_TO_ERASE : erase) + { + SCOPED_TRACE(std::string("Erase at index: ") + std::to_string(INDEX_TO_ERASE)); + + sut_complex.clear(); + fillSutComplex(); + + const SutComplex::Iterator it_erase = sut_complex.iter_from_index(INDEX_TO_ERASE); + stats.reset(); + + const auto it = sut_complex.erase(it_erase); + + EXPECT_THAT(it.to_index(), Eq(INDEX_TO_ERASE + 1U)); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); + } +} + +TEST_F(FixedPositionContainer_test, EraseWithConstIteratorWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "14b268f0-7e57-4719-b7af-19434f7ce994"); + + const std::vector erase{ + SutComplex::Index::FIRST, SutComplex::Index::LAST / 2U, SutComplex::Index::LAST}; + for (const auto INDEX_TO_ERASE : erase) + { + SCOPED_TRACE(std::string("Erase at index: ") + std::to_string(INDEX_TO_ERASE)); + + sut_complex.clear(); + fillSutComplex(); + + const SutComplex::ConstIterator it_erase = sut_complex.iter_from_index(INDEX_TO_ERASE); + stats.reset(); + + const auto it = sut_complex.erase(it_erase); + + EXPECT_THAT(it.to_index(), Eq(INDEX_TO_ERASE + 1U)); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(INDEX_TO_ERASE)); + } +} + +TEST_F(FixedPositionContainer_test, EraseOnEmptyContainerCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "943c9f2d-0ebd-4593-a721-884c952fef0d"); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(Sut::Index::FIRST); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseOnEmptySlotCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "4f03708a-4d26-4005-8e95-e710f14d1269"); + + fillSut(); + + constexpr SutComplex::IndexType INDEX_TO_ERASE{Sut::Index::LAST / 2U}; + sut.erase(INDEX_TO_ERASE); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(INDEX_TO_ERASE); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithOutOfBoundsIndexCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "f2d16f4a-c806-41c1-8051-b6eb0906994b"); + + fillSut(); + + constexpr SutComplex::IndexType INDEX_TO_ERASE{Sut::Index::LAST + 1U}; + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(INDEX_TO_ERASE); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithNullptrCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "3ad256c9-c87c-45f0-9c08-4206ae20a5ee"); + + fillSut(); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(nullptr); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithPointerPointingOutOfContainerCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "3bc4791c-deda-452b-91fa-3d52468c4d3e"); + + fillSut(); + + auto* ptr_first = sut.begin().to_ptr(); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(ptr_first - 1U); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(ptr_first + CAPACITY); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithUnalignedPointerCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "865a04c1-b5be-4436-8e7f-537d5861ac63"); + + fillSut(); + + auto* ptr_first = sut.begin().to_ptr(); + auto* ptr_unaligned = reinterpret_cast(reinterpret_cast(ptr_first) + 1U); + + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(ptr_unaligned); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithEndIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "61e3f1cb-2e27-423a-8744-6b326b633e94"); + + fillSut(); + + Sut::Iterator it = sut.end(); + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(it); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithIteratorNotOriginatingFromContainerCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "cebb7500-acc7-4726-812a-5d9a3b9239b5"); + + fillSut(); + + Sut sut2; + sut2.emplace(666U); + + Sut::Iterator it = sut2.begin(); + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(it); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithEndConstIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "504d8a43-f0b0-4ab2-aa93-9fb4d3ec42d8"); + + fillSut(); + + Sut::ConstIterator it = sut.end(); + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(it); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, EraseWithConstIteratorNotOriginatingFromContainerCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "aa5cb040-d2bb-4a19-ace2-4e04b8dcca41"); + + fillSut(); + + Sut sut2; + sut2.emplace(666U); + + Sut::ConstIterator it = sut2.begin(); + IOX_EXPECT_FATAL_FAILURE([&] { sut.erase(it); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +// END test erase + + +// BEGIN test dTor + +TEST_F(FixedPositionContainer_test, ContainerWithoutElementsDoesNotCallsDestructorOnElements) +{ + ::testing::Test::RecordProperty("TEST_ID", "1baeb9cf-49c0-41a6-97cc-49f15696d213"); + + { + SutComplex s; + } + + EXPECT_THAT(stats.dTor, Eq(0)); +} + +TEST_F(FixedPositionContainer_test, ContainerWithOneElementsCallsDestructorOnElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "99785123-36ab-4213-9093-09100345a49e"); + + constexpr DataType EXPECTED_VALUE{37}; + + { + SutComplex s; + s.emplace(EXPECTED_VALUE); + } + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, FilledUpContainerCallsDestructorOnAllEelements) +{ + ::testing::Test::RecordProperty("TEST_ID", "08119caf-ec5a-4a3e-a200-8bba3ab1112e"); + + { + SutComplex s; + fillComplex(s); + } + + EXPECT_THAT(stats.dTor, Eq(CAPACITY)); + ASSERT_THAT(stats.dTorOrder.size(), Eq(CAPACITY)); + + DataType expected_value{0}; + for (const auto value : stats.dTorOrder) + { + EXPECT_THAT(value, Eq(expected_value)); + ++expected_value; + } +} + +TEST_F(FixedPositionContainer_test, PartiallyFilledUpContainerCallsDestructorOnExistingEelements) +{ + ::testing::Test::RecordProperty("TEST_ID", "b0c6511b-e4bc-477c-bd19-05962b518e69"); + + const std::vector erased{ + SutComplex::Index::FIRST, SutComplex::Index::LAST / 2U, SutComplex::Index::LAST}; + + { + SutComplex s; + fillComplex(s); + + for (const auto& i : erased) + { + s.erase(i); + } + stats.reset(); + } + + EXPECT_THAT(stats.dTor, Eq(CAPACITY - erased.size())); + EXPECT_THAT(stats.dTorOrder.size(), Eq(CAPACITY - erased.size())); + + std::vector expected_values; + for (uint64_t i = 0; i < CAPACITY; ++i) + { + if (std::find(erased.begin(), erased.end(), i) == erased.end()) + { + expected_values.emplace_back(i); + } + } + + uint64_t i = 0; + for (const auto value : stats.dTorOrder) + { + EXPECT_THAT(value, Eq(expected_values[i])); + ++i; + } +} + +// END test dTor + + +// BEGIN test clear + +TEST_F(FixedPositionContainer_test, ClearOnNewlyCreatedContainerResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "2d214a69-541a-42fb-8842-2d187cb9199a"); + + sut.clear(); + + EXPECT_THAT(sut.empty(), Eq(true)); + EXPECT_THAT(sut.full(), Eq(false)); + EXPECT_THAT(sut.size(), Eq(0U)); +} + +TEST_F(FixedPositionContainer_test, ClearAfterAddingOneElementResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "8280433a-3ed7-4128-a624-88474a907412"); + + sut.emplace(42U); + + sut.clear(); + + EXPECT_THAT(sut.empty(), Eq(true)); + EXPECT_THAT(sut.full(), Eq(false)); + EXPECT_THAT(sut.size(), Eq(0U)); +} + +TEST_F(FixedPositionContainer_test, ClearAfterFillingUpResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "a7c5bdf1-3bd2-4fb6-986a-adc58068586a"); + + fillSut(); + + sut.clear(); + + EXPECT_THAT(sut.empty(), Eq(true)); + EXPECT_THAT(sut.full(), Eq(false)); + EXPECT_THAT(sut.size(), Eq(0U)); +} + +TEST_F(FixedPositionContainer_test, ClearOnPartiallyFillUpContainerResultsInEmptyContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "de927932-f774-45fb-9095-44942d5db894"); + + fillSut(); + + const std::vector erased{Sut::Index::FIRST, Sut::Index::LAST / 2U, Sut::Index::LAST}; + + for (const auto& i : erased) + { + sut.erase(i); + } + + sut.clear(); + + EXPECT_THAT(sut.empty(), Eq(true)); + EXPECT_THAT(sut.full(), Eq(false)); + EXPECT_THAT(sut.size(), Eq(0U)); +} + +TEST_F(FixedPositionContainer_test, ClearAfterAddingOneElementCallsDestructor) +{ + ::testing::Test::RecordProperty("TEST_ID", "fd776cc1-2c69-460d-b874-038908d066e6"); + + constexpr DataType EXPECTED_VALUE{73}; + sut_complex.emplace(EXPECTED_VALUE); + + sut_complex.clear(); + + EXPECT_THAT(stats.dTor, Eq(1)); + EXPECT_THAT(stats.classValue, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, ClearAfterFillingUpCallsDestructorOnAllElements) +{ + ::testing::Test::RecordProperty("TEST_ID", "3339d266-901a-4d08-8058-7a980ec9540c"); + + fillSutComplex(); + + sut_complex.clear(); + + EXPECT_THAT(stats.dTor, Eq(CAPACITY)); + EXPECT_THAT(stats.dTorOrder.size(), Eq(CAPACITY)); + + DataType expected_value{0}; + for (const auto value : stats.dTorOrder) + { + EXPECT_THAT(value, Eq(expected_value)); + ++expected_value; + } +} + +TEST_F(FixedPositionContainer_test, ClearAfterPartiallyFillingContainerUpCallsDestructorOnAllElements) +{ + ::testing::Test::RecordProperty("TEST_ID", "c84ef512-4ed1-41ce-9a82-3832495513e0"); + + fillSutComplex(); + + const std::vector erased{ + SutComplex::Index::FIRST, SutComplex::Index::LAST / 2U, SutComplex::Index::LAST}; + + for (const auto& i : erased) + { + sut_complex.erase(i); + } + stats.reset(); + + sut_complex.clear(); + + EXPECT_THAT(stats.dTor, Eq(CAPACITY - erased.size())); + EXPECT_THAT(stats.dTorOrder.size(), Eq(CAPACITY - erased.size())); + + std::vector expected_values; + for (uint64_t i = 0; i < CAPACITY; ++i) + { + if (std::find(erased.begin(), erased.end(), i) == erased.end()) + { + expected_values.emplace_back(i); + } + } + + uint64_t i = 0; + for (const auto value : stats.dTorOrder) + { + EXPECT_THAT(value, Eq(expected_values[i])); + ++i; + } +} + +// END test clear + + +// BEGIN test iter_from_index + +TEST_F(FixedPositionContainer_test, IterFromIndexWithIndexPointingToEmptySlotReturnsEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "9de27168-53e4-4da7-aec5-3fac1b3783a5"); + + EXPECT_THAT(sut.iter_from_index(Sut::Index::LAST / 2U), Eq(sut.end())); +} + +TEST_F(FixedPositionContainer_test, IterFromIndexWithOutOfBoundsIndexReturnsEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "ec6984df-b93e-48eb-9205-c8c921b6629a"); + + EXPECT_THAT(sut.iter_from_index(Sut::Index::LAST + 1U), Eq(sut.end())); +} + +TEST_F(FixedPositionContainer_test, IterFromIndexWithValidIndexReturnsIteratorTo) +{ + ::testing::Test::RecordProperty("TEST_ID", "24f3eb09-36db-4515-a0f7-1322e2277042"); + + fillSut(); + + EXPECT_THAT(sut.iter_from_index(Sut::Index::LAST / 2U).to_index(), Eq(Sut::Index::LAST / 2U)); +} + +// END test iter_from_index + + +// BEGIN test iterator + +TEST_F(FixedPositionContainer_test, NewlyCreatedContainerHasEndIteratorPointingToEnd) +{ + ::testing::Test::RecordProperty("TEST_ID", "2705fdcd-fdcb-41de-8d4f-4a2d708ea019"); + + auto it_from_end = sut.end(); + auto const_it_from_end = static_cast(sut).end(); + auto const_it_from_cend = sut.cend(); + + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + + EXPECT_THAT(it_from_end.to_index(), Eq(CAPACITY)); + EXPECT_THAT(const_it_from_end.to_index(), Eq(CAPACITY)); + EXPECT_THAT(const_it_from_cend.to_index(), Eq(CAPACITY)); +} + +TEST_F(FixedPositionContainer_test, NewlyCreatedContainerHasBeginIteratorPointingToEnd) +{ + ::testing::Test::RecordProperty("TEST_ID", "c147fffc-a373-484a-a802-e89fae60bfd9"); + + auto it_from_begin = sut.begin(); + auto const_it_from_begin = static_cast(sut).begin(); + auto const_it_from_cbegin = sut.cbegin(); + + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + EXPECT_TRUE((std::is_same::value)); + + EXPECT_THAT(it_from_begin.to_index(), Eq(CAPACITY)); + EXPECT_THAT(const_it_from_begin.to_index(), Eq(CAPACITY)); + EXPECT_THAT(const_it_from_cbegin.to_index(), Eq(CAPACITY)); +} + +TEST_F(FixedPositionContainer_test, BeginIteratorPointsToBeginOfContainerAfterInsertingTheFirstElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "10c6b680-4ba1-4927-8544-506cb73a460b"); + + constexpr DataType EXPECTED_VALUE{42}; + constexpr Sut::IndexType EXPECTED_INDEX{Sut::Index::FIRST}; + + sut.emplace(EXPECTED_VALUE); + + auto it_from_begin = sut.begin(); + auto const_it_from_begin = static_cast(sut).begin(); + auto const_it_from_cbegin = sut.cbegin(); + + EXPECT_THAT(it_from_begin.to_index(), Eq(EXPECTED_INDEX)); + EXPECT_THAT(const_it_from_begin.to_index(), Eq(EXPECTED_INDEX)); + EXPECT_THAT(const_it_from_cbegin.to_index(), Eq(EXPECTED_INDEX)); + + EXPECT_THAT(*it_from_begin, Eq(EXPECTED_VALUE)); + EXPECT_THAT(*const_it_from_begin, Eq(EXPECTED_VALUE)); + EXPECT_THAT(*const_it_from_cbegin, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, BeginIteratorPointsToFirstUsedSlotWhenSlotAtPositionZeroIsFree) +{ + ::testing::Test::RecordProperty("TEST_ID", "91a22130-d166-4919-a9a3-50b32d5ee7be"); + + constexpr DataType DUMMY_VALUE{0}; + constexpr DataType EXPECTED_VALUE{13}; + constexpr Sut::IndexType DUMMY_INDEX{0}; + constexpr Sut::IndexType EXPECTED_INDEX{1}; + + sut.emplace(DUMMY_VALUE); + sut.emplace(EXPECTED_VALUE); + sut.erase(DUMMY_INDEX); + + auto it_from_begin = sut.begin(); + auto const_it_from_begin = static_cast(sut).begin(); + auto const_it_from_cbegin = sut.cbegin(); + + EXPECT_THAT(it_from_begin.to_index(), Eq(EXPECTED_INDEX)); + EXPECT_THAT(const_it_from_begin.to_index(), Eq(EXPECTED_INDEX)); + EXPECT_THAT(const_it_from_cbegin.to_index(), Eq(EXPECTED_INDEX)); + + EXPECT_THAT(*it_from_begin, Eq(EXPECTED_VALUE)); + EXPECT_THAT(*const_it_from_begin, Eq(EXPECTED_VALUE)); + EXPECT_THAT(*const_it_from_cbegin, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, IteratorToConstIteratorViaConstructorWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "b4440ac7-d802-4cbc-912a-2829c86f0140"); + constexpr DataType EXPECTED_VALUE{13}; + + sut.emplace(0U); + auto it = sut.emplace(EXPECTED_VALUE); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); + + Sut::ConstIterator cit{it}; + EXPECT_THAT(*cit, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, IteratorToConstIteratorViaAssignmentWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "9543dde5-bcb0-4aad-afeb-86a9c0d289e2"); + constexpr DataType EXPECTED_VALUE{37}; + + sut.emplace(0U); + auto it = sut.emplace(EXPECTED_VALUE); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); + + Sut::ConstIterator cit{sut.end()}; + cit = it; + EXPECT_THAT(*cit, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, IteratorPreIncrementOnEndIteratorLeadsToEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "2e0fb1c7-744d-4d90-9524-56220ccc72bd"); + + auto it = sut.end(); + auto cit = sut.cend(); + + ++it; + ++cit; + + EXPECT_THAT(it, Eq(sut.end())); + EXPECT_THAT(cit, Eq(sut.cend())); +} + +TEST_F(FixedPositionContainer_test, IteratorPreIncrementLeadsToEndIteratorWhenContainerHasOneElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "e7e8a6f1-72ce-4a84-93d7-611be1e05445"); + + sut.emplace(123U); + + auto it = sut.begin(); + auto cit = sut.cbegin(); + + ++it; + ++cit; + + EXPECT_THAT(it, Eq(sut.end())); + EXPECT_THAT(cit, Eq(sut.cend())); +} + +TEST_F(FixedPositionContainer_test, IteratorPreIncrementLeadsToIteratorForNextElementWhenContainerHasRemainingElements) +{ + ::testing::Test::RecordProperty("TEST_ID", "e00b9667-25a8-453d-8819-8e39bce8b62c"); + + sut.emplace(456U); + sut.emplace(769U); + + auto it = sut.begin(); + auto cit = sut.cbegin(); + + ++it; + ++cit; + + EXPECT_THAT(it.to_index(), Eq(Sut::Index::FIRST + 1U)); + EXPECT_THAT(cit.to_index(), Eq(Sut::Index::FIRST + 1U)); +} + +TEST_F(FixedPositionContainer_test, IteratorPreIncrementAccessesAllElementsInFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "aefe17f5-d764-45f9-92af-c65bb6512ef6"); + + fillSut(); + + Sut::IndexType expected_index{Sut::Index::FIRST}; + auto it = sut.begin(); + do + { + EXPECT_THAT(it.to_index(), Eq(expected_index)); + ASSERT_THAT(expected_index, Le(Sut::Index::LAST)); + ++expected_index; + } while (++it != sut.end()); + --expected_index; + EXPECT_THAT(expected_index, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, IteratorPreIncrementAccessesAllElementsInPartiallyFilledUpContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "6dd67a93-636e-4f63-b2e2-b34777e16b56"); + + const std::vector erased{Sut::Index::FIRST, Sut::Index::LAST / 2U, Sut::Index::LAST}; + fillSut(); + for (const auto& i : erased) + { + sut.erase(i); + } + + Sut::IndexType expected_index{Sut::Index::FIRST + 1U}; + auto it = sut.begin(); + do + { + EXPECT_THAT(it.to_index(), Eq(expected_index)); + ASSERT_THAT(expected_index, Le(Sut::Index::LAST)); + ++expected_index; + if (std::find(erased.begin(), erased.end(), expected_index) != erased.end()) + { + ++expected_index; + } + } while (++it != sut.end()); + --expected_index; + EXPECT_THAT(expected_index, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, IteratorPostIncrementOnEndIteratorLeadsToEndIterator) +{ + ::testing::Test::RecordProperty("TEST_ID", "ba4dd951-fe2b-4ba1-bf88-4a2ef832c15f"); + + auto it = sut.end(); + auto cit = sut.cend(); + + auto old = it++; + auto cold = cit++; + + EXPECT_THAT(it, Eq(sut.end())); + EXPECT_THAT(cit, Eq(sut.cend())); + + EXPECT_THAT(old, Eq(sut.end())); + EXPECT_THAT(cold, Eq(sut.cend())); +} + +TEST_F(FixedPositionContainer_test, IteratorPostIncrementLeadsToEndIteratorWhenContainerHasOneElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "b214c524-f149-451b-b8ee-f1804f9f4884"); + + sut.emplace(123U); + + auto it = sut.begin(); + auto cit = sut.cbegin(); + const auto old_expected = it; + + auto old = it++; + auto cold = cit++; + + EXPECT_THAT(it, Eq(sut.end())); + EXPECT_THAT(cit, Eq(sut.cend())); + + EXPECT_THAT(old, Eq(old_expected)); + EXPECT_THAT(cold, Eq(old_expected)); +} + +TEST_F(FixedPositionContainer_test, IteratorPostIncrementLeadsToIteratorForNextElementWhenContainerHasRemainingElements) +{ + ::testing::Test::RecordProperty("TEST_ID", "f8a7be35-b61e-48cd-8375-b5654de688ab"); + + sut.emplace(456U); + sut.emplace(769U); + + auto it = sut.begin(); + auto cit = sut.cbegin(); + const auto old_expected = it; + + auto old = it++; + auto cold = cit++; + + EXPECT_THAT(it.to_index(), Eq(Sut::Index::FIRST + 1U)); + EXPECT_THAT(cit.to_index(), Eq(Sut::Index::FIRST + 1U)); + + EXPECT_THAT(old, Eq(old_expected)); + EXPECT_THAT(cold, Eq(old_expected)); +} + +TEST_F(FixedPositionContainer_test, IteratorPostIncrementAccessesAllElementsInFullContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "d298293b-924f-4aea-b408-2d463f4f9a5e"); + + fillSut(); + + Sut::IndexType expected_index{Sut::Index::FIRST}; + auto it = sut.begin(); + auto old = it; + do + { + old = it++; + EXPECT_THAT(old.to_index(), Eq(expected_index)); + ASSERT_THAT(expected_index, Le(Sut::Index::LAST)); + ++expected_index; + EXPECT_THAT(it.to_index(), Eq(expected_index)); + } while (it != sut.end()); + --expected_index; + EXPECT_THAT(expected_index, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, IteratorPostIncrementAccessesAllElementsInPartiallyFilledUpContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "b8ec4dc8-6f9a-4856-871e-f43385045cb3"); + + const std::vector erased{Sut::Index::FIRST, Sut::Index::LAST / 2U, Sut::Index::LAST}; + fillSut(); + for (const auto& i : erased) + { + sut.erase(i); + } + + Sut::IndexType expected_index{Sut::Index::FIRST + 1U}; + auto it = sut.begin(); + auto old = it; + do + { + old = it++; + EXPECT_THAT(old.to_index(), Eq(expected_index)); + ASSERT_THAT(expected_index, Le(Sut::Index::LAST)); + ++expected_index; + if (std::find(erased.begin(), erased.end(), expected_index) != erased.end()) + { + ++expected_index; + } + EXPECT_THAT(it.to_index(), Eq(expected_index)); + } while (it != sut.end()); + --expected_index; + EXPECT_THAT(expected_index, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, DereferencingNonConstItertorLeadsToNonConstReference) +{ + ::testing::Test::RecordProperty("TEST_ID", "e7b43292-94d1-44b2-8496-26d2abcf38f4"); + + auto is_non_const = std::is_same().operator*()), DataType&>::value; + EXPECT_TRUE(is_non_const); +} + +TEST_F(FixedPositionContainer_test, DereferencingConstIteratorLeadsToConstReference) +{ + ::testing::Test::RecordProperty("TEST_ID", "43330807-9ca8-4b82-a518-b7ab59dbf373"); + + auto is_const = std::is_same().operator*()), const DataType&>::value; + EXPECT_TRUE(is_const); +} + +TEST_F(FixedPositionContainer_test, DereferencingIteratorAccessesUnderlyingValue) +{ + ::testing::Test::RecordProperty("TEST_ID", "cd595860-74f8-4b54-890f-e20f4396d696"); + + constexpr DataType EXPECTED_VALUE{1111}; + auto it = sut.emplace(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it, Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, DereferencingIteratorOnFullContainerAccessesAllUnderlyingValues) +{ + ::testing::Test::RecordProperty("TEST_ID", "c4442b60-2265-480f-ac5c-07a7a4116fd6"); + + fillSut(); + + DataType expected_value{Sut::Index::FIRST}; + auto it = sut.begin(); + EXPECT_THAT(*it, Eq(expected_value)); + while (++it != sut.end()) + { + ++expected_value; + EXPECT_THAT(*it, Eq(expected_value)); + ASSERT_THAT(expected_value, Le(Sut::Index::LAST)); + } + EXPECT_THAT(expected_value, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, DereferencingEndIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "f2ccf248-97f8-4265-9bb4-9c8e7cb79e67"); + + IOX_EXPECT_FATAL_FAILURE([&] { auto _ IOX_MAYBE_UNUSED = *sut.end(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); + + IOX_EXPECT_FATAL_FAILURE([&] { auto _ IOX_MAYBE_UNUSED = *sut.cend(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, DereferencingInvalidIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "72c83dc7-ddc2-4c84-a64d-df9630ebc54b"); + + auto it = sut.emplace(135U); + sut.erase(it); + + IOX_EXPECT_FATAL_FAILURE([&] { auto _ IOX_MAYBE_UNUSED = *it; }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, ArrowOperatorOnNonConstItertorLeadsToNonConstPointer) +{ + ::testing::Test::RecordProperty("TEST_ID", "5ee50ed6-7c5a-494c-9832-26d8e3e62bfe"); + + auto is_non_const = std::is_same().operator->()), ComplexType*>::value; + EXPECT_TRUE(is_non_const); +} + +TEST_F(FixedPositionContainer_test, ArrowOperatorOnConstItertorLeadsToConstReference) +{ + ::testing::Test::RecordProperty("TEST_ID", "e09991fe-0358-40ad-8dad-af6f0940ec6d"); + + auto is_const = + std::is_same().operator->()), const ComplexType*>::value; + EXPECT_TRUE(is_const); +} + +TEST_F(FixedPositionContainer_test, ArrowOperatorOnIteratorAccessesUnderlyingValue) +{ + ::testing::Test::RecordProperty("TEST_ID", "9de3d4ff-30e9-43a3-b54e-3ed318c96654"); + + constexpr DataType EXPECTED_VALUE{2222}; + auto it = sut_complex.emplace(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut_complex.end())); + EXPECT_THAT(it->ref(), Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, ArrowOperatorOnIteratorOnFullContainerAccessesAllUnderlyingValues) +{ + ::testing::Test::RecordProperty("TEST_ID", "30060b3f-6952-4f5e-89ff-b28d4cc35a39"); + + fillSutComplex(); + + DataType expected_value{SutComplex::Index::FIRST}; + auto it = sut_complex.begin(); + EXPECT_THAT(it->ref(), Eq(expected_value)); + while (++it != sut_complex.end()) + { + ++expected_value; + EXPECT_THAT(it->ref(), Eq(expected_value)); + ASSERT_THAT(expected_value, Le(SutComplex::Index::LAST)); + } + EXPECT_THAT(expected_value, Eq(SutComplex::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, ArrowOperatorOnEndIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "74e20989-69dd-451c-9d6d-f65044a7d7b6"); + + IOX_EXPECT_FATAL_FAILURE([&] { sut_complex.end()->ref(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); + + IOX_EXPECT_FATAL_FAILURE([&] { sut_complex.cend()->ref(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, ArrowOperatorOnInvalidIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "282b090b-f66b-41a4-9a38-dbade26cb998"); + + auto it = sut_complex.emplace(135U); + sut_complex.erase(it); + + IOX_EXPECT_FATAL_FAILURE([&] { it->ref(); }, iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, ToPtrOnNonConstItertorLeadsToNonConstPointer) +{ + ::testing::Test::RecordProperty("TEST_ID", "a388be7f-759e-4946-85ea-7a47f06c553d"); + + auto is_non_const = std::is_same().to_ptr()), DataType*>::value; + EXPECT_TRUE(is_non_const); +} + +TEST_F(FixedPositionContainer_test, ToPtrOnConstIteratorLeadsToConstPointer) +{ + ::testing::Test::RecordProperty("TEST_ID", "ba7621dc-7e03-4185-a83a-f6d9e33df2e2"); + + auto is_const = std::is_same().to_ptr()), const DataType*>::value; + EXPECT_TRUE(is_const); +} + +TEST_F(FixedPositionContainer_test, ToPtrOnIteratorAccessesUnderlyingValue) +{ + ::testing::Test::RecordProperty("TEST_ID", "516dcc3c-fede-4894-9864-f06b0330828b"); + + constexpr DataType EXPECTED_VALUE{1111}; + auto it = sut.emplace(EXPECTED_VALUE); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(*it.to_ptr(), Eq(EXPECTED_VALUE)); +} + +TEST_F(FixedPositionContainer_test, ToPtrOnIteratorOnFullContainerAccessesAllUnderlyingValues) +{ + ::testing::Test::RecordProperty("TEST_ID", "ff640b88-e136-41dc-91cc-97c550fbafb1"); + + fillSut(); + + DataType expected_value{Sut::Index::FIRST}; + auto it = sut.begin(); + EXPECT_THAT(*it.to_ptr(), Eq(expected_value)); + while (++it != sut.end()) + { + ++expected_value; + EXPECT_THAT(*it.to_ptr(), Eq(expected_value)); + ASSERT_THAT(expected_value, Le(Sut::Index::LAST)); + } + EXPECT_THAT(expected_value, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, ToPtrOnEndIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "51b76d04-6c8c-486e-88c9-8b6b760c41d4"); + + IOX_EXPECT_FATAL_FAILURE([&] { auto _ IOX_MAYBE_UNUSED = sut.end().to_ptr(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); + + IOX_EXPECT_FATAL_FAILURE([&] { auto _ IOX_MAYBE_UNUSED = sut.cend().to_ptr(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, ToPtrOnInvalidIteratorCallsErrorHandler) +{ + ::testing::Test::RecordProperty("TEST_ID", "38df6619-65f3-4eee-aa4a-8c35aba13c1b"); + + auto it = sut.emplace(135U); + sut.erase(it); + + IOX_EXPECT_FATAL_FAILURE([&] { auto _ IOX_MAYBE_UNUSED = it.to_ptr(); }, + iox::HoofsError::EXPECTS_ENSURES_FAILED); +} + +TEST_F(FixedPositionContainer_test, ToIndexOnIteratorReturnsCorrespondingIndex) +{ + ::testing::Test::RecordProperty("TEST_ID", "b7d820cd-56f2-4165-a85c-c400f03f0e06"); + + auto it = sut.emplace(159U); + + ASSERT_THAT(it, Ne(sut.end())); + EXPECT_THAT(it.to_index(), Eq(Sut::Index::FIRST)); +} + +TEST_F(FixedPositionContainer_test, ToIndexOnIteratorOnFullContainerReturnsAllCorrespondingIndices) +{ + ::testing::Test::RecordProperty("TEST_ID", "1ba5a0cb-66fe-4ece-8ffa-d55532d9be1c"); + + fillSut(); + + Sut::IndexType expected_index{Sut::Index::FIRST}; + auto it = sut.begin(); + EXPECT_THAT(it.to_index(), Eq(expected_index)); + while (++it != sut.end()) + { + ++expected_index; + EXPECT_THAT(it.to_index(), Eq(expected_index)); + ASSERT_THAT(expected_index, Le(Sut::Index::LAST)); + } + EXPECT_THAT(expected_index, Eq(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, ToIndexOnEndIteratorReturnsIndexBeyondLast) +{ + ::testing::Test::RecordProperty("TEST_ID", "4fe6b23f-aae8-41d4-b5ad-ce8385709061"); + + EXPECT_THAT(sut.end().to_index(), Gt(Sut::Index::LAST)); + EXPECT_THAT(sut.cend().to_index(), Gt(Sut::Index::LAST)); +} + +TEST_F(FixedPositionContainer_test, ToIndexOnInvalidIteratorReturnsStoredIndex) +{ + ::testing::Test::RecordProperty("TEST_ID", "3027523b-85fb-49eb-b0ef-b3d6f3cad5a7"); + + sut.emplace(531U); + auto it = sut.emplace(369U); + sut.erase(it); + + EXPECT_THAT(it.to_index(), Eq(Sut::Index::FIRST + 1U)); +} + +TEST_F(FixedPositionContainer_test, OriginsFromReturnsTrueWhenIteratorOriginsFromContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "3d462756-8cc8-42be-af02-83361ec527e0"); + + auto it = sut.emplace(121U); + + EXPECT_TRUE(it.origins_from(sut)); +} + +TEST_F(FixedPositionContainer_test, OriginsFromReturnsFalseWhenIteratorDoesNotOriginFromContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "cb400b16-b705-4512-8701-5cf62cf82534"); + + auto it = sut.emplace(213U); + Sut sut2; + + EXPECT_FALSE(it.origins_from(sut2)); +} + +TEST_F(FixedPositionContainer_test, CompareForEqualityReturnsTrueWhenIteratorPointToTheSameElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "846b2153-ebcd-4810-b86a-56ba36b141e6"); + + auto it1 = sut.emplace(987U); + auto it2 = sut.begin(); + + EXPECT_TRUE(it1 == it2); +} + +TEST_F(FixedPositionContainer_test, CompareForEqualityReturnsFalseWhenIteratorDoesNotPointToTheSameElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "2801a787-bda2-4a6d-8cea-88ca7a59c075"); + + auto it1 = sut.emplace(963U); + auto it2 = sut.emplace(963U); + + EXPECT_FALSE(it1 == it2); +} + +TEST_F(FixedPositionContainer_test, CompareForEqualityReturnsFalseWhenIteratorDoesNotOriginFromTheSameContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "8f4547de-5acc-458f-9cfc-95e472fa3732"); + + auto it1 = sut.emplace(842U); + Sut sut2; + auto it2 = sut2.emplace(842U); + + EXPECT_FALSE(it1 == it2); +} + +TEST_F(FixedPositionContainer_test, CompareForNonEqualityReturnsFalseWhenIteratorPointToTheSameElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "4301a29c-b90c-4dba-9431-1d668e2de2f5"); + + auto it1 = sut.emplace(987U); + auto it2 = sut.begin(); + + EXPECT_FALSE(it1 != it2); +} + +TEST_F(FixedPositionContainer_test, CompareForNonEqualityReturnsTrueWhenIteratorDoesNotPointToTheSameElement) +{ + ::testing::Test::RecordProperty("TEST_ID", "a76db7ad-0d4e-4d15-92c8-9a5b53d431e9"); + + auto it1 = sut.emplace(963U); + auto it2 = sut.emplace(963U); + + EXPECT_TRUE(it1 != it2); +} + +TEST_F(FixedPositionContainer_test, CompareForNonEqualityReturnsTrueWhenIteratorDoesNotOriginFromTheSameContainer) +{ + ::testing::Test::RecordProperty("TEST_ID", "03d3bc8e-03da-4b1c-ac25-8606e132f7ac"); + + auto it1 = sut.emplace(842U); + Sut sut2; + auto it2 = sut2.emplace(842U); + + EXPECT_TRUE(it1 != it2); +} + +TEST_F(FixedPositionContainer_test, IteratorDestructorDoesNotDestroyObjectItPointsTo) +{ + ::testing::Test::RecordProperty("TEST_ID", "a52e9d6e-c763-4953-95c2-1f05d605d180"); + + fillSutComplex(); + + { + auto it IOX_MAYBE_UNUSED = sut_complex.begin(); + auto cit IOX_MAYBE_UNUSED = sut_complex.cbegin(); + } + + EXPECT_THAT(stats.dTor, Eq(0)); +} + +// END test iterator + +} // namespace diff --git a/iceoryx_dust/test/moduletests/test_dust_modules.cpp b/iceoryx_dust/test/moduletests/test_dust_modules.cpp index dbabebf672..1091df15b9 100644 --- a/iceoryx_dust/test/moduletests/test_dust_modules.cpp +++ b/iceoryx_dust/test/moduletests/test_dust_modules.cpp @@ -22,18 +22,11 @@ using namespace ::testing; using ::testing::_; -// global argc and argv needed by the argv_inspection test -int g_argc; -char** g_argv; - int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); iox::testing::TestingLogger::init(); - g_argc = argc; - g_argv = argv; - return RUN_ALL_TESTS(); } diff --git a/iceoryx_dust/vocabulary/include/iox/detail/span_iterator.hpp b/iceoryx_dust/vocabulary/include/iox/detail/span_iterator.hpp index af4e4f0260..356ae71e42 100644 --- a/iceoryx_dust/vocabulary/include/iox/detail/span_iterator.hpp +++ b/iceoryx_dust/vocabulary/include/iox/detail/span_iterator.hpp @@ -80,8 +80,6 @@ class span_iterator final return *this; } - // Rule DCL21-CPP is deprecated - // NOLINTNEXTLINE(cert-dcl21-cpp) constexpr span_iterator operator++(int) noexcept { span_iterator ret = *this; @@ -97,8 +95,6 @@ class span_iterator final return *this; } - // Rule DCL21-CPP is deprecated - // NOLINTNEXTLINE(cert-dcl21-cpp) constexpr span_iterator operator--(int) noexcept { span_iterator ret = *this; diff --git a/iceoryx_hoofs/design/include/iox/detail/newtype/decrementable.hpp b/iceoryx_hoofs/design/include/iox/detail/newtype/decrementable.hpp index dfa2226957..6e24112231 100644 --- a/iceoryx_hoofs/design/include/iox/detail/newtype/decrementable.hpp +++ b/iceoryx_hoofs/design/include/iox/detail/newtype/decrementable.hpp @@ -36,8 +36,6 @@ struct Decrementable return Derived{--internal::newTypeRefAccessor(self)}; } - // Rule DCL21-CPP is deprecated - // NOLINTNEXTLINE(cert-dcl21-cpp) friend Derived operator--(T& self, int) noexcept { return Derived{internal::newTypeRefAccessor(self)--}; diff --git a/iceoryx_hoofs/design/include/iox/detail/newtype/incrementable.hpp b/iceoryx_hoofs/design/include/iox/detail/newtype/incrementable.hpp index b583c8dee6..c618effc6c 100644 --- a/iceoryx_hoofs/design/include/iox/detail/newtype/incrementable.hpp +++ b/iceoryx_hoofs/design/include/iox/detail/newtype/incrementable.hpp @@ -36,8 +36,6 @@ struct Incrementable return Derived{++internal::newTypeRefAccessor(self)}; } - // Rule DCL21-CPP is deprecated - // NOLINTNEXTLINE(cert-dcl21-cpp) friend Derived operator++(T& self, int) noexcept { return Derived{internal::newTypeRefAccessor(self)++}; diff --git a/iceoryx_hoofs/test/moduletests/test_hoofs_modules.cpp b/iceoryx_hoofs/test/moduletests/test_hoofs_modules.cpp index e02d6a1978..79d6142262 100644 --- a/iceoryx_hoofs/test/moduletests/test_hoofs_modules.cpp +++ b/iceoryx_hoofs/test/moduletests/test_hoofs_modules.cpp @@ -24,10 +24,6 @@ using namespace ::testing; using ::testing::_; -// global argc and argv needed by the argv_inspection test -int g_argc; -char** g_argv; - int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); @@ -37,8 +33,5 @@ int main(int argc, char* argv[]) iox::testing::ErrorHandler handler; iox::er::ErrorHandler::set(handler); - g_argc = argc; - g_argv = argv; - return RUN_ALL_TESTS(); } diff --git a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/ctor_and_assignment_operator_test_class.hpp b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/ctor_and_assignment_operator_test_class.hpp index 9be1afd804..d1388fcbed 100644 --- a/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/ctor_and_assignment_operator_test_class.hpp +++ b/iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/ctor_and_assignment_operator_test_class.hpp @@ -92,6 +92,16 @@ class CTorAndAssignmentOperatorTestClass stats.dTorOrder.emplace_back(value); } + T& ref() + { + return value; + } + + const T& ref() const + { + return value; + } + struct Statistics { uint64_t cTor{0}; diff --git a/iceoryx_meta/tests.cmake b/iceoryx_meta/tests.cmake index 8ba9982283..c801e6a998 100644 --- a/iceoryx_meta/tests.cmake +++ b/iceoryx_meta/tests.cmake @@ -19,7 +19,7 @@ if (BUILD_TEST) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/googletest ${CMAKE_BINARY_DIR}/dependencies/googletest/prebuild) ### create component list - set(COMPONENTS "hoofs" "posh") + set(COMPONENTS "hoofs" "dust" "posh") ### possible place for more extensions if (BINDING_C)