From 6907983a331bb936efee9bfee99d1a1182a46c15 Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Wed, 29 Apr 2026 14:15:31 +0200 Subject: [PATCH 1/9] mw/com: Store field set handler in method instead of field --- score/mw/com/impl/skeleton_field.h | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index 228ab650d..0bf2cbf1c 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -118,18 +118,18 @@ class SkeletonField : public SkeletonFieldBase // // \tparam CallableType Any callable (std::function, score::cpp::callback, lambda, ...) with the signature: // void(FieldType& new_value) - // - new_value : the value requested by the proxy. + // - new_value : the value requested by the proxy. This value will be modified in place by the registered handler + // and the new value will be used to update the field. template ::type = 0, typename CallableType> - Result RegisterSetHandler(CallableType&& handler) + Result RegisterSetHandler(CallableType&& set_handler) { static_assert(std::is_invocable_v, "RegisterSetHandler: handler must be callable as void(FieldType& value). " "The argument initially holds the proxy-requested value and may be modified in-place."); - set_handler_ = std::move(handler); - auto wrapped_callback = [this](FieldType& new_value) -> FieldType { + auto wrapped_callback = [this, set_handler = std::move(set_handler)](FieldType& new_value) -> FieldType { // Allow user to validate/modify the value in-place - set_handler_(new_value); + set_handler(new_value); // Store the (possibly modified) value as the latest field value auto update_result = this->Update(new_value); @@ -168,15 +168,6 @@ class SkeletonField : public SkeletonFieldBase std::conditional_t>, detail::EnableSetOnlyTag>; SetMethodType set_method_; - // Stores the user-provided set handler. Kept as a member so that the wrapped - // callback can invoke it via this->set_handler_. The concrete storage type is - // score::cpp::callback with the expected signature so that any callable provided - // to RegisterSetHandler is type-erased here. - // Zero-cost when EnableSet=false. - using SetHandlerStorageType = - std::conditional_t, detail::EnableSetOnlyTag>; - SetHandlerStorageType set_handler_{}; - // Tracks whether RegisterSetHandler() has been called. Zero-cost when EnableSet=false. using IsSetHandlerRegisteredType = std::conditional_t; IsSetHandlerRegisteredType is_set_handler_registered_{}; @@ -311,7 +302,6 @@ SkeletonField::SkeletonField(Skeleton initial_field_value_{std::move(other.initial_field_value_)}, skeleton_field_mock_{other.skeleton_field_mock_}, set_method_{std::move(other.set_method_)}, - set_handler_{std::move(other.set_handler_)}, is_set_handler_registered_{std::move(other.is_set_handler_registered_)}, get_method_{std::move(other.get_method_)} { @@ -330,7 +320,6 @@ auto SkeletonField::operator=(Skeleto initial_field_value_ = std::move(other.initial_field_value_); skeleton_field_mock_ = std::move(other.skeleton_field_mock_); set_method_ = std::move(other.set_method_); - set_handler_ = std::move(other.set_handler_); is_set_handler_registered_ = std::move(other.is_set_handler_registered_); get_method_ = std::move(other.get_method_); SkeletonBaseView skeleton_base_view{skeleton_base_.get()}; From 5edf9dd792db709ea040938874f54bc6ce9ccc25 Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Wed, 29 Apr 2026 16:02:38 +0200 Subject: [PATCH 2/9] mw/com: Extract duplicate code into fixture --- score/mw/com/impl/skeleton_field_test.cpp | 559 ++++++---------------- 1 file changed, 154 insertions(+), 405 deletions(-) diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index 1967b65c0..b2c762ed4 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -68,6 +68,41 @@ class MyDummySkeleton : public SkeletonBase SkeletonField my_dummy_field_{*this, kFieldName}; }; +class SkeletonFieldTestFixture : public ::testing::Test +{ + protected: + void SetUp() override + { + ON_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, + CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) + .WillByDefault(InvokeWithoutArgs([this]() { + return std::make_unique>( + skeleton_field_binding_mock_); + })); + + ON_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) + .WillByDefault(InvokeWithoutArgs([this]() { + return std::make_unique(skeleton_field_get_binding_mock_); + })); + + ON_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) + .WillByDefault(InvokeWithoutArgs([this]() { + return std::make_unique(skeleton_field_set_binding_mock_); + })); + } + + RuntimeMockGuard runtime_mock_guard_{}; + + SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard_{}; + SkeletonMethodBindingFactoryMockGuard skeleton_method_binding_factory_mock_guard_{}; + + mock_binding::SkeletonEvent skeleton_field_binding_mock_{}; + mock_binding::SkeletonMethod skeleton_field_get_binding_mock_{}; + mock_binding::SkeletonMethod skeleton_field_set_binding_mock_{}; +}; + TEST(SkeletonFieldTest, NotCopyable) { RecordProperty("Verifies", "SCR-18221574"); @@ -115,7 +150,8 @@ TEST(SkeletonFieldTest, SkeletonFieldContainsPublicSampleType) // When Ticket-104261 is implemented, the Update call does not have to be deferred until OfferService is called. This // test can be reworked to remove the call to PrepareOffer() and simply test Update() before PrepareOffer() is called. -TEST(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServiceDefersCallToOfferService) +using SkeletonFieldCopyUpdateTest = SkeletonFieldTestFixture; +TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServiceDefersCallToOfferService) { RecordProperty("Verifies", "SCR-17434775, SCR-17563743, SCR-21553554"); RecordProperty("Description", "Checks that calling Update before offer service defers the call to OfferService()."); @@ -126,23 +162,11 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServiceDefersCallToOff const TestSampleType initial_value{42}; bool is_send_called_on_binding{false}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)) .WillOnce(InvokeWithoutArgs([&is_send_called_on_binding]() noexcept -> Result { is_send_called_on_binding = true; return {}; @@ -173,7 +197,7 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServiceDefersCallToOff // When Ticket-104261 is implemented, the Update call does not have to be deferred until OfferService is called. This // test can be reworked to remove the call to PrepareOffer() and the deferred processing of Update() and simply test // Update() before PrepareOffer() is called. -TEST(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServicePropagatesBindingFailureToOfferService) +TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServicePropagatesBindingFailureToOfferService) { RecordProperty("Verifies", "SCR-17434775, SCR-21553554"); RecordProperty("Description", "Checks that calling Update before offer service defers the call to OfferService()."); @@ -184,23 +208,11 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServicePropagatesBindi const TestSampleType initial_value{42}; bool is_send_called_on_binding{false}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an error - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)) .WillOnce(InvokeWithoutArgs([&is_send_called_on_binding] { is_send_called_on_binding = true; return MakeUnexpected(ComErrc::kInvalidBindingInformation); @@ -229,7 +241,7 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServicePropagatesBindi EXPECT_TRUE(is_send_called_on_binding); } -TEST(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServiceDispatchesToBinding) +TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServiceDispatchesToBinding) { RecordProperty("Verifies", "SCR-17434775, SCR-21553375"); RecordProperty("Description", "Checks that calling Update after offer service dispatches to the binding."); @@ -240,26 +252,14 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServiceDispatchesToBind const TestSampleType initial_value{42}; const TestSampleType updated_value{43}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(score::Result{})); // and Send will be called a second time on the event binding with the updated value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock, Send(updated_value, _)).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(updated_value, _)).WillOnce(Return(score::Result{})); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -283,7 +283,7 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServiceDispatchesToBind ASSERT_TRUE(update_result_2.has_value()); } -TEST(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServicePropagatesBindingFail) +TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServicePropagatesBindingFail) { RecordProperty("Verifies", "SCR-17434775, SCR-21553375"); RecordProperty("Description", @@ -296,26 +296,14 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServicePropagatesBindin const TestSampleType initial_value{42}; const TestSampleType updated_value{43}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(score::Result{})); // and Send will be called a second time on the event binding with the updated value and returns an error - EXPECT_CALL(skeleton_field_binding_mock, Send(updated_value, _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(updated_value, _)) .WillOnce(Return(MakeUnexpected(ComErrc::kInvalidBindingInformation))); // Given a skeleton created based on a Lola binding @@ -342,25 +330,16 @@ TEST(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServicePropagatesBindin } // This test can be removed when Ticket-104261 is implemented. -TEST(SkeletonFieldAllocateTest, CallingAllocateBeforePrepareOfferDoesNotReturnValidSlot) -{ - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; +using SkeletonFieldAllocateTest = SkeletonFieldTestFixture; - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); +TEST_F(SkeletonFieldAllocateTest, CallingAllocateBeforePrepareOfferDoesNotReturnValidSlot) +{ - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).Times(0); + // and that PrepareOffer() will not be called on the event binding + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).Times(0); // and Allocate will not be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, Allocate()).Times(0); + EXPECT_CALL(skeleton_field_binding_mock_, Allocate()).Times(0); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -373,7 +352,7 @@ TEST(SkeletonFieldAllocateTest, CallingAllocateBeforePrepareOfferDoesNotReturnVa EXPECT_EQ(slot_result.error(), ComErrc::kBindingFailure); } -TEST(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferDispatchesToBinding) +TEST_F(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferDispatchesToBinding) { RecordProperty("Verifies", "SCR-17434933, SCR-21470600"); RecordProperty("Description", "Checks that calling allocate after prepare offer dispatches to the binding."); @@ -383,26 +362,14 @@ TEST(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferDispatchesToBind const TestSampleType initial_value{42}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); // and Allocate will be called again which returns a valid SampleAllocateePtr - EXPECT_CALL(skeleton_field_binding_mock, Allocate()) + EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) .WillOnce(Return(ByMove(MakeSampleAllocateePtr(std::make_unique())))); // Given a skeleton created based on a Lola binding @@ -427,7 +394,7 @@ TEST(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferDispatchesToBind ASSERT_TRUE(slot_result.has_value()); } -TEST(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferFailsWhenBindingReturnsError) +TEST_F(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferFailsWhenBindingReturnsError) { RecordProperty("Verifies", "SCR-17434933"); RecordProperty("Description", @@ -438,26 +405,14 @@ TEST(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferFailsWhenBinding const TestSampleType initial_value{42}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); // and Allocate will be called again which returns a nullptr - EXPECT_CALL(skeleton_field_binding_mock, Allocate()) + EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) .WillOnce(Return(ByMove(MakeUnexpected(ComErrc::kInvalidConfiguration)))); // Given a skeleton created based on a Lola binding @@ -483,7 +438,9 @@ TEST(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferFailsWhenBinding EXPECT_EQ(slot_result.error(), ComErrc::kBindingFailure); } -TEST(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceDispatchesToBinding) +using SkeletonFieldZeroCopyUpdateTest = SkeletonFieldTestFixture; + +TEST_F(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceDispatchesToBinding) { RecordProperty("Verifies", "SCR-17434778, SCR-21553623"); RecordProperty("Description", @@ -495,30 +452,18 @@ TEST(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceDisp const TestSampleType initial_value{42}; const TestSampleType new_value{52}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); // and Allocate will be called again which returns a valid SampleAllocateePtr - EXPECT_CALL(skeleton_field_binding_mock, Allocate()) + EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) .WillOnce(Return(ByMove(MakeSampleAllocateePtr(std::make_unique())))); // and Send will be called a second time on the event binding with a new value which returns an empty result - EXPECT_CALL(skeleton_field_binding_mock, Send(An>(), _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(An>(), _)) .WillOnce(WithArg<0>(Invoke([new_value](SampleAllocateePtr sample_ptr) -> Result { EXPECT_EQ(*sample_ptr, new_value); return {}; @@ -556,7 +501,7 @@ TEST(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceDisp EXPECT_TRUE(new_update_result.has_value()); } -TEST(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServicePropagatesBindingFail) +TEST_F(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServicePropagatesBindingFail) { RecordProperty("Verifies", "SCR-17434778"); RecordProperty( @@ -570,30 +515,18 @@ TEST(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceProp const TestSampleType initial_value{42}; const TestSampleType new_value{52}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); // and Allocate will be called again which returns a valid SampleAllocateePtr - EXPECT_CALL(skeleton_field_binding_mock, Allocate()) + EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) .WillOnce(Return(ByMove(MakeSampleAllocateePtr(std::make_unique())))); // and Send will be called a second time on the event binding with a new value which returns an error - EXPECT_CALL(skeleton_field_binding_mock, Send(An>(), _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(An>(), _)) .WillOnce(WithArg<0>(Invoke([new_value](SampleAllocateePtr sample_ptr) -> Result { EXPECT_EQ(*sample_ptr, new_value); return MakeUnexpected(ComErrc::kInvalidBindingInformation); @@ -630,7 +563,9 @@ TEST(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceProp EXPECT_EQ(update_result_2.error(), ComErrc::kBindingFailure); } -TEST(SkeletonFieldInitialValueFixture, LatestFieldValueWillBeSetOnPrepareOffer) +using SkeletonFieldInitialValueFixture = SkeletonFieldTestFixture; + +TEST_F(SkeletonFieldInitialValueFixture, LatestFieldValueWillBeSetOnPrepareOffer) { RecordProperty("Verifies", "SCR-22129134"); RecordProperty( @@ -643,23 +578,11 @@ TEST(SkeletonFieldInitialValueFixture, LatestFieldValueWillBeSetOnPrepareOffer) const TestSampleType initial_value{42}; const TestSampleType latest_value{43}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called only once on the event binding with the latest value - EXPECT_CALL(skeleton_field_binding_mock, Send(latest_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(latest_value, _)); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -683,7 +606,7 @@ TEST(SkeletonFieldInitialValueFixture, LatestFieldValueWillBeSetOnPrepareOffer) EXPECT_TRUE(prepare_offer_result.has_value()); } -TEST(SkeletonFieldInitialValueFixture, OfferingFieldBeforeUpdatingValueReturnsError) +TEST_F(SkeletonFieldInitialValueFixture, OfferingFieldBeforeUpdatingValueReturnsError) { RecordProperty("Verifies", "SCR-17563743"); RecordProperty("Description", "Calling OfferService before setting the field value returns kFieldValueIsNotValid."); @@ -691,20 +614,8 @@ TEST(SkeletonFieldInitialValueFixture, OfferingFieldBeforeUpdatingValueReturnsEr RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will not be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).Times(0); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).Times(0); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -719,27 +630,15 @@ TEST(SkeletonFieldInitialValueFixture, OfferingFieldBeforeUpdatingValueReturnsEr EXPECT_EQ(result.error(), ComErrc::kFieldValueIsNotValid); } -TEST(SkeletonFieldInitialValueFixture, MoveConstructingFieldBeforePrepareOfferWillKeepInitialValue) +TEST_F(SkeletonFieldInitialValueFixture, MoveConstructingFieldBeforePrepareOfferWillKeepInitialValue) { const TestSampleType initial_value{42}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - - // Expecting that a SkeletonField binding is created - auto skeleton_field_binding_mock_ptr = std::make_unique>(); - auto& skeleton_field_binding_mock = *skeleton_field_binding_mock_ptr; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // and that PrepareOffer() will be called on the event binding - EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -760,7 +659,7 @@ TEST(SkeletonFieldInitialValueFixture, MoveConstructingFieldBeforePrepareOfferWi EXPECT_TRUE(prepare_offer_result.has_value()); } -TEST(SkeletonFieldInitialValueFixture, MoveAssigningFieldBeforePrepareOfferWillKeepInitialValue) +TEST(SkeletonFieldInitialValueTest, MoveAssigningFieldBeforePrepareOfferWillKeepInitialValue) { const TestSampleType initial_value{42}; const TestSampleType initial_value_2{43}; @@ -827,17 +726,8 @@ TEST(SkeletonFieldInitialValueFixture, MoveAssigningFieldBeforePrepareOfferWillK EXPECT_TRUE(prepare_offer_result.has_value()); } -TEST(SkeletonFieldTest, SkeletonFieldsRegisterThemselvesWithSkeleton) +TEST_F(SkeletonFieldTestFixture, SkeletonFieldsRegisterThemselvesWithSkeleton) { - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - // Expecting that the SkeletonFieldBindingFactory returns a valid binding - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -857,17 +747,8 @@ TEST(SkeletonFieldTest, SkeletonFieldsRegisterThemselvesWithSkeleton) EXPECT_EQ(&field, &unit.my_dummy_field_); } -TEST(SkeletonFieldTest, MovingConstructingSkeletonUpdatesFieldMapReference) +TEST_F(SkeletonFieldTestFixture, MovingConstructingSkeletonUpdatesFieldMapReference) { - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - // Expecting that the SkeletonFieldBindingFactory returns a valid binding - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -889,11 +770,8 @@ TEST(SkeletonFieldTest, MovingConstructingSkeletonUpdatesFieldMapReference) EXPECT_EQ(&field, &unit2.my_dummy_field_); } -TEST(SkeletonFieldTest, MovingAssigningSkeletonUpdatesFieldMapReference) +TEST_F(SkeletonFieldTestFixture, MovingAssigningSkeletonUpdatesFieldMapReference) { - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - ServiceIdentifierType service{make_ServiceIdentifierType("foo2", 1U, 0U)}; const ServiceInstanceDeployment instance_deployment{ service, @@ -903,12 +781,6 @@ TEST(SkeletonFieldTest, MovingAssigningSkeletonUpdatesFieldMapReference) InstanceIdentifier identifier2{make_InstanceIdentifier(instance_deployment, kTypeDeployment)}; // Expecting that the SkeletonFieldBindingFactory returns a valid binding for both Skeletons - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, CreateEventBinding(identifier2, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -933,17 +805,9 @@ TEST(SkeletonFieldTest, MovingAssigningSkeletonUpdatesFieldMapReference) EXPECT_EQ(&field, &unit2.my_dummy_field_); } -TEST(SkeletonFieldDeathTest, UpdateWithInvalidFieldNameTriggersTermination) +using SkeletonFieldDeathTest = SkeletonFieldTestFixture; +TEST_F(SkeletonFieldDeathTest, UpdateWithInvalidFieldNameTriggersTermination) { - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - // Expecting that the SkeletonFieldBindingFactory returns a valid binding - SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard{}; - EXPECT_CALL(skeleton_field_binding_factory_mock_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -971,7 +835,7 @@ class MySetterSkeleton : public SkeletonBase // Static type-trait tests for RegisterSetHandler availability -TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerOnlyExistsWhenEnableSetIsTrue) +TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerOnlyExistsWhenEnableSetIsTrue) { RecordProperty("Description", "RegisterSetHandler() shall only exist on SkeletonField. " @@ -992,7 +856,9 @@ TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerOnlyExistsWhenEnableSetIsTru // RegisterSetHandler – happy-path: handler forwarded to method binding -TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) +using SkeletonFieldSetHandlerTest = SkeletonFieldTestFixture; + +TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) { RecordProperty("Description", "Calling RegisterSetHandler() on an EnableSet=true SkeletonField shall forward " @@ -1002,24 +868,8 @@ TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - - // Inject a mock SkeletonMethodBinding so that RegisterHandler is interceptable. - mock_binding::SkeletonMethod method_binding_mock{}; - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) - .WillOnce(Return(ByMove(std::make_unique(method_binding_mock)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); - // The method binding's RegisterHandler must be called exactly once and returns success. - EXPECT_CALL(method_binding_mock, RegisterHandler(_)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillOnce(Return(Result{})); // Given a setter-capable skeleton MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1033,7 +883,7 @@ TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) // RegisterSetHandler – failure propagation from the method binding -TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) +TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) { RecordProperty("Description", "When the underlying SkeletonMethod binding returns an error from RegisterHandler, " @@ -1042,23 +892,8 @@ TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - - mock_binding::SkeletonMethod method_binding_mock{}; - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) - .WillOnce(Return(ByMove(std::make_unique(method_binding_mock)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); - // The method binding returns an error - EXPECT_CALL(method_binding_mock, RegisterHandler(_)) + EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)) .WillOnce(Return(MakeUnexpected(ComErrc::kCommunicationLinkError))); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1073,7 +908,7 @@ TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) // PrepareOffer fails when EnableSet=true but no handler has been registered -TEST(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered) +TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered) { RecordProperty("Verifies", "SCR-17563743"); RecordProperty("Description", @@ -1083,16 +918,7 @@ TEST(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::make_unique>()))); - - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, _)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, _)) .WillOnce(Return(ByMove(nullptr))) .WillOnce(Return(ByMove(nullptr))); @@ -1111,7 +937,7 @@ TEST(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered) // PrepareOffer succeeds when EnableSet=true and handler IS registered -TEST(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) +TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) { RecordProperty("Description", "When an EnableSet=true SkeletonField has a set handler registered and an initial " @@ -1122,29 +948,12 @@ TEST(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) const TestSampleType initial_value{7U}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - - mock_binding::SkeletonMethod method_binding_mock{}; - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) - .WillOnce(Return(ByMove(std::make_unique(method_binding_mock)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); - // The binding's RegisterHandler returns success - EXPECT_CALL(method_binding_mock, RegisterHandler(_)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillOnce(Return(Result{})); // PrepareOffer on the event binding and the initial-value Send must succeed - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(initial_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(Result{})); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1163,7 +972,7 @@ TEST(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) // EnableSet=false: PrepareOffer does NOT require a registered set handler -TEST(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnableSetIsFalse) +TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnableSetIsFalse) { RecordProperty("Description", "When a SkeletonField has EnableSet=false (no setter), PrepareOffer() shall " @@ -1174,18 +983,8 @@ TEST(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnableSe const TestSampleType initial_value{5U}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(initial_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(Result{})); // A non-setter skeleton (EnableSet=false) MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1199,7 +998,7 @@ TEST(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnableSe // RegisterSetHandler accepts any callable with the expected signature -TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerAcceptsAnyCallable) +TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerAcceptsAnyCallable) { RecordProperty("Description", "RegisterSetHandler() shall accept any callable (lambda, std::function, " @@ -1236,7 +1035,7 @@ class CapturingSkeletonMethodBinding : public SkeletonMethodBinding TypeErasedHandler captured_handler_{}; }; -TEST(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) +TEST_F(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) { RecordProperty("Description", "The callback registered with RegisterSetHandler() is invoked by the wrapped " @@ -1248,31 +1047,23 @@ TEST(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) const TestSampleType incoming_value{99U}; bool user_callback_called{false}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - // PrepareOffer and the deferred Send for the initial value - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); // The wrapped handler also calls Update(incoming_value) → Send on the event binding - EXPECT_CALL(event_binding, Send(incoming_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(incoming_value, _)).WillOnce(Return(Result{})); // Use a capturing binding so that we can invoke the type-erased handler later auto capturing_binding = std::make_unique(); auto& capturing_binding_ref = *capturing_binding; - - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) .WillOnce(Return(ByMove(std::move(capturing_binding)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) + .WillOnce(InvokeWithoutArgs([]() { + return std::unique_ptr{}; + })); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1305,7 +1096,7 @@ TEST(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) } // Handler wrapping: user callback may modify the value in-place -TEST(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) +TEST_F(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) { RecordProperty("Description", "The set handler callback receives the value by reference. Modifications made " @@ -1318,29 +1109,21 @@ TEST(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) const TestSampleType incoming_value{10U}; const TestSampleType modified_value{20U}; // callback doubles the value - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); // The modified value (20) must be the one forwarded to the event binding - EXPECT_CALL(event_binding, Send(modified_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(modified_value, _)).WillOnce(Return(Result{})); auto capturing_binding = std::make_unique(); auto& capturing_binding_ref = *capturing_binding; - - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) .WillOnce(Return(ByMove(std::move(capturing_binding)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) + .WillOnce(InvokeWithoutArgs([]() { + return std::unique_ptr{}; + })); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1367,7 +1150,7 @@ TEST(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) } // Handler wrapping: Update() failure inside the wrapped handler is logged, not propagated -TEST(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) +TEST_F(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) { RecordProperty("Description", "When the event binding's Send() fails inside the wrapped set handler, the " @@ -1381,30 +1164,22 @@ TEST(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) const TestSampleType incoming_value{55U}; bool user_callback_called{false}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); // Simulate Update() failure when the wrapped handler is invoked by the proxy - EXPECT_CALL(event_binding, Send(incoming_value, _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(incoming_value, _)) .WillOnce(Return(MakeUnexpected(ComErrc::kCommunicationLinkError))); auto capturing_binding = std::make_unique(); auto& capturing_binding_ref = *capturing_binding; - - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) .WillOnce(Return(ByMove(std::move(capturing_binding)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) + .WillOnce(InvokeWithoutArgs([]() { + return std::unique_ptr{}; + })); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1432,7 +1207,7 @@ TEST(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) } // RegisterSetHandler sets is_set_handler_registered_ flag -TEST(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistration) +TEST_F(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistration) { RecordProperty("Description", "After a successful RegisterSetHandler() call the internal flag " @@ -1443,26 +1218,10 @@ TEST(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistrati const TestSampleType initial_value{3U}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(initial_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(Result{})); - mock_binding::SkeletonMethod method_binding_mock{}; - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) - .WillOnce(Return(ByMove(std::make_unique(method_binding_mock)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) - .WillOnce(Return(ByMove(nullptr))); - EXPECT_CALL(method_binding_mock, RegisterHandler(_)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillOnce(Return(Result{})); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; @@ -1483,7 +1242,7 @@ TEST(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistrati } // RegisterSetHandler called twice: second call replaces the handler -TEST(SkeletonFieldSetHandlerTest, SecondRegisterSetHandlerReplacesHandler) +TEST_F(SkeletonFieldSetHandlerTest, SecondRegisterSetHandlerReplacesHandler) { RecordProperty("Description", "Calling RegisterSetHandler() a second time shall replace the previously stored " @@ -1497,28 +1256,18 @@ TEST(SkeletonFieldSetHandlerTest, SecondRegisterSetHandlerReplacesHandler) bool first_callback_called{false}; bool second_callback_called{false}; - RuntimeMockGuard runtime_mock_guard{}; - ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); - - SkeletonFieldBindingFactoryMockGuard field_binding_factory_guard{}; - auto event_binding_ptr = std::make_unique>(); - auto& event_binding = *event_binding_ptr; - EXPECT_CALL(field_binding_factory_guard.factory_mock_, - CreateEventBinding(kInstanceIdWithLolaBinding, _, kFieldName)) - .WillOnce(Return(ByMove(std::move(event_binding_ptr)))); - - EXPECT_CALL(event_binding, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); - EXPECT_CALL(event_binding, Send(incoming_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(incoming_value, _)).WillOnce(Return(Result{})); // The method binding is called twice (once per RegisterSetHandler) auto capturing_binding = std::make_unique(); auto& capturing_binding_ref = *capturing_binding; - - SkeletonMethodBindingFactoryMockGuard method_binding_factory_guard{}; - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kSet)) .WillOnce(Return(ByMove(std::move(capturing_binding)))); - EXPECT_CALL(method_binding_factory_guard.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(kInstanceIdWithLolaBinding, _, _, MethodType::kGet)) .WillOnce(Return(ByMove(nullptr))); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; From 46e5e5e4c761d985e347026659120073ad7cf51f Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Wed, 29 Apr 2026 16:07:47 +0200 Subject: [PATCH 3/9] mw/com: Remove redundant comments These comments are redundant with the test names and tests themselves. These comments are very likely to become out of date if these tests change / are moved so we remove them. --- score/mw/com/impl/skeleton_field_test.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index b2c762ed4..5228c9123 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -824,7 +824,6 @@ TEST_F(SkeletonFieldDeathTest, UpdateWithInvalidFieldNameTriggersTermination) } // Helper skeleton that holds an EnableSet=true field (setter-capable field) - class MySetterSkeleton : public SkeletonBase { public: @@ -833,8 +832,6 @@ class MySetterSkeleton : public SkeletonBase SkeletonField my_setter_field_{*this, kFieldName}; }; -// Static type-trait tests for RegisterSetHandler availability - TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerOnlyExistsWhenEnableSetIsTrue) { RecordProperty("Description", @@ -854,8 +851,6 @@ TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerOnlyExistsWhenEnab "EnableSet=false and EnableSet=true fields must be different types"); } -// RegisterSetHandler – happy-path: handler forwarded to method binding - using SkeletonFieldSetHandlerTest = SkeletonFieldTestFixture; TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) @@ -881,8 +876,6 @@ TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) EXPECT_TRUE(result.has_value()); } -// RegisterSetHandler – failure propagation from the method binding - TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) { RecordProperty("Description", @@ -906,8 +899,6 @@ TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) EXPECT_EQ(result.error(), ComErrc::kCommunicationLinkError); } -// PrepareOffer fails when EnableSet=true but no handler has been registered - TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered) { RecordProperty("Verifies", "SCR-17563743"); @@ -935,8 +926,6 @@ TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered EXPECT_EQ(result.error(), ComErrc::kSetHandlerNotSet); } -// PrepareOffer succeeds when EnableSet=true and handler IS registered - TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) { RecordProperty("Description", @@ -970,8 +959,6 @@ TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) EXPECT_TRUE(result.has_value()); } -// EnableSet=false: PrepareOffer does NOT require a registered set handler - TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnableSetIsFalse) { RecordProperty("Description", @@ -996,8 +983,6 @@ TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnable EXPECT_TRUE(result.has_value()); } -// RegisterSetHandler accepts any callable with the expected signature - TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerAcceptsAnyCallable) { RecordProperty("Description", @@ -1095,7 +1080,6 @@ TEST_F(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) EXPECT_TRUE(user_callback_called); } -// Handler wrapping: user callback may modify the value in-place TEST_F(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) { RecordProperty("Description", @@ -1149,7 +1133,6 @@ TEST_F(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) capturing_binding_ref.captured_handler_(in_span, out_span); } -// Handler wrapping: Update() failure inside the wrapped handler is logged, not propagated TEST_F(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) { RecordProperty("Description", @@ -1206,7 +1189,6 @@ TEST_F(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) EXPECT_TRUE(user_callback_called); } -// RegisterSetHandler sets is_set_handler_registered_ flag TEST_F(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistration) { RecordProperty("Description", @@ -1241,7 +1223,6 @@ TEST_F(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistra EXPECT_TRUE(result.has_value()); } -// RegisterSetHandler called twice: second call replaces the handler TEST_F(SkeletonFieldSetHandlerTest, SecondRegisterSetHandlerReplacesHandler) { RecordProperty("Description", From fade8ee5ee4456aec972a9b17642ff6b9e000ad9 Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Wed, 29 Apr 2026 17:29:38 +0200 Subject: [PATCH 4/9] mw/com: Remove conditional types in SkeletonField We store the set and get method dispatches always as unique_ptrs which are either nullptrs in case set / get is disabled or a pointer to a valid binding. This allows us to avoid having constructors for each combination of get / set. --- score/mw/com/impl/skeleton_field.h | 101 ++++++++++++----------------- score/mw/com/impl/traits_test.cpp | 96 ++++++++++++++------------- 2 files changed, 93 insertions(+), 104 deletions(-) diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index 0bf2cbf1c..807eedf10 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -147,6 +147,16 @@ class SkeletonField : public SkeletonFieldBase } private: + using SetMethodSignature = FieldType(FieldType); + using GetMethodSignature = FieldType(); + + /// \brief Private delegating constructor used by the no-setter public ctor and testing ctor. + SkeletonField(SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + std::unique_ptr> skeleton_set_method_dispatch, + std::unique_ptr> skeleton_get_method_dispatch, + const std::string_view field_name); + bool IsInitialValueSaved() const noexcept override { return initial_field_value_ != nullptr; @@ -159,20 +169,6 @@ class SkeletonField : public SkeletonFieldBase SkeletonEvent* GetTypedEvent() const noexcept; - std::unique_ptr initial_field_value_; - ISkeletonField* skeleton_field_mock_; - - // Zero-cost conditional storage: unique_ptr when EnableSet=true, zero-size tag when false. - using SetMethodSignature = FieldType(FieldType); - using SetMethodType = - std::conditional_t>, detail::EnableSetOnlyTag>; - SetMethodType set_method_; - - // Tracks whether RegisterSetHandler() has been called. Zero-cost when EnableSet=false. - using IsSetHandlerRegisteredType = std::conditional_t; - IsSetHandlerRegisteredType is_set_handler_registered_{}; - - // EnableSet=true: checks the flag; EnableSet=false: no setter, no handler required. bool IsSetHandlerRegistered() const noexcept override { if constexpr (EnableSet) @@ -182,27 +178,14 @@ class SkeletonField : public SkeletonFieldBase return true; } - /// \brief Private delegating constructor used by the setter-enabled public ctor. - template > - SkeletonField(SkeletonBase& parent, - std::unique_ptr> skeleton_event_dispatch, - const std::string_view field_name, - detail::EnableSetOnlyTag); + std::unique_ptr initial_field_value_; + ISkeletonField* skeleton_field_mock_; - /// \brief Private delegating constructor used by the no-setter public ctor and testing ctor. - SkeletonField(SkeletonBase& parent, - std::unique_ptr> skeleton_event_dispatch, - const std::string_view field_name); + // Tracks whether RegisterSetHandler() has been called. + bool is_set_handler_registered_; - // TODO: Move get_method_ initialization into the delegating constructors (like set_method_) once the - // Get handler is implemented. - using GetMethodSignature = FieldType(); - std::unique_ptr> get_method_{ - std::make_unique>( - skeleton_base_.get(), - field_name_, - ::score::mw::com::impl::MethodType::kGet, - typename SkeletonMethod::FieldOnlyConstructorEnabler{})}; + std::unique_ptr> set_method_; + std::unique_ptr> get_method_; }; /// \brief Public ctor — EnableSet=true: delegates to the private ctor that also creates the set method. @@ -220,8 +203,19 @@ SkeletonField::SkeletonField(Skeleton parent, field_name), typename SkeletonEvent::FieldOnlyConstructorEnabler{}), - field_name, - detail::EnableSetOnlyTag{}} + std::make_unique>( + parent, + field_name, + ::score::mw::com::impl::MethodType::kSet, + typename SkeletonMethod::FieldOnlyConstructorEnabler{}), + // TODO: Move get_method_ initialization into the delegating constructors (like set_method_) once the + // Get handler is implemented. + std::make_unique>( + parent, + field_name, + ::score::mw::com::impl::MethodType::kGet, + typename SkeletonMethod::FieldOnlyConstructorEnabler{}), + field_name} { } @@ -240,6 +234,8 @@ SkeletonField::SkeletonField(Skeleton parent, field_name), typename SkeletonEvent::FieldOnlyConstructorEnabler{}), + nullptr, + nullptr, field_name} { } @@ -252,40 +248,25 @@ SkeletonField::SkeletonField( std::unique_ptr> binding) : SkeletonField{skeleton_base, std::make_unique>(skeleton_base, field_name, std::move(binding)), + nullptr, + nullptr, field_name} { } -/// \brief Private delegating ctor — setter enabled. -template -template -SkeletonField::SkeletonField( - SkeletonBase& parent, - std::unique_ptr> skeleton_event_dispatch, - const std::string_view field_name, - detail::EnableSetOnlyTag) - : SkeletonFieldBase{parent, field_name, std::move(skeleton_event_dispatch)}, - initial_field_value_{nullptr}, - skeleton_field_mock_{nullptr} -{ - set_method_ = std::make_unique>( - parent, - field_name_, - ::score::mw::com::impl::MethodType::kSet, - typename SkeletonMethod::FieldOnlyConstructorEnabler{}); - SkeletonBaseView skeleton_base_view{parent}; - skeleton_base_view.RegisterField(field_name, *this); -} - -/// \brief Private delegating ctor — no setter. Receives the already-constructed event. template SkeletonField::SkeletonField( SkeletonBase& parent, std::unique_ptr> skeleton_event_dispatch, + std::unique_ptr> skeleton_set_method_dispatch, + std::unique_ptr> skeleton_get_method_dispatch, const std::string_view field_name) : SkeletonFieldBase{parent, field_name, std::move(skeleton_event_dispatch)}, initial_field_value_{nullptr}, - skeleton_field_mock_{nullptr} + skeleton_field_mock_{nullptr}, + is_set_handler_registered_{false}, + set_method_{std::move(skeleton_set_method_dispatch)}, + get_method_{std::move(skeleton_get_method_dispatch)} { SkeletonBaseView skeleton_base_view{parent}; skeleton_base_view.RegisterField(field_name, *this); @@ -301,8 +282,8 @@ SkeletonField::SkeletonField(Skeleton // coverity[autosar_cpp14_a12_8_3_violation] This is a false-positive. initial_field_value_{std::move(other.initial_field_value_)}, skeleton_field_mock_{other.skeleton_field_mock_}, - set_method_{std::move(other.set_method_)}, is_set_handler_registered_{std::move(other.is_set_handler_registered_)}, + set_method_{std::move(other.set_method_)}, get_method_{std::move(other.get_method_)} { SkeletonBaseView skeleton_base_view{skeleton_base_.get()}; @@ -319,8 +300,8 @@ auto SkeletonField::operator=(Skeleto initial_field_value_ = std::move(other.initial_field_value_); skeleton_field_mock_ = std::move(other.skeleton_field_mock_); - set_method_ = std::move(other.set_method_); is_set_handler_registered_ = std::move(other.is_set_handler_registered_); + set_method_ = std::move(other.set_method_); get_method_ = std::move(other.get_method_); SkeletonBaseView skeleton_base_view{skeleton_base_.get()}; skeleton_base_view.UpdateField(field_name_, *this); diff --git a/score/mw/com/impl/traits_test.cpp b/score/mw/com/impl/traits_test.cpp index 7074a6829..d10205aba 100644 --- a/score/mw/com/impl/traits_test.cpp +++ b/score/mw/com/impl/traits_test.cpp @@ -12,6 +12,7 @@ ********************************************************************************/ #include "score/mw/com/impl/traits.h" +#include "method_type.h" #include "score/mw/com/impl/bindings/mock_binding/proxy_method.h" #include "score/mw/com/impl/bindings/mock_binding/skeleton.h" #include "score/mw/com/impl/bindings/mock_binding/skeleton_method.h" @@ -104,6 +105,10 @@ class ProxyCreationFixture : public ::testing::Test std::make_unique>(proxy_field_binding_mock_); auto proxy_method_binding_mock_ptr = std::make_unique(proxy_method_binding_mock_); + auto proxy_field_get_binding_mock_ptr = + std::make_unique(proxy_field_get_binding_mock_); + auto proxy_field_set_binding_mock_ptr = + std::make_unique(proxy_field_set_binding_mock_); auto& runtime_mock = runtime_mock_guard_.runtime_mock_; // By default the runtime configuration has no GetTracingFilterConfig @@ -122,8 +127,12 @@ class ProxyCreationFixture : public ::testing::Test .WillByDefault(Return(ByMove(std::move(proxy_field_binding_mock_ptr)))); // By default the Create call on the ProxyMethodBindingFactory returns valid bindings. - ON_CALL(proxy_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, kMethodName, _)) + ON_CALL(proxy_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, kMethodName, MethodType::kMethod)) .WillByDefault(Return(ByMove(std::move(proxy_method_binding_mock_ptr)))); + ON_CALL(proxy_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, kFieldName, MethodType::kSet)) + .WillByDefault(Return(ByMove(std::move(proxy_field_set_binding_mock_ptr)))); + ON_CALL(proxy_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, kFieldName, MethodType::kGet)) + .WillByDefault(Return(ByMove(std::move(proxy_field_get_binding_mock_ptr)))); // By default that the proxy_binding can successfully call SetupMethods ON_CALL(proxy_binding_mock_, SetupMethods()).WillByDefault(Return(score::Result{})); @@ -146,6 +155,8 @@ class ProxyCreationFixture : public ::testing::Test mock_binding::ProxyEvent proxy_event_binding_mock_{}; mock_binding::ProxyEvent proxy_field_binding_mock_{}; mock_binding::ProxyMethod proxy_method_binding_mock_{}; + mock_binding::ProxyMethod proxy_field_set_binding_mock_{}; + mock_binding::ProxyMethod proxy_field_get_binding_mock_{}; }; TEST(GeneratedProxyTest, NotCopyable) @@ -461,6 +472,10 @@ class SkeletonCreationFixture : public ::testing::Test std::make_unique>(skeleton_field_binding_mock_); auto skeleton_method_binding_mock_ptr = std::make_unique(skeleton_method_binding_mock_); + auto skeleton_field_get_binding_mock_ptr = + std::make_unique(skeleton_field_get_binding_mock_); + auto skeleton_field_set_binding_mock_ptr = + std::make_unique(skeleton_field_set_binding_mock_); auto& runtime_mock = runtime_mock_guard_.runtime_mock_; // By default the runtime configuration has no GetTracingFilterConfig @@ -481,18 +496,15 @@ class SkeletonCreationFixture : public ::testing::Test .WillByDefault(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); // By default the Create call on the SkeletonMethodBindingFactory returns valid bindings. - // Broad catch-all for field get/set method bindings (defined before the specific kMethodName matcher - // so that the more specific ON_CALL takes precedence for kMethodName calls). - ON_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _)) - .WillByDefault(Invoke([this](const InstanceIdentifier&, - SkeletonBinding*, - const std::string_view, - MethodType) -> std::unique_ptr { - return std::make_unique(skeleton_field_method_binding_mock_); - })); ON_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, - Create(identifier_with_valid_binding_, _, kMethodName, _)) + Create(identifier_with_valid_binding_, _, kMethodName, MethodType::kMethod)) .WillByDefault(Return(ByMove(std::move(skeleton_method_binding_mock_ptr)))); + ON_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kSet)) + .WillByDefault(Return(ByMove(std::move(skeleton_field_set_binding_mock_ptr)))); + ON_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kGet)) + .WillByDefault(Return(ByMove(std::move(skeleton_field_get_binding_mock_ptr)))); // By default the runtime configuration resolves instance identifiers resolved_instance_identifiers_.push_back(identifier_with_valid_binding_); @@ -519,7 +531,8 @@ class SkeletonCreationFixture : public ::testing::Test mock_binding::SkeletonEvent skeleton_event_binding_mock_{}; mock_binding::SkeletonEvent skeleton_field_binding_mock_{}; mock_binding::SkeletonMethod skeleton_method_binding_mock_{}; - mock_binding::SkeletonMethod skeleton_field_method_binding_mock_{}; + mock_binding::SkeletonMethod skeleton_field_set_binding_mock_{}; + mock_binding::SkeletonMethod skeleton_field_get_binding_mock_{}; }; using GeneratedSkeletonCreationInstanceSpecifierTestFixture = SkeletonCreationFixture; @@ -539,6 +552,8 @@ TEST_F(GeneratedSkeletonCreationInstanceSpecifierTestFixture, std::make_unique>(skeleton_field_binding_mock_); auto skeleton_method_binding_mock_ptr = std::make_unique(skeleton_method_binding_mock_); + auto skeleton_field_set_binding_mock_ptr = + std::make_unique(skeleton_field_set_binding_mock_); // Expecting that valid bindings are created for the Skeleton, SkeletonEvent and SkeletonField EXPECT_CALL(skeleton_binding_factory_mock_guard_.factory_mock_, Create(identifier_with_valid_binding_)) @@ -549,15 +564,8 @@ TEST_F(GeneratedSkeletonCreationInstanceSpecifierTestFixture, EXPECT_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, CreateEventBinding(identifier_with_valid_binding_, _, kFieldName)) .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); - // Field get method binding (not yet fully implemented; set method only exists when EnableSet=true) - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _)) - .Times(1) - .WillOnce(Invoke([this](const InstanceIdentifier&, SkeletonBinding*, const std::string_view, MethodType) - -> std::unique_ptr { - return std::make_unique(skeleton_field_method_binding_mock_); - })); EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, - Create(identifier_with_valid_binding_, _, kMethodName, _)) + Create(identifier_with_valid_binding_, _, kMethodName, MethodType::kMethod)) .WillOnce(Return(ByMove(std::move(skeleton_method_binding_mock_ptr)))); // When constructing a skeleton with an InstanceSpecifier @@ -644,10 +652,8 @@ TEST_F(GeneratedSkeletonCreationInstanceSpecifierTestFixture, RecordProperty("DerivationTechnique", "Analysis of requirements"); // Expecting that the Create call on the SkeletonMethodBindingFactory returns an invalid binding for the method. - // Field get method binding (not yet fully implemented; set method only exists when EnableSet=true) - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _)).Times(1); EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, - Create(identifier_with_valid_binding_, _, kMethodName, _)) + Create(_, _, kMethodName, MethodType::kMethod)) .WillOnce(Return(ByMove(nullptr))); // When constructing a skeleton with an InstanceSpecifier @@ -777,12 +783,8 @@ TEST_F(GeneratedSkeletonCreationInstanceIdentifierTestFixture, ConstructingFromI TEST_F(GeneratedSkeletonCreationInstanceIdentifierTestFixture, ConstructingFromInvalidSkeletonMethodReturnsError) { - // Expecting that the Create call on the SkeletonMethodBindingFactory returns an invalid binding for the method. - // Field get method binding (not yet fully implemented; set method only exists when EnableSet=true) - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _)).Times(1); - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, - Create(identifier_with_valid_binding_, _, kMethodName, _)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kMethod)) .WillOnce(Return(ByMove(nullptr))); // When constructing a skeleton with an InstanceIdentifier @@ -932,15 +934,17 @@ class GeneratedSkeletonStopOfferServiceRaiiFixture : public SkeletonCreationFixt EXPECT_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, CreateEventBinding(_, _, _)) .WillOnce(Return(ByMove( std::make_unique>(skeleton_field_binding_mock_)))); - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kMethod)) .WillOnce( - Return(ByMove(std::make_unique(skeleton_method_binding_mock_)))) - .WillRepeatedly(Invoke([this](const InstanceIdentifier&, - SkeletonBinding*, - const std::string_view, - MethodType) -> std::unique_ptr { - return std::make_unique(skeleton_field_method_binding_mock_); - })); + Return(ByMove(std::make_unique(skeleton_method_binding_mock_)))); + + /// TODO: Enable when the field in MyInterface enables getters / setters + // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kSet)) + // .WillOnce(Return( + // ByMove(std::make_unique(skeleton_field_set_binding_mock_)))); + // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kGet)) + // .WillOnce(Return( + // ByMove(std::make_unique(skeleton_field_get_binding_mock_)))); EXPECT_CALL(skeleton_binding_factory_mock_guard_.factory_mock_, Create(_)) .WillOnce(Return(ByMove(std::make_unique(skeleton_binding_mock_2_)))); @@ -950,15 +954,17 @@ class GeneratedSkeletonStopOfferServiceRaiiFixture : public SkeletonCreationFixt EXPECT_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, CreateEventBinding(_, _, _)) .WillOnce(Return(ByMove( std::make_unique>(skeleton_field_binding_mock_2_)))); - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _)) + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kMethod)) .WillOnce( - Return(ByMove(std::make_unique(skeleton_method_binding_mock_2_)))) - .WillRepeatedly(Invoke([this](const InstanceIdentifier&, - SkeletonBinding*, - const std::string_view, - MethodType) -> std::unique_ptr { - return std::make_unique(skeleton_field_method_binding_mock_); - })); + Return(ByMove(std::make_unique(skeleton_method_binding_mock_2_)))); + + /// TODO: Enable when the field in MyInterface enables getters / setters + // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kSet)) + // .WillOnce(Return( + // ByMove(std::make_unique(skeleton_field_set_binding_mock_2_)))); + // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kGet)) + // .WillOnce(Return( + // ByMove(std::make_unique(skeleton_field_get_binding_mock_2_)))); score::cpp::ignore = skeleton_.emplace(CreateService()); score::cpp::ignore = skeleton_2_.emplace(CreateService()); @@ -997,6 +1003,8 @@ class GeneratedSkeletonStopOfferServiceRaiiFixture : public SkeletonCreationFixt mock_binding::SkeletonEvent skeleton_event_binding_mock_2_{}; mock_binding::SkeletonEvent skeleton_field_binding_mock_2_{}; mock_binding::SkeletonMethod skeleton_method_binding_mock_2_{}; + mock_binding::SkeletonMethod skeleton_field_set_binding_mock_2_{}; + mock_binding::SkeletonMethod skeleton_field_get_binding_mock_2_{}; std::optional skeleton_{}; std::optional skeleton_2_{}; From f5c04673330b3687192ad4b2d06ef5dee7d38416 Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Wed, 29 Apr 2026 17:40:31 +0200 Subject: [PATCH 5/9] mw/com: Rename IsSetHandlerRegistered to IsSetHandlerMissing Previously, IsSetHandlerRegistered would return true even if no handler was registered but the setter was not enabled. The new name is semantically clearer in this case. --- score/mw/com/impl/skeleton_base_test.cpp | 2 +- score/mw/com/impl/skeleton_field.h | 8 ++++---- score/mw/com/impl/skeleton_field_base.h | 9 +++++---- score/mw/com/impl/skeleton_field_base_test.cpp | 8 ++++---- score/mw/com/impl/tracing/skeleton_tracing_test.cpp | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/score/mw/com/impl/skeleton_base_test.cpp b/score/mw/com/impl/skeleton_base_test.cpp index 5f2138b2b..94cf3d901 100644 --- a/score/mw/com/impl/skeleton_base_test.cpp +++ b/score/mw/com/impl/skeleton_base_test.cpp @@ -668,7 +668,7 @@ class DummyField : public SkeletonFieldBase return Result{}; }; - bool IsSetHandlerRegistered() const noexcept override + bool IsSetHandlerMissing() const noexcept override { return false; } diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index 807eedf10..689dc8f55 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -169,13 +169,13 @@ class SkeletonField : public SkeletonFieldBase SkeletonEvent* GetTypedEvent() const noexcept; - bool IsSetHandlerRegistered() const noexcept override + bool IsSetHandlerMissing() const noexcept override { - if constexpr (EnableSet) + if constexpr (!EnableSet) { - return is_set_handler_registered_; + return false; } - return true; + return !is_set_handler_registered_; } std::unique_ptr initial_field_value_; diff --git a/score/mw/com/impl/skeleton_field_base.h b/score/mw/com/impl/skeleton_field_base.h index 0e0097b11..bc765bac0 100644 --- a/score/mw/com/impl/skeleton_field_base.h +++ b/score/mw/com/impl/skeleton_field_base.h @@ -63,8 +63,8 @@ class SkeletonFieldBase if (!was_prepare_offer_called_) { // If the field is configured with a setter, the application must register - // a set handler before calling OfferService(), otherwise Offer() shall fail. - if (!IsSetHandlerRegistered()) + // a set handler via RegisterSetHandler before calling OfferService(), otherwise Offer() shall fail. + if (IsSetHandlerMissing()) { score::mw::log::LogWarn("lola") << "Set handler must be registered before offering field: " << field_name_; @@ -131,8 +131,9 @@ class SkeletonFieldBase /// \brief Returns whether the initial value has been saved by the user to be used by DoDeferredUpdate virtual bool IsInitialValueSaved() const noexcept = 0; - /// \brief Returns whether a set handler has been registered. - virtual bool IsSetHandlerRegistered() const noexcept = 0; + /// \brief Returns true if a setter has been enabled in the interface and a set handler was not registered via + /// RegisterSetHandler. Otherwise, returns false. + virtual bool IsSetHandlerMissing() const noexcept = 0; /// \brief Sets the initial value of the field. /// diff --git a/score/mw/com/impl/skeleton_field_base_test.cpp b/score/mw/com/impl/skeleton_field_base_test.cpp index c43a501cb..7e0808d06 100644 --- a/score/mw/com/impl/skeleton_field_base_test.cpp +++ b/score/mw/com/impl/skeleton_field_base_test.cpp @@ -83,9 +83,9 @@ class MyDummyField : public SkeletonFieldBase return {}; } - bool IsSetHandlerRegistered() const noexcept override + bool IsSetHandlerMissing() const noexcept override { - return true; + return false; } bool was_deferred_update_called_{false}; @@ -100,9 +100,9 @@ class MyDummyFieldFailingDeferredUpdate final : public MyDummyField return MakeUnexpected(ComErrc::kCommunicationLinkError); } - bool IsSetHandlerRegistered() const noexcept override + bool IsSetHandlerMissing() const noexcept override { - return true; + return false; } }; diff --git a/score/mw/com/impl/tracing/skeleton_tracing_test.cpp b/score/mw/com/impl/tracing/skeleton_tracing_test.cpp index f2d395cdb..1beee19e2 100644 --- a/score/mw/com/impl/tracing/skeleton_tracing_test.cpp +++ b/score/mw/com/impl/tracing/skeleton_tracing_test.cpp @@ -77,9 +77,9 @@ class MyDummyField : public SkeletonFieldBase return {}; } - bool IsSetHandlerRegistered() const noexcept override + bool IsSetHandlerMissing() const noexcept override { - return true; + return false; } }; From 29a5ae5cfbc34c3bc7cc941f5912dc8dd3436187 Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Thu, 30 Apr 2026 08:29:48 +0200 Subject: [PATCH 6/9] mw/com: Update SkeletonBase reference in field getter / setter The getter / setter methods don't register themselves with the parent skeleton, rather the field registers itself. Therefore, the field is also responsible for updating the reference to SkeletonBase in the contained methods. --- score/mw/com/impl/skeleton_base_test.cpp | 3 +++ score/mw/com/impl/skeleton_field.h | 23 ++++++++++++++++++- score/mw/com/impl/skeleton_field_base.h | 9 ++++---- .../mw/com/impl/skeleton_field_base_test.cpp | 4 ++++ score/mw/com/impl/skeleton_field_test.cpp | 21 +++++++++++++++++ .../impl/tracing/skeleton_tracing_test.cpp | 2 ++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/score/mw/com/impl/skeleton_base_test.cpp b/score/mw/com/impl/skeleton_base_test.cpp index 94cf3d901..377d63ee0 100644 --- a/score/mw/com/impl/skeleton_base_test.cpp +++ b/score/mw/com/impl/skeleton_base_test.cpp @@ -659,6 +659,9 @@ class DummyField : public SkeletonFieldBase { public: using SkeletonFieldBase::SkeletonFieldBase; + + void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept override {} + bool IsInitialValueSaved() const noexcept override { return false; diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index 689dc8f55..ad9784c18 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -143,7 +143,28 @@ class SkeletonField : public SkeletonFieldBase }; is_set_handler_registered_ = true; - return set_method_.get()->RegisterHandler(std::move(wrapped_callback)); + return set_method_->RegisterHandler(std::move(wrapped_callback)); + } + + /// \brief Updates the reference to SkeletonBase held by this SkeletonField and also the owned methods. + /// + /// This is necessary when a Skeleton (which owns its events, fields and methods) is moved to a new address. When + /// this happens, the references to the SkeletonBase are pointing to the old address and must be updated. This must + /// be done also for the get and set method since they call a SkeletonMethod constructor which does not register + /// them with the SkeletonBase. Rather, they're considered as part of the SkeletonField and it's the field's + /// responsibility to update their SkeletonBase reference when it's moved. + void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept override + { + skeleton_base_ = skeleton_base; + + if (set_method_ != nullptr) + { + set_method_->UpdateSkeletonReference(skeleton_base); + } + if (get_method_ != nullptr) + { + get_method_->UpdateSkeletonReference(skeleton_base); + } } private: diff --git a/score/mw/com/impl/skeleton_field_base.h b/score/mw/com/impl/skeleton_field_base.h index bc765bac0..efe640931 100644 --- a/score/mw/com/impl/skeleton_field_base.h +++ b/score/mw/com/impl/skeleton_field_base.h @@ -50,10 +50,11 @@ class SkeletonFieldBase virtual ~SkeletonFieldBase() = default; - void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept - { - skeleton_base_ = skeleton_base; - } + /// \brief Updates the reference to SkeletonBase held by the SkeletonField and also the owned methods. + /// + /// This must happen in the derived class since the derived class owns the methods (this is required since they are + /// templated with the FieldType, which SkeletonFieldBase doesn't know). + virtual void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept = 0; /// \brief Used to indicate that the field shall be available to consumer (e.g. binding specific preparation) Result PrepareOffer() noexcept diff --git a/score/mw/com/impl/skeleton_field_base_test.cpp b/score/mw/com/impl/skeleton_field_base_test.cpp index 7e0808d06..a141d7e36 100644 --- a/score/mw/com/impl/skeleton_field_base_test.cpp +++ b/score/mw/com/impl/skeleton_field_base_test.cpp @@ -64,6 +64,8 @@ class MyDummyField : public SkeletonFieldBase { } + void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept override {} + StrictMock* GetMockEventBinding() noexcept { auto* const skeleton_field_base_binding = SkeletonFieldBaseView{*this}.GetEventBinding(); @@ -95,6 +97,8 @@ class MyDummyField : public SkeletonFieldBase class MyDummyFieldFailingDeferredUpdate final : public MyDummyField { public: + void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept override {} + Result DoDeferredUpdate() noexcept override { return MakeUnexpected(ComErrc::kCommunicationLinkError); diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index 5228c9123..a923e1703 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -1285,5 +1285,26 @@ TEST_F(SkeletonFieldSetHandlerTest, SecondRegisterSetHandlerReplacesHandler) EXPECT_TRUE(second_callback_called); } +using SkeletonFieldMoveConstructionFixture = SkeletonFieldTestFixture; +TEST_F(SkeletonFieldMoveConstructionFixture, SecondRegisterSetHandlerReplacesHandler) +{ + // Note. This test verifies that moving a skeleton does not break the getter / setter methods stored within a field. + // When moving, UpdateSkeletonReference must update the references to SkeletonBase in the field instance as well as + // the stored methods. However, the SkeletonBase reference in the methods are only used when moving the method (to + // update the reference to the method in SkeletonBase). Since the methods are stored in the field as unique_ptrs, + // they will never actually be moved. Therefore, with the current implementation, the SkeletonBase reference in the + // getter and setter are never used and so we have no way of ensuring that they are updated correctly. We can only + // verify that the method is still valid after move construction. + + // Given a skeleton containing a field with a setter enabled + MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; + + // When move constructing the skeleton + MySetterSkeleton unit2{std::move(unit)}; + + // Then the method should still be usable (validated by calling RegisterSetHandler which dispatches to the method) + unit2.my_setter_field_.RegisterSetHandler([](TestSampleType& /*value*/) noexcept {}); +} + } // namespace } // namespace score::mw::com::impl diff --git a/score/mw/com/impl/tracing/skeleton_tracing_test.cpp b/score/mw/com/impl/tracing/skeleton_tracing_test.cpp index 1beee19e2..e987fc35f 100644 --- a/score/mw/com/impl/tracing/skeleton_tracing_test.cpp +++ b/score/mw/com/impl/tracing/skeleton_tracing_test.cpp @@ -67,6 +67,8 @@ class MyDummyField : public SkeletonFieldBase { } + void UpdateSkeletonReference(SkeletonBase& skeleton_base) noexcept override {} + bool IsInitialValueSaved() const noexcept override { return true; From 493971338eec126a5c73ef9123de68d1174f70ec Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Thu, 30 Apr 2026 15:17:51 +0200 Subject: [PATCH 7/9] mw/com: Enable setter in traits_test We pass true for the setter flag to test the creation of the setter method binding in traits_test. Currently, this also creates the getter method binding. In future, this will be enabled via a template parameter. --- score/mw/com/impl/traits_test.cpp | 53 ++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/score/mw/com/impl/traits_test.cpp b/score/mw/com/impl/traits_test.cpp index d10205aba..f99961ee5 100644 --- a/score/mw/com/impl/traits_test.cpp +++ b/score/mw/com/impl/traits_test.cpp @@ -68,7 +68,7 @@ class MyInterface : public InterfaceTrait::Base using InterfaceTrait::Base::Base; typename InterfaceTrait::template Event some_event{*this, kEventName}; - typename InterfaceTrait::template Field some_field{*this, kFieldName}; + typename InterfaceTrait::template Field some_field{*this, kFieldName}; typename InterfaceTrait::template Method some_method{*this, kMethodName}; }; using MyProxy = AsProxy; @@ -97,7 +97,6 @@ class ProxyCreationFixture : public ::testing::Test public: void SetUp() override { - auto proxy_binding_mock_ptr = std::make_unique(proxy_binding_mock_); auto proxy_event_binding_mock_ptr = std::make_unique>(proxy_event_binding_mock_); @@ -554,6 +553,8 @@ TEST_F(GeneratedSkeletonCreationInstanceSpecifierTestFixture, std::make_unique(skeleton_method_binding_mock_); auto skeleton_field_set_binding_mock_ptr = std::make_unique(skeleton_field_set_binding_mock_); + auto skeleton_field_get_binding_mock_ptr = + std::make_unique(skeleton_field_get_binding_mock_); // Expecting that valid bindings are created for the Skeleton, SkeletonEvent and SkeletonField EXPECT_CALL(skeleton_binding_factory_mock_guard_.factory_mock_, Create(identifier_with_valid_binding_)) @@ -564,6 +565,12 @@ TEST_F(GeneratedSkeletonCreationInstanceSpecifierTestFixture, EXPECT_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, CreateEventBinding(identifier_with_valid_binding_, _, kFieldName)) .WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr)))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kSet)) + .WillOnce(Return(ByMove(std::move(skeleton_field_set_binding_mock_ptr)))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kGet)) + .WillOnce(Return(ByMove(std::move(skeleton_field_get_binding_mock_ptr)))); EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(identifier_with_valid_binding_, _, kMethodName, MethodType::kMethod)) .WillOnce(Return(ByMove(std::move(skeleton_method_binding_mock_ptr)))); @@ -655,6 +662,10 @@ TEST_F(GeneratedSkeletonCreationInstanceSpecifierTestFixture, EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, kMethodName, MethodType::kMethod)) .WillOnce(Return(ByMove(nullptr))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kSet)); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kGet)); // When constructing a skeleton with an InstanceSpecifier const auto unit = MySkeleton::Create(kInstanceSpecifier); @@ -786,6 +797,10 @@ TEST_F(GeneratedSkeletonCreationInstanceIdentifierTestFixture, ConstructingFromI // Expecting that the Create call on the SkeletonMethodBindingFactory returns an invalid binding for the method. EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kMethod)) .WillOnce(Return(ByMove(nullptr))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kSet)); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, + Create(identifier_with_valid_binding_, _, kFieldName, MethodType::kGet)); // When constructing a skeleton with an InstanceIdentifier const auto unit = MySkeleton::Create(identifier_with_valid_binding_); @@ -845,6 +860,9 @@ TEST_F(GeneratedSkeletonCreationInstanceIdentifierTestFixture, CanInterpretAsSke // and updating the field value std::ignore = unit.some_field.Update(field_value); + // and registering a field set handler + unit.some_field.RegisterSetHandler([](TestSampleType&) {}); + // and offering the service const auto result = unit.OfferService(); EXPECT_TRUE(result.has_value()); @@ -909,6 +927,9 @@ class GeneratedSkeletonStopOfferServiceRaiiFixture : public SkeletonCreationFixt const auto update_result = skeleton.some_field.Update(field_value); ASSERT_TRUE(update_result.has_value()); + const auto register_result = skeleton.some_field.RegisterSetHandler([](TestSampleType&) {}); + ASSERT_TRUE(register_result.has_value()); + const auto offer_result = skeleton.OfferService(); ASSERT_TRUE(offer_result.has_value()); } @@ -934,18 +955,16 @@ class GeneratedSkeletonStopOfferServiceRaiiFixture : public SkeletonCreationFixt EXPECT_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, CreateEventBinding(_, _, _)) .WillOnce(Return(ByMove( std::make_unique>(skeleton_field_binding_mock_)))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kSet)) + .WillOnce( + Return(ByMove(std::make_unique(skeleton_field_set_binding_mock_)))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kGet)) + .WillOnce( + Return(ByMove(std::make_unique(skeleton_field_get_binding_mock_)))); EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kMethod)) .WillOnce( Return(ByMove(std::make_unique(skeleton_method_binding_mock_)))); - /// TODO: Enable when the field in MyInterface enables getters / setters - // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kSet)) - // .WillOnce(Return( - // ByMove(std::make_unique(skeleton_field_set_binding_mock_)))); - // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kGet)) - // .WillOnce(Return( - // ByMove(std::make_unique(skeleton_field_get_binding_mock_)))); - EXPECT_CALL(skeleton_binding_factory_mock_guard_.factory_mock_, Create(_)) .WillOnce(Return(ByMove(std::make_unique(skeleton_binding_mock_2_)))); EXPECT_CALL(skeleton_event_binding_factory_mock_guard_.factory_mock_, Create(_, _, _)) @@ -954,18 +973,16 @@ class GeneratedSkeletonStopOfferServiceRaiiFixture : public SkeletonCreationFixt EXPECT_CALL(skeleton_field_binding_factory_mock_guard_.factory_mock_, CreateEventBinding(_, _, _)) .WillOnce(Return(ByMove( std::make_unique>(skeleton_field_binding_mock_2_)))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kSet)) + .WillOnce(Return( + ByMove(std::make_unique(skeleton_field_set_binding_mock_2_)))); + EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kGet)) + .WillOnce(Return( + ByMove(std::make_unique(skeleton_field_get_binding_mock_2_)))); EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kMethod)) .WillOnce( Return(ByMove(std::make_unique(skeleton_method_binding_mock_2_)))); - /// TODO: Enable when the field in MyInterface enables getters / setters - // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kSet)) - // .WillOnce(Return( - // ByMove(std::make_unique(skeleton_field_set_binding_mock_2_)))); - // EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, MethodType::kGet)) - // .WillOnce(Return( - // ByMove(std::make_unique(skeleton_field_get_binding_mock_2_)))); - score::cpp::ignore = skeleton_.emplace(CreateService()); score::cpp::ignore = skeleton_2_.emplace(CreateService()); From 90cb10d4c97d4027f55a6e1b166ab10da2a6b47b Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Thu, 30 Apr 2026 16:10:12 +0200 Subject: [PATCH 8/9] mw/com: Clean up skeleton field tests - Extracts constants into global constant. - Removes EXPECT_CALLS which are not part of the expectations of the test. - Cleans up some given / when / then comments --- score/mw/com/impl/skeleton_field_test.cpp | 165 +++++++--------------- 1 file changed, 51 insertions(+), 114 deletions(-) diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index a923e1703..9175f5f9f 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -12,6 +12,7 @@ ********************************************************************************/ #include "score/mw/com/impl/skeleton_field.h" +#include "method_type.h" #include "score/mw/com/impl/bindings/mock_binding/skeleton_method.h" #include "score/mw/com/impl/method_type.h" #include "score/mw/com/impl/methods/skeleton_method.h" @@ -48,6 +49,7 @@ using ::testing::StrictMock; using ::testing::WithArg; constexpr std::string_view kFieldName{"Field1"}; +const TestSampleType kDummyInitialValue{42}; ServiceIdentifierType kServiceIdentifier{make_ServiceIdentifierType("foo", 1U, 0U)}; std::uint16_t kInstanceId{23U}; @@ -91,6 +93,8 @@ class SkeletonFieldTestFixture : public ::testing::Test .WillByDefault(InvokeWithoutArgs([this]() { return std::make_unique(skeleton_field_set_binding_mock_); })); + + ON_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillByDefault(Return(Result{})); } RuntimeMockGuard runtime_mock_guard_{}; @@ -159,14 +163,13 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServiceDefersCallToO RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; bool is_send_called_on_binding{false}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)) .WillOnce(InvokeWithoutArgs([&is_send_called_on_binding]() noexcept -> Result { is_send_called_on_binding = true; return {}; @@ -176,7 +179,7 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServiceDefersCallToO MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // then it does not return an error ASSERT_TRUE(update_result.has_value()); @@ -205,14 +208,13 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServicePropagatesBin RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; bool is_send_called_on_binding{false}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an error - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)) + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)) .WillOnce(InvokeWithoutArgs([&is_send_called_on_binding] { is_send_called_on_binding = true; return MakeUnexpected(ComErrc::kInvalidBindingInformation); @@ -222,7 +224,7 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateBeforeOfferServicePropagatesBin MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // then it does not return an error ASSERT_TRUE(update_result.has_value()); @@ -249,14 +251,13 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServiceDispatchesToBi RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - const TestSampleType updated_value{43}; + const TestSampleType updated_value{kDummyInitialValue + 1U}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)).WillOnce(Return(score::Result{})); // and Send will be called a second time on the event binding with the updated value and returns an empty result EXPECT_CALL(skeleton_field_binding_mock_, Send(updated_value, _)).WillOnce(Return(score::Result{})); @@ -265,7 +266,7 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServiceDispatchesToBi MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // then it does not return an error ASSERT_TRUE(update_result.has_value()); @@ -293,14 +294,13 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServicePropagatesBind RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - const TestSampleType updated_value{43}; + const TestSampleType updated_value{kDummyInitialValue + 1U}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value and returns an empty result - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(score::Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)).WillOnce(Return(score::Result{})); // and Send will be called a second time on the event binding with the updated value and returns an error EXPECT_CALL(skeleton_field_binding_mock_, Send(updated_value, _)) @@ -310,7 +310,7 @@ TEST_F(SkeletonFieldCopyUpdateTest, CallingUpdateAfterOfferServicePropagatesBind MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // then it does not return an error ASSERT_TRUE(update_result.has_value()); @@ -334,7 +334,6 @@ using SkeletonFieldAllocateTest = SkeletonFieldTestFixture; TEST_F(SkeletonFieldAllocateTest, CallingAllocateBeforePrepareOfferDoesNotReturnValidSlot) { - // and that PrepareOffer() will not be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).Times(0); @@ -360,13 +359,11 @@ TEST_F(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferDispatchesToBi RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)); // and Allocate will be called again which returns a valid SampleAllocateePtr EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) @@ -376,7 +373,7 @@ TEST_F(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferDispatchesToBi MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -403,13 +400,11 @@ TEST_F(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferFailsWhenBindi RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)); // and Allocate will be called again which returns a nullptr EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) @@ -419,7 +414,7 @@ TEST_F(SkeletonFieldAllocateTest, CallingAllocateAfterPrepareOfferFailsWhenBindi MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -449,14 +444,13 @@ TEST_F(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceDi RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - const TestSampleType new_value{52}; + const TestSampleType new_value{kDummyInitialValue + 1U}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)); // and Allocate will be called again which returns a valid SampleAllocateePtr EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) @@ -473,7 +467,7 @@ TEST_F(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServiceDi MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -512,14 +506,13 @@ TEST_F(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServicePr RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - const TestSampleType new_value{52}; + const TestSampleType new_value{kDummyInitialValue + 1U}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)); // and Allocate will be called again which returns a valid SampleAllocateePtr EXPECT_CALL(skeleton_field_binding_mock_, Allocate()) @@ -536,7 +529,7 @@ TEST_F(SkeletonFieldZeroCopyUpdateTest, CallingZeroCopyUpdateAfterOfferServicePr MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -575,8 +568,7 @@ TEST_F(SkeletonFieldInitialValueFixture, LatestFieldValueWillBeSetOnPrepareOffer RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{42}; - const TestSampleType latest_value{43}; + const TestSampleType latest_value{kDummyInitialValue + 1U}; // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); @@ -588,7 +580,7 @@ TEST_F(SkeletonFieldInitialValueFixture, LatestFieldValueWillBeSetOnPrepareOffer MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -632,19 +624,17 @@ TEST_F(SkeletonFieldInitialValueFixture, OfferingFieldBeforeUpdatingValueReturns TEST_F(SkeletonFieldInitialValueFixture, MoveConstructingFieldBeforePrepareOfferWillKeepInitialValue) { - const TestSampleType initial_value{42}; - // and that PrepareOffer() will be called on the event binding EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -661,8 +651,7 @@ TEST_F(SkeletonFieldInitialValueFixture, MoveConstructingFieldBeforePrepareOffer TEST(SkeletonFieldInitialValueTest, MoveAssigningFieldBeforePrepareOfferWillKeepInitialValue) { - const TestSampleType initial_value{42}; - const TestSampleType initial_value_2{43}; + const TestSampleType kDummyInitialValue_2{kDummyInitialValue + 1U}; RuntimeMockGuard runtime_mock_guard{}; ON_CALL(runtime_mock_guard.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); @@ -682,13 +671,13 @@ TEST(SkeletonFieldInitialValueTest, MoveAssigningFieldBeforePrepareOfferWillKeep EXPECT_CALL(skeleton_field_binding_mock, PrepareOffer()).WillOnce(Return(score::Result{})); // and Send will be called on the event binding with the initial value from the moved-from field - EXPECT_CALL(skeleton_field_binding_mock, Send(initial_value, _)); + EXPECT_CALL(skeleton_field_binding_mock, Send(kDummyInitialValue, _)); // Given a skeleton created based on a Lola binding MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When the initial value is set via an Update call - const auto update_result = unit.my_dummy_field_.Update(initial_value); + const auto update_result = unit.my_dummy_field_.Update(kDummyInitialValue); // which does not return an error EXPECT_TRUE(update_result.has_value()); @@ -712,7 +701,7 @@ TEST(SkeletonFieldInitialValueTest, MoveAssigningFieldBeforePrepareOfferWillKeep MyDummySkeleton unit_2{std::make_unique(), identifier2}; // When the initial value is set via an Update call - const auto update_result_2 = unit_2.my_dummy_field_.Update(initial_value_2); + const auto update_result_2 = unit_2.my_dummy_field_.Update(kDummyInitialValue_2); // which does not return an error EXPECT_TRUE(update_result_2.has_value()); @@ -832,6 +821,7 @@ class MySetterSkeleton : public SkeletonBase SkeletonField my_setter_field_{*this, kFieldName}; }; +/// gtodo: What is this test testing?? TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerOnlyExistsWhenEnableSetIsTrue) { RecordProperty("Description", @@ -855,18 +845,10 @@ using SkeletonFieldSetHandlerTest = SkeletonFieldTestFixture; TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) { - RecordProperty("Description", - "Calling RegisterSetHandler() on an EnableSet=true SkeletonField shall forward " - "the handler registration to the underlying SkeletonMethod binding and return " - "success."); - RecordProperty("TestType", "Requirements-based test"); - RecordProperty("Priority", "1"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); - - // The method binding's RegisterHandler must be called exactly once and returns success. + // Expecting that RegisterHandler is called on the field set method binding which returns success EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillOnce(Return(Result{})); - // Given a setter-capable skeleton + // Given a skeleton containing a field with a setter enabled MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When RegisterSetHandler is called with a valid (no-op) handler @@ -878,17 +860,11 @@ TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerForwardsToMethodBinding) TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) { - RecordProperty("Description", - "When the underlying SkeletonMethod binding returns an error from RegisterHandler, " - "RegisterSetHandler() shall propagate that error unchanged."); - RecordProperty("TestType", "Requirements-based test"); - RecordProperty("Priority", "1"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); - - // The method binding returns an error + // Expecting that RegisterHandler is called on the field set method binding which returns an error EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)) .WillOnce(Return(MakeUnexpected(ComErrc::kCommunicationLinkError))); + // Given a skeleton containing a field with a setter enabled MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // When RegisterSetHandler is called @@ -901,21 +877,10 @@ TEST_F(SkeletonFieldSetHandlerTest, RegisterSetHandlerPropagatesBindingError) TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered) { - RecordProperty("Verifies", "SCR-17563743"); - RecordProperty("Description", - "When a SkeletonField is defined with EnableSet=true and no set handler has been " - "registered, PrepareOffer() shall return kSetHandlerNotSet."); - RecordProperty("TestType", "Requirements-based test"); - RecordProperty("Priority", "1"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); - - EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(kInstanceIdWithLolaBinding, _, _, _)) - .WillOnce(Return(ByMove(nullptr))) - .WillOnce(Return(ByMove(nullptr))); - + // Given a skeleton containing a field with a setter enabled MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; - // Set an initial value so that the initial-value check does not fire first + // and given an initial value was set so that the initial-value check does not fail EXPECT_TRUE(unit.my_setter_field_.Update(TestSampleType{42}).has_value()); // When PrepareOffer is called without having called RegisterSetHandler @@ -928,29 +893,16 @@ TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferFailsWhenSetHandlerNotRegistered TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) { - RecordProperty("Description", - "When an EnableSet=true SkeletonField has a set handler registered and an initial " - "value set, PrepareOffer() shall succeed."); - RecordProperty("TestType", "Requirements-based test"); - RecordProperty("Priority", "1"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); - - const TestSampleType initial_value{7U}; - - // The binding's RegisterHandler returns success - EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillOnce(Return(Result{})); - - // PrepareOffer on the event binding and the initial-value Send must succeed - EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(Result{})); + const TestSampleType kDummyInitialValue{7U}; + // Given a skeleton containing a field with a setter enabled MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // Register a valid (no-op) set handler ASSERT_TRUE(unit.my_setter_field_.RegisterSetHandler([](TestSampleType& /*value*/) noexcept {}).has_value()); // Set the initial field value - ASSERT_TRUE(unit.my_setter_field_.Update(initial_value).has_value()); + ASSERT_TRUE(unit.my_setter_field_.Update(kDummyInitialValue).has_value()); // When PrepareOffer is called const auto result = unit.my_setter_field_.PrepareOffer(); @@ -961,28 +913,19 @@ TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsAfterRegisterSetHandler) TEST_F(SkeletonFieldSetHandlerTest, PrepareOfferSucceedsWithoutHandlerWhenEnableSetIsFalse) { - RecordProperty("Description", - "When a SkeletonField has EnableSet=false (no setter), PrepareOffer() shall " - "succeed without registering a set handler."); - RecordProperty("TestType", "Requirements-based test"); - RecordProperty("Priority", "1"); - RecordProperty("DerivationTechnique", "Analysis of requirements"); - - const TestSampleType initial_value{5U}; - - EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(Result{})); - - // A non-setter skeleton (EnableSet=false) + // Given a skeleton containing a field without a setter enabled MyDummySkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; - ASSERT_TRUE(unit.my_dummy_field_.Update(initial_value).has_value()); + ASSERT_TRUE(unit.my_dummy_field_.Update(kDummyInitialValue).has_value()); - // PrepareOffer must succeed even without a RegisterSetHandler call + // When PrepareOffer is called without registering a set handler const auto result = unit.my_dummy_field_.PrepareOffer(); + + // Then it succeeds EXPECT_TRUE(result.has_value()); } +// gtodo: What is this testing??? TEST(SkeletonFieldSetHandlerTypeTraitsTest, RegisterSetHandlerAcceptsAnyCallable) { RecordProperty("Description", @@ -1032,12 +975,6 @@ TEST_F(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) const TestSampleType incoming_value{99U}; bool user_callback_called{false}; - // PrepareOffer and the deferred Send for the initial value - EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(skeleton_field_binding_mock_, Send(TestSampleType{1U}, _)).WillOnce(Return(Result{})); - // The wrapped handler also calls Update(incoming_value) → Send on the event binding - EXPECT_CALL(skeleton_field_binding_mock_, Send(incoming_value, _)).WillOnce(Return(Result{})); - // Use a capturing binding so that we can invoke the type-erased handler later auto capturing_binding = std::make_unique(); auto& capturing_binding_ref = *capturing_binding; @@ -1198,17 +1135,17 @@ TEST_F(SkeletonFieldSetHandlerTest, IsSetHandlerRegisteredFlagIsSetAfterRegistra RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - const TestSampleType initial_value{3U}; + const TestSampleType kDummyInitialValue{3U}; EXPECT_CALL(skeleton_field_binding_mock_, PrepareOffer()).WillOnce(Return(Result{})); - EXPECT_CALL(skeleton_field_binding_mock_, Send(initial_value, _)).WillOnce(Return(Result{})); + EXPECT_CALL(skeleton_field_binding_mock_, Send(kDummyInitialValue, _)).WillOnce(Return(Result{})); EXPECT_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillOnce(Return(Result{})); MySetterSkeleton unit{std::make_unique(), kInstanceIdWithLolaBinding}; // Before registration PrepareOffer should fail with kSetHandlerNotSet - ASSERT_TRUE(unit.my_setter_field_.Update(initial_value).has_value()); + ASSERT_TRUE(unit.my_setter_field_.Update(kDummyInitialValue).has_value()); { // Separate scope: verify failure without handler // (We cannot call PrepareOffer twice without a stop-offer in between, so we From df70c322cd725952084e86bf4f5108b2d7e5a68f Mon Sep 17 00:00:00 2001 From: Brendan Emery Date: Thu, 30 Apr 2026 16:58:02 +0200 Subject: [PATCH 9/9] mw/com: Extract duplicate code into function --- score/mw/com/impl/skeleton_field_test.cpp | 50 +++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index 9175f5f9f..c62242ac3 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -97,6 +97,24 @@ class SkeletonFieldTestFixture : public ::testing::Test ON_CALL(skeleton_field_set_binding_mock_, RegisterHandler(_)).WillByDefault(Return(Result{})); } + /// \brief Returns a span pointing to storage containing the provided field value + std::pair, score::cpp::span> CreateFieldSetterInArgAndReturnSpans( + const TestSampleType in_arg_value, + const TestSampleType return_value) + { + SCORE_LANGUAGE_FUTURECPP_ASSERT(!in_arg_storage_.has_value()); + SCORE_LANGUAGE_FUTURECPP_ASSERT(!return_storage_.has_value()); + score::cpp::ignore = in_arg_storage_.emplace(in_arg_value); + score::cpp::ignore = return_storage_.emplace(return_value); + + score::cpp::span in_span{reinterpret_cast(&(in_arg_storage_.value())), + sizeof(TestSampleType)}; + score::cpp::span out_span{reinterpret_cast(&(return_storage_.value())), + sizeof(TestSampleType)}; + + return {in_span, out_span}; + } + RuntimeMockGuard runtime_mock_guard_{}; SkeletonFieldBindingFactoryMockGuard skeleton_field_binding_factory_mock_guard_{}; @@ -105,6 +123,9 @@ class SkeletonFieldTestFixture : public ::testing::Test mock_binding::SkeletonEvent skeleton_field_binding_mock_{}; mock_binding::SkeletonMethod skeleton_field_get_binding_mock_{}; mock_binding::SkeletonMethod skeleton_field_set_binding_mock_{}; + + std::optional in_arg_storage_{}; + std::optional return_storage_{}; }; TEST(SkeletonFieldTest, NotCopyable) @@ -1003,13 +1024,7 @@ TEST_F(SkeletonFieldSetHandlerTest, UserCallbackIsInvokedByWrappedHandler) // Simulate the proxy invoking the setter by calling the captured type-erased handler. // The SkeletonMethod serializes the incoming value into a byte span before dispatch. // We replicate that serialization here for the single TestSampleType argument. - using InArgStorage = TestSampleType; - InArgStorage in_arg{incoming_value}; - TestSampleType return_storage{}; - std::optional> in_span{ - score::cpp::span{reinterpret_cast(&in_arg), sizeof(InArgStorage)}}; - std::optional> out_span{ - score::cpp::span{reinterpret_cast(&return_storage), sizeof(TestSampleType)}}; + auto [in_span, out_span] = CreateFieldSetterInArgAndReturnSpans(incoming_value, TestSampleType{}); capturing_binding_ref.captured_handler_(in_span, out_span); @@ -1059,12 +1074,7 @@ TEST_F(SkeletonFieldSetHandlerTest, UserCallbackCanModifyValueInPlace) ASSERT_TRUE(unit.my_setter_field_.PrepareOffer().has_value()); // Invoke the wrapped handler with incoming_value (10) - TestSampleType in_arg{incoming_value}; - TestSampleType return_storage{}; - std::optional> in_span{ - score::cpp::span{reinterpret_cast(&in_arg), sizeof(in_arg)}}; - std::optional> out_span{ - score::cpp::span{reinterpret_cast(&return_storage), sizeof(TestSampleType)}}; + auto [in_span, out_span] = CreateFieldSetterInArgAndReturnSpans(incoming_value, TestSampleType{}); // The handler shall call Send with 20, not 10 capturing_binding_ref.captured_handler_(in_span, out_span); @@ -1112,12 +1122,7 @@ TEST_F(SkeletonFieldSetHandlerTest, WrappedHandlerLogsWhenUpdateFails) ASSERT_TRUE(unit.my_setter_field_.Update(TestSampleType{1U}).has_value()); ASSERT_TRUE(unit.my_setter_field_.PrepareOffer().has_value()); - TestSampleType in_arg{incoming_value}; - TestSampleType return_storage{}; - std::optional> in_span{ - score::cpp::span{reinterpret_cast(&in_arg), sizeof(in_arg)}}; - std::optional> out_span{ - score::cpp::span{reinterpret_cast(&return_storage), sizeof(TestSampleType)}}; + auto [in_span, out_span] = CreateFieldSetterInArgAndReturnSpans(incoming_value, TestSampleType{}); // Handler must complete normally even when Update() returns an error capturing_binding_ref.captured_handler_(in_span, out_span); @@ -1208,12 +1213,7 @@ TEST_F(SkeletonFieldSetHandlerTest, SecondRegisterSetHandlerReplacesHandler) ASSERT_TRUE(unit.my_setter_field_.PrepareOffer().has_value()); // Invoke the most-recently captured handler (from the second registration) - TestSampleType in_arg{incoming_value}; - TestSampleType return_storage{}; - std::optional> in_span{ - score::cpp::span{reinterpret_cast(&in_arg), sizeof(in_arg)}}; - std::optional> out_span{ - score::cpp::span{reinterpret_cast(&return_storage), sizeof(TestSampleType)}}; + auto [in_span, out_span] = CreateFieldSetterInArgAndReturnSpans(incoming_value, TestSampleType{}); capturing_binding_ref.captured_handler_(in_span, out_span);