diff --git a/iceoryx_platform/test/moduletests/test_platform_atomic.cpp b/iceoryx_platform/test/moduletests/test_platform_atomic.cpp new file mode 100644 index 0000000000..722abd8d61 --- /dev/null +++ b/iceoryx_platform/test/moduletests/test_platform_atomic.cpp @@ -0,0 +1,541 @@ +// Copyright (c) 2024 by ekxide IO GmbH. 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_platform/atomic.hpp" + +#include "test.hpp" + +#include + +namespace +{ +using namespace ::testing; + +struct DummyStruct +{ + static constexpr uint64_t DEFAULT_VALUE{42}; + uint64_t value{DEFAULT_VALUE}; +}; + +bool operator==(const DummyStruct& lhs, const DummyStruct& rhs) +{ + return lhs.value == rhs.value; +} + +struct StdAtomic +{ + template + using SutType = std::atomic; +}; +struct IoxAtomic +{ + template + using SutType = iox::Atomic; +}; + +template +class Atomic_test : public Test +{ + protected: + template + using SutType = typename T::template SutType; +}; + +using Implementations = Types; + +TYPED_TEST_SUITE(Atomic_test, Implementations, ); + +TYPED_TEST(Atomic_test, IsAlwaysLockFree) +{ + ::testing::Test::RecordProperty("TEST_ID", "28ac9afb-14a1-4970-b461-ec523f712d6b"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + EXPECT_THAT(SutInt::is_always_lock_free, Eq(true)); + EXPECT_THAT(SutFP::is_always_lock_free, Eq(true)); + EXPECT_THAT(SutPtr::is_always_lock_free, Eq(true)); + EXPECT_THAT(SutStruct::is_always_lock_free, Eq(true)); +} + +TYPED_TEST(Atomic_test, DefaultCtorWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "840e5518-5bfa-4932-bdcf-125995dd7029"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + SutInt sut_int; + SutFP sut_fp; + SutPtr sut_ptr; + SutStruct sut_struct; + + if (std::is_same_v>) + { + GTEST_SKIP() << "Default CTor test skipped for std::atomic since the iox::Atomic always initialized the value!"; + } + + EXPECT_THAT(sut_int.load(), Eq(uint64_t())); + EXPECT_THAT(sut_fp.load(), Eq(double())); + EXPECT_THAT(sut_ptr.load(), Eq(nullptr)); + EXPECT_THAT(sut_struct.load(), Eq(DummyStruct{DummyStruct::DEFAULT_VALUE})); +} + +TYPED_TEST(Atomic_test, CtorArgumentWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "7dd9d9f8-4985-463d-af61-3b19b5a9cf34"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INT{13}; + constexpr double EXPECTED_FP{73.37}; + constexpr DummyStruct EXPECTED_STRUCT{4242}; + uint64_t ptr_source{0}; + uint64_t* expected_ptr{&ptr_source}; + + SutInt sut_int{EXPECTED_INT}; + SutFP sut_fp{EXPECTED_FP}; + SutPtr sut_ptr(expected_ptr); + SutStruct sut_struct{EXPECTED_STRUCT}; + + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_INT)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_FP)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_ptr)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_STRUCT)); +} + +TYPED_TEST(Atomic_test, AssignmentOperatorWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "2fc65a59-ff5b-4272-95ac-b7dce804f34e"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INT{3}; + constexpr double EXPECTED_FP{73.7}; + constexpr DummyStruct EXPECTED_STRUCT{422}; + uint64_t ptr_source{0}; + uint64_t* expected_ptr{&ptr_source}; + + SutInt sut_int; + SutFP sut_fp; + SutPtr sut_ptr; + SutStruct sut_struct; + + sut_int = EXPECTED_INT; + sut_fp = EXPECTED_FP; + sut_ptr = expected_ptr; + sut_struct = EXPECTED_STRUCT; + + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_INT)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_FP)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_ptr)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_STRUCT)); +} + +TYPED_TEST(Atomic_test, ConversionOperatorWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "364732a4-5456-435c-80bf-34f54172632c"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INT{113}; + constexpr double EXPECTED_FP{7.37}; + constexpr DummyStruct EXPECTED_STRUCT{242}; + uint64_t ptr_source{0}; + uint64_t* expected_ptr{&ptr_source}; + + SutInt sut_int{EXPECTED_INT}; + SutFP sut_fp{EXPECTED_FP}; + SutPtr sut_ptr(expected_ptr); + SutStruct sut_struct{EXPECTED_STRUCT}; + + EXPECT_THAT(static_cast(sut_int), Eq(EXPECTED_INT)); + EXPECT_THAT(static_cast(sut_fp), Eq(EXPECTED_FP)); + EXPECT_THAT(static_cast(sut_ptr), Eq(expected_ptr)); + EXPECT_THAT(static_cast(sut_struct), Eq(EXPECTED_STRUCT)); +} + +TYPED_TEST(Atomic_test, IsLockFreeWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "d5eb1b2c-515d-42fd-87f2-b8f51dd29d09"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + SutInt sut_int; + SutFP sut_fp; + SutPtr sut_ptr; + SutStruct sut_struct; + + EXPECT_THAT(sut_int.is_lock_free(), Eq(true)); + EXPECT_THAT(sut_fp.is_lock_free(), Eq(true)); + EXPECT_THAT(sut_ptr.is_lock_free(), Eq(true)); + EXPECT_THAT(sut_struct.is_lock_free(), Eq(true)); +} + +TYPED_TEST(Atomic_test, StoreAndLoadWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "10d44cbe-81df-4d89-a6db-6553a5b58d02"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INT{31}; + constexpr double EXPECTED_FP{73.73}; + constexpr DummyStruct EXPECTED_STRUCT{4422}; + uint64_t ptr_source{0}; + uint64_t* expected_ptr{&ptr_source}; + + SutInt sut_int; + SutFP sut_fp; + SutPtr sut_ptr; + SutStruct sut_struct; + + sut_int.store(EXPECTED_INT, std::memory_order::memory_order_relaxed); + sut_fp.store(EXPECTED_FP, std::memory_order::memory_order_relaxed); + sut_ptr.store(expected_ptr, std::memory_order::memory_order_relaxed); + sut_struct.store(EXPECTED_STRUCT, std::memory_order::memory_order_relaxed); + + EXPECT_THAT(sut_int.load(std::memory_order::memory_order_relaxed), Eq(EXPECTED_INT)); + EXPECT_THAT(sut_fp.load(std::memory_order::memory_order_relaxed), Eq(EXPECTED_FP)); + EXPECT_THAT(sut_ptr.load(std::memory_order::memory_order_relaxed), Eq(expected_ptr)); + EXPECT_THAT(sut_struct.load(std::memory_order::memory_order_relaxed), Eq(EXPECTED_STRUCT)); +} + +TYPED_TEST(Atomic_test, ExchangeWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "a461a0ee-bda6-45e4-a7f0-f501d3c385b4"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INITIAL_INT{31}; + constexpr double EXPECTED_INITIAL_FP{73.73}; + constexpr DummyStruct EXPECTED_INITIAL_STRUCT{4422}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{31}; + constexpr double EXPECTED_NEW_FP{73.73}; + constexpr DummyStruct EXPECTED_NEW_STRUCT{4422}; + uint64_t ptr_new_source{0}; + uint64_t* expected_new_ptr{&ptr_new_source}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutFP sut_fp{EXPECTED_INITIAL_FP}; + SutPtr sut_ptr(expected_initial_ptr); + SutStruct sut_struct{EXPECTED_INITIAL_STRUCT}; + + EXPECT_THAT(sut_int.exchange(EXPECTED_NEW_INT, std::memory_order::memory_order_relaxed), Eq(EXPECTED_INITIAL_INT)); + EXPECT_THAT(sut_fp.exchange(EXPECTED_NEW_FP, std::memory_order::memory_order_relaxed), Eq(EXPECTED_INITIAL_FP)); + EXPECT_THAT(sut_ptr.exchange(expected_new_ptr, std::memory_order::memory_order_relaxed), Eq(expected_initial_ptr)); + EXPECT_THAT(sut_struct.exchange(EXPECTED_NEW_STRUCT, std::memory_order::memory_order_relaxed), + Eq(EXPECTED_INITIAL_STRUCT)); + + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_NEW_FP)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_NEW_STRUCT)); +} + +TYPED_TEST(Atomic_test, CompareExchangeWeakWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "d563ea82-4284-4b1c-8791-9387f5c77fc1"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INITIAL_INT{31}; + constexpr double EXPECTED_INITIAL_FP{73.73}; + constexpr DummyStruct EXPECTED_INITIAL_STRUCT{4422}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{313}; + constexpr double EXPECTED_NEW_FP{73.37}; + constexpr DummyStruct EXPECTED_NEW_STRUCT{2244}; + uint64_t ptr_new_source{0}; + uint64_t* expected_new_ptr{&ptr_new_source}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutFP sut_fp{EXPECTED_INITIAL_FP}; + SutPtr sut_ptr(expected_initial_ptr); + SutStruct sut_struct{EXPECTED_INITIAL_STRUCT}; + + uint64_t expected_int{EXPECTED_INITIAL_INT}; + EXPECT_THAT(sut_int.compare_exchange_weak(expected_int, EXPECTED_NEW_INT, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_int, Eq(EXPECTED_INITIAL_INT)); + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_int.compare_exchange_weak(expected_int, + EXPECTED_INITIAL_INT, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_int, Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + + double expected_fp{EXPECTED_INITIAL_FP}; + EXPECT_THAT(sut_fp.compare_exchange_weak(expected_fp, EXPECTED_NEW_FP, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_fp, Eq(EXPECTED_INITIAL_FP)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_NEW_FP)); + EXPECT_THAT(sut_fp.compare_exchange_weak(expected_fp, + EXPECTED_INITIAL_FP, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_fp, Eq(EXPECTED_NEW_FP)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_NEW_FP)); + + uint64_t* expected_ptr{expected_initial_ptr}; + EXPECT_THAT(sut_ptr.compare_exchange_weak(expected_ptr, expected_new_ptr, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_ptr, Eq(expected_initial_ptr)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); + EXPECT_THAT(sut_ptr.compare_exchange_weak(expected_ptr, + expected_initial_ptr, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_ptr, Eq(expected_new_ptr)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); + + DummyStruct expected_struct{EXPECTED_INITIAL_STRUCT}; + EXPECT_THAT( + sut_struct.compare_exchange_weak(expected_struct, EXPECTED_NEW_STRUCT, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_struct, Eq(EXPECTED_INITIAL_STRUCT)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_NEW_STRUCT)); + EXPECT_THAT(sut_struct.compare_exchange_weak(expected_struct, + EXPECTED_INITIAL_STRUCT, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_struct, Eq(EXPECTED_NEW_STRUCT)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_NEW_STRUCT)); +} + +TYPED_TEST(Atomic_test, CompareExchangeStronWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "9f39293c-5d84-4d59-ab91-58fb738b5386"); + + using SutInt = typename TestFixture::template SutType; + using SutFP = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + using SutStruct = typename TestFixture::template SutType; + + constexpr uint64_t EXPECTED_INITIAL_INT{131}; + constexpr double EXPECTED_INITIAL_FP{37.73}; + constexpr DummyStruct EXPECTED_INITIAL_STRUCT{4242}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{313}; + constexpr double EXPECTED_NEW_FP{73.37}; + constexpr DummyStruct EXPECTED_NEW_STRUCT{2244}; + uint64_t ptr_new_source{0}; + uint64_t* expected_new_ptr{&ptr_new_source}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutFP sut_fp{EXPECTED_INITIAL_FP}; + SutPtr sut_ptr(expected_initial_ptr); + SutStruct sut_struct{EXPECTED_INITIAL_STRUCT}; + + uint64_t expected_int{EXPECTED_INITIAL_INT}; + EXPECT_THAT( + sut_int.compare_exchange_strong(expected_int, EXPECTED_NEW_INT, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_int, Eq(EXPECTED_INITIAL_INT)); + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_int.compare_exchange_strong(expected_int, + EXPECTED_INITIAL_INT, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_int, Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + + double expected_fp{EXPECTED_INITIAL_FP}; + EXPECT_THAT(sut_fp.compare_exchange_strong(expected_fp, EXPECTED_NEW_FP, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_fp, Eq(EXPECTED_INITIAL_FP)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_NEW_FP)); + EXPECT_THAT(sut_fp.compare_exchange_strong(expected_fp, + EXPECTED_INITIAL_FP, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_fp, Eq(EXPECTED_NEW_FP)); + EXPECT_THAT(sut_fp.load(), Eq(EXPECTED_NEW_FP)); + + uint64_t* expected_ptr{expected_initial_ptr}; + EXPECT_THAT( + sut_ptr.compare_exchange_strong(expected_ptr, expected_new_ptr, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_ptr, Eq(expected_initial_ptr)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); + EXPECT_THAT(sut_ptr.compare_exchange_strong(expected_ptr, + expected_initial_ptr, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_ptr, Eq(expected_new_ptr)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); + + DummyStruct expected_struct{EXPECTED_INITIAL_STRUCT}; + EXPECT_THAT(sut_struct.compare_exchange_strong( + expected_struct, EXPECTED_NEW_STRUCT, std::memory_order::memory_order_relaxed), + Eq(true)); + EXPECT_THAT(expected_struct, Eq(EXPECTED_INITIAL_STRUCT)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_NEW_STRUCT)); + EXPECT_THAT(sut_struct.compare_exchange_strong(expected_struct, + EXPECTED_INITIAL_STRUCT, + std::memory_order::memory_order_release, + std::memory_order::memory_order_acquire), + Eq(false)); + EXPECT_THAT(expected_struct, Eq(EXPECTED_NEW_STRUCT)); + EXPECT_THAT(sut_struct.load(), Eq(EXPECTED_NEW_STRUCT)); +} + +TYPED_TEST(Atomic_test, FetchAddWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "9525afc0-35cc-45ae-84d6-11f154395740"); + + using SutInt = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + + constexpr uint64_t DELTA_INT{5}; + constexpr std::ptrdiff_t DELTA_PTR{DELTA_INT}; + + constexpr uint64_t EXPECTED_INITIAL_INT{31}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{EXPECTED_INITIAL_INT + DELTA_INT}; + uint64_t* expected_new_ptr{expected_initial_ptr + DELTA_PTR}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutPtr sut_ptr(&ptr_initial_source); + + EXPECT_THAT(sut_int.fetch_add(DELTA_INT, std::memory_order::memory_order_relaxed), Eq(EXPECTED_INITIAL_INT)); + EXPECT_THAT(sut_ptr.fetch_add(DELTA_PTR, std::memory_order::memory_order_relaxed), Eq(expected_initial_ptr)); + + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); +} + +TYPED_TEST(Atomic_test, FetchSubWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "2b13c4c3-95d8-43d2-a8e2-7e93b1f1e892"); + + using SutInt = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + + constexpr uint64_t DELTA_INT{3}; + constexpr std::ptrdiff_t DELTA_PTR{DELTA_INT}; + + constexpr uint64_t EXPECTED_INITIAL_INT{31}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{EXPECTED_INITIAL_INT - DELTA_INT}; + uint64_t* expected_new_ptr{expected_initial_ptr - DELTA_PTR}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutPtr sut_ptr(&ptr_initial_source); + + EXPECT_THAT(sut_int.fetch_sub(DELTA_INT, std::memory_order::memory_order_relaxed), Eq(EXPECTED_INITIAL_INT)); + EXPECT_THAT(sut_ptr.fetch_sub(DELTA_PTR, std::memory_order::memory_order_relaxed), Eq(expected_initial_ptr)); + + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); +} + +TYPED_TEST(Atomic_test, AddAssignmentWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "90bdd039-31d3-47ed-9d10-7c38e1e837ce"); + + using SutInt = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + + constexpr uint64_t DELTA_INT{13}; + constexpr std::ptrdiff_t DELTA_PTR{DELTA_INT}; + + constexpr uint64_t EXPECTED_INITIAL_INT{31}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{EXPECTED_INITIAL_INT + DELTA_INT}; + uint64_t* expected_new_ptr{expected_initial_ptr + DELTA_PTR}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutPtr sut_ptr(&ptr_initial_source); + + EXPECT_THAT(sut_int += DELTA_INT, Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_ptr += DELTA_PTR, Eq(expected_new_ptr)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); +} + +TYPED_TEST(Atomic_test, SubAssignmentWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "56737ae3-67e7-4daf-a316-f25c19af7fb9"); + + using SutInt = typename TestFixture::template SutType; + using SutPtr = typename TestFixture::template SutType; + + constexpr uint64_t DELTA_INT{10}; + constexpr std::ptrdiff_t DELTA_PTR{DELTA_INT}; + + constexpr uint64_t EXPECTED_INITIAL_INT{31}; + uint64_t ptr_initial_source{0}; + uint64_t* expected_initial_ptr{&ptr_initial_source}; + + constexpr uint64_t EXPECTED_NEW_INT{EXPECTED_INITIAL_INT - DELTA_INT}; + uint64_t* expected_new_ptr{expected_initial_ptr - DELTA_PTR}; + + SutInt sut_int{EXPECTED_INITIAL_INT}; + SutPtr sut_ptr(&ptr_initial_source); + + EXPECT_THAT(sut_int -= DELTA_INT, Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_int.load(), Eq(EXPECTED_NEW_INT)); + EXPECT_THAT(sut_ptr -= DELTA_PTR, Eq(expected_new_ptr)); + EXPECT_THAT(sut_ptr.load(), Eq(expected_new_ptr)); +} + +} // namespace