From 18d4ada8d031fc53e692f3b307a221dd1c60314c Mon Sep 17 00:00:00 2001 From: Krishna Date: Fri, 24 Apr 2026 18:14:13 +0200 Subject: [PATCH 1/3] mw/com: add unit tests for MethodType Add unit tests for to_string(MethodType), covering kMethod/kGet/kSet/kUnknown and the out-of-range "Invalid" fallback. --- score/mw/com/impl/BUILD | 9 ++++ score/mw/com/impl/method_type_test.cpp | 65 ++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 score/mw/com/impl/method_type_test.cpp diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index 8172c3dee..149650e1e 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -1176,6 +1176,15 @@ cc_unit_test( ], ) +cc_unit_test( + name = "method_type_test", + srcs = ["method_type_test.cpp"], + features = COMPILER_WARNING_FEATURES, + deps = [ + ":method_type", + ], +) + cc_unit_test( name = "sample_reference_tracker_test", srcs = ["sample_reference_tracker_test.cpp"], diff --git a/score/mw/com/impl/method_type_test.cpp b/score/mw/com/impl/method_type_test.cpp new file mode 100644 index 000000000..9558fe360 --- /dev/null +++ b/score/mw/com/impl/method_type_test.cpp @@ -0,0 +1,65 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#include "score/mw/com/impl/method_type.h" + +#include + +namespace score::mw::com::impl +{ +namespace +{ + +TEST(MethodTypeToStringTest, ReturnsMethodForKMethod) +{ + // Given a MethodType of kMethod + // When converting to string + // Then the result is "Method" + EXPECT_EQ(to_string(MethodType::kMethod), "Method"); +} + +TEST(MethodTypeToStringTest, ReturnsGetForKGet) +{ + // Given a MethodType of kGet + // When converting to string + // Then the result is "Get" + EXPECT_EQ(to_string(MethodType::kGet), "Get"); +} + +TEST(MethodTypeToStringTest, ReturnsSetForKSet) +{ + // Given a MethodType of kSet + // When converting to string + // Then the result is "Set" + EXPECT_EQ(to_string(MethodType::kSet), "Set"); +} + +TEST(MethodTypeToStringTest, ReturnsUnknownForKUnknown) +{ + // Given a MethodType of kUnknown + // When converting to string + // Then the result is "Unknown" + EXPECT_EQ(to_string(MethodType::kUnknown), "Unknown"); +} + +TEST(MethodTypeToStringTest, ReturnsInvalidForOutOfRangeValue) +{ + // Given an out-of-range MethodType value + const auto invalid_value = static_cast(255); + + // When converting to string + // Then the result is "Invalid" + EXPECT_EQ(to_string(invalid_value), "Invalid"); +} + +} // namespace +} // namespace score::mw::com::impl From 237a949823e0fd31f88b9194a695f5133c58d6e1 Mon Sep 17 00:00:00 2001 From: Krishna Satish Deshkulkarni Shankaranarayana Date: Mon, 1 Jun 2026 19:54:11 +0200 Subject: [PATCH 2/3] mw/com: add ProxyField Get/Set behavioral tests --- score/mw/com/impl/BUILD | 2 + score/mw/com/impl/proxy_field_test.cpp | 121 +++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index 149650e1e..ca50f3a68 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -1252,9 +1252,11 @@ cc_unit_test( deps = [ ":impl", ":runtime_mock", + "//score/mw/com/impl/bindings/mock_binding", "//score/mw/com/impl/plumbing:proxy_field_binding_factory_mock", "//score/mw/com/impl/test:binding_factory_resources", "//score/mw/com/impl/test:proxy_resources", + "//score/mw/com/impl/test:runtime_mock_guard", ], ) diff --git a/score/mw/com/impl/proxy_field_test.cpp b/score/mw/com/impl/proxy_field_test.cpp index c33fec6f2..6a65e0554 100644 --- a/score/mw/com/impl/proxy_field_test.cpp +++ b/score/mw/com/impl/proxy_field_test.cpp @@ -19,13 +19,21 @@ #include "score/mw/com/impl/proxy_field.h" +#include "score/mw/com/impl/bindings/mock_binding/proxy_event.h" +#include "score/mw/com/impl/bindings/mock_binding/proxy_method.h" +#include "score/mw/com/impl/com_error.h" #include "score/mw/com/impl/runtime.h" #include "score/mw/com/impl/runtime_mock.h" #include "score/mw/com/impl/test/binding_factory_resources.h" #include "score/mw/com/impl/test/proxy_resources.h" +#include "score/mw/com/impl/test/runtime_mock_guard.h" #include #include +#include +#include +#include +#include #include namespace score::mw::com::impl @@ -330,5 +338,118 @@ TEST(ProxyFieldNotifierGatingTest, OnlyNotifierApiExistsWhenNoTagsArePresent) static_assert(!has_set::value); } +/// \brief Test fixture for the runtime behavior of ProxyField's Get / Set API. +class ProxyFieldGetSetFixture : public ::testing::Test +{ + public: + void SetUp() override + { + ON_CALL(runtime_mock_guard_.runtime_mock_, GetTracingFilterConfig()).WillByDefault(Return(nullptr)); + + ON_CALL(get_method_binding_mock_, GetReturnValueBuffer(0)) + .WillByDefault(Return(score::Result>{ + score::cpp::span{return_type_buffer_.data(), return_type_buffer_.size()}})); + ON_CALL(get_method_binding_mock_, GetInArgsBuffer(0)) + .WillByDefault(Return(score::Result>{ + score::cpp::span{in_args_buffer_.data(), in_args_buffer_.size()}})); + ON_CALL(get_method_binding_mock_, DoCall(0)).WillByDefault(Return(score::ResultBlank{})); + + ON_CALL(set_method_binding_mock_, GetReturnValueBuffer(0)) + .WillByDefault(Return(score::Result>{ + score::cpp::span{return_type_buffer_.data(), return_type_buffer_.size()}})); + ON_CALL(set_method_binding_mock_, GetInArgsBuffer(0)) + .WillByDefault(Return(score::Result>{ + score::cpp::span{in_args_buffer_.data(), in_args_buffer_.size()}})); + ON_CALL(set_method_binding_mock_, DoCall(0)).WillByDefault(Return(score::ResultBlank{})); + } + + ProxyField CreateFieldWithGetOnly(const std::string_view name = "TestField") + { + return ProxyField{ + name, + std::make_unique>(proxy_event_mock_), + nullptr, + std::make_unique(get_method_binding_mock_)}; + } + + ProxyField CreateFieldWithSetAndNotifier( + const std::string_view name = "TestField") + { + return ProxyField{ + name, + std::make_unique>(proxy_event_mock_), + std::make_unique(set_method_binding_mock_)}; + } + + alignas(8) std::array return_type_buffer_{}; + alignas(8) std::array in_args_buffer_{}; + RuntimeMockGuard runtime_mock_guard_{}; + mock_binding::ProxyEvent proxy_event_mock_{}; + mock_binding::ProxyMethod get_method_binding_mock_{}; + mock_binding::ProxyMethod set_method_binding_mock_{}; +}; + +TEST_F(ProxyFieldGetSetFixture, GetDelegatesToProxyMethodBinding) +{ + // Given a Get-enabled ProxyField and a mock method binding + auto field = CreateFieldWithGetOnly(); + EXPECT_CALL(get_method_binding_mock_, GetReturnValueBuffer(0U)); + EXPECT_CALL(get_method_binding_mock_, DoCall(0U)); + + // When calling Get() + auto result = field.Get(); + + // Then the call is delegated to the underlying method binding and succeeds + EXPECT_TRUE(result.has_value()); +} + +TEST_F(ProxyFieldGetSetFixture, SetDelegatesToProxyMethodBindingAndCopiesValueIntoInArgsBuffer) +{ + // Given a ProxyField with a setter (WithSetter, WithNotifier) + auto field = CreateFieldWithSetAndNotifier(); + const TestSampleType value{42U}; + EXPECT_CALL(set_method_binding_mock_, GetInArgsBuffer(0U)); + EXPECT_CALL(set_method_binding_mock_, GetReturnValueBuffer(0U)); + EXPECT_CALL(set_method_binding_mock_, DoCall(0U)); + + // When Set is called + auto result = field.Set(value); + + // Then the call is delegated to the binding and the value lands in the in-args buffer + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(static_cast(in_args_buffer_[0]), value); +} + +TEST_F(ProxyFieldGetSetFixture, GetPropagatesBindingError) +{ + // Given a Get-enabled ProxyField (WithGetter) + auto field = CreateFieldWithGetOnly(); + + // When calling Get() + EXPECT_CALL(get_method_binding_mock_, GetReturnValueBuffer(0U)) + .WillOnce(Return(MakeUnexpected(ComErrc::kBindingFailure))); + auto result = field.Get(); + + // Then the error is propagated back to the caller + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), ComErrc::kBindingFailure); +} + +TEST_F(ProxyFieldGetSetFixture, SetPropagatesBindingError) +{ + // Given a Set-enabled ProxyField (WithSetter, WithNotifier) + auto field = CreateFieldWithSetAndNotifier(); + const TestSampleType value{42U}; + + // When Set is called + EXPECT_CALL(set_method_binding_mock_, GetInArgsBuffer(0U)) + .WillOnce(Return(MakeUnexpected(ComErrc::kBindingFailure))); + auto result = field.Set(value); + + // Then the error is propagated back to the caller + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), ComErrc::kBindingFailure); +} + } // namespace } // namespace score::mw::com::impl From 197485a8f18df5d41b99eb40a593d43031195938 Mon Sep 17 00:00:00 2001 From: Krishna Date: Fri, 10 Jul 2026 18:58:18 +0200 Subject: [PATCH 3/3] lola: add ProxyMethodBindingFactory field Get/Set construction test --- score/mw/com/impl/BUILD | 4 +- score/mw/com/impl/method_type_test.cpp | 14 ++--- .../proxy_method_binding_factory_impl.h | 3 + .../proxy_method_binding_factory_test.cpp | 61 +++++++++++++++++++ score/mw/com/impl/proxy_field_test.cpp | 23 +++++-- 5 files changed, 87 insertions(+), 18 deletions(-) diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index ca50f3a68..cd455d16e 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -1180,9 +1180,7 @@ cc_unit_test( name = "method_type_test", srcs = ["method_type_test.cpp"], features = COMPILER_WARNING_FEATURES, - deps = [ - ":method_type", - ], + deps = [":method_type"], ) cc_unit_test( diff --git a/score/mw/com/impl/method_type_test.cpp b/score/mw/com/impl/method_type_test.cpp index 9558fe360..f83d429bb 100644 --- a/score/mw/com/impl/method_type_test.cpp +++ b/score/mw/com/impl/method_type_test.cpp @@ -21,32 +21,28 @@ namespace TEST(MethodTypeToStringTest, ReturnsMethodForKMethod) { - // Given a MethodType of kMethod - // When converting to string + // When converting a MethodType of kMethod to string // Then the result is "Method" EXPECT_EQ(to_string(MethodType::kMethod), "Method"); } TEST(MethodTypeToStringTest, ReturnsGetForKGet) { - // Given a MethodType of kGet - // When converting to string + // When converting a MethodType of kGet to string // Then the result is "Get" EXPECT_EQ(to_string(MethodType::kGet), "Get"); } TEST(MethodTypeToStringTest, ReturnsSetForKSet) { - // Given a MethodType of kSet - // When converting to string + // When converting a MethodType of kSet to string // Then the result is "Set" EXPECT_EQ(to_string(MethodType::kSet), "Set"); } TEST(MethodTypeToStringTest, ReturnsUnknownForKUnknown) { - // Given a MethodType of kUnknown - // When converting to string + // When converting a MethodType of kUnknown to string // Then the result is "Unknown" EXPECT_EQ(to_string(MethodType::kUnknown), "Unknown"); } @@ -54,7 +50,7 @@ TEST(MethodTypeToStringTest, ReturnsUnknownForKUnknown) TEST(MethodTypeToStringTest, ReturnsInvalidForOutOfRangeValue) { // Given an out-of-range MethodType value - const auto invalid_value = static_cast(255); + const auto invalid_value = static_cast(255U); // When converting to string // Then the result is "Invalid" diff --git a/score/mw/com/impl/plumbing/proxy_method_binding_factory_impl.h b/score/mw/com/impl/plumbing/proxy_method_binding_factory_impl.h index d572003ed..23caaf73e 100644 --- a/score/mw/com/impl/plumbing/proxy_method_binding_factory_impl.h +++ b/score/mw/com/impl/plumbing/proxy_method_binding_factory_impl.h @@ -104,6 +104,9 @@ Result> ProxyMethodBindingFactoryImpl>; diff --git a/score/mw/com/impl/plumbing/proxy_method_binding_factory_test.cpp b/score/mw/com/impl/plumbing/proxy_method_binding_factory_test.cpp index a057829b8..cfd0b4d94 100644 --- a/score/mw/com/impl/plumbing/proxy_method_binding_factory_test.cpp +++ b/score/mw/com/impl/plumbing/proxy_method_binding_factory_test.cpp @@ -13,6 +13,8 @@ #include "score/mw/com/impl/plumbing/proxy_method_binding_factory.h" #include "score/mw/com/impl/bindings/lola/test/proxy_event_test_resources.h" #include "score/mw/com/impl/bindings/mock_binding/proxy.h" +#include "score/mw/com/impl/configuration/lola_event_instance_deployment.h" +#include "score/mw/com/impl/configuration/lola_field_instance_deployment.h" #include "score/mw/com/impl/configuration/lola_service_instance_deployment.h" #include "score/mw/com/impl/configuration/lola_service_instance_id.h" #include "score/mw/com/impl/configuration/quality_type.h" @@ -63,6 +65,27 @@ ConfigurationStore kConfigStoreAsilB{kInstanceSpecifier, kLolaServiceTypeDeployment, kLolaServiceInstanceDeployment}; +constexpr auto kDummyFieldName{"Field1"}; +constexpr std::uint16_t kDummyFieldId{6U}; +const auto kFieldInstanceSpecifier = InstanceSpecifier::Create(std::string{"/my_field_instance_specifier"}).value(); + +const LolaServiceInstanceDeployment kLolaServiceInstanceDeploymentWithField{ + LolaServiceInstanceId{kInstanceId}, + {}, + {{kDummyFieldName, LolaFieldInstanceDeployment{LolaEventInstanceDeployment{{1U}, {3U}, 1U, true, 0}, true, true}}}, + {{kDummyFieldName, LolaMethodInstanceDeployment{kQueueSize, true}}}}; + +const LolaServiceTypeDeployment kLolaServiceTypeDeploymentWithField{kServiceId, + {}, + {{kDummyFieldName, kDummyFieldId}}, + {{kDummyMethodName, kDummyMethodId}}}; + +ConfigurationStore kConfigStoreWithFieldAsilB{kFieldInstanceSpecifier, + make_ServiceIdentifierType("/a/service/somewhere/out/there", 13U, 37U), + kQualityType, + kLolaServiceTypeDeploymentWithField, + kLolaServiceInstanceDeploymentWithField}; + class ProxyMethodFactoryFixture : public lola::ProxyMockedMemoryFixture { @@ -72,6 +95,11 @@ class ProxyMethodFactoryFixture : public lola::ProxyMockedMemoryFixture return kConfigStoreAsilB.GetHandle(); } + HandleType GetValidLoLaHandleWithField() + { + return kConfigStoreWithFieldAsilB.GetHandle(); + } + HandleType GetBlankBindingHandle() { const auto instance_identifier = dummy_instance_identifier_builder_.CreateBlankBindingInstanceIdentifier(); @@ -108,6 +136,25 @@ TYPED_TEST(ProxyMethodFactoryTypedFixture, CanConstructLolaProxyMethod) ASSERT_NE(proxy_method.value(), nullptr); } +TYPED_TEST(ProxyMethodFactoryTypedFixture, CanConstructFieldGetAndSetMethods) +{ + // Given a valid lola binding whose deployment carries a field named kDummyFieldName + const auto handle = this->GetValidLoLaHandleWithField(); + this->InitialiseProxyWithConstructor(handle.GetInstanceIdentifier()); + using MethodSignature = TypeParam; + + // When creating a binding for both the Get and the Set of that field + for (const auto method_type : {MethodType::kGet, MethodType::kSet}) + { + auto proxy_method = + ProxyMethodBindingFactory::Create(handle, *this->proxy_, kDummyFieldName, method_type); + + // Then a valid binding is created + ASSERT_TRUE(proxy_method.has_value()); + ASSERT_NE(proxy_method.value(), nullptr); + } +} + TYPED_TEST(ProxyMethodFactoryTypedFixture, ConstructingLolaMethodBindingWhichIsDisabledInConfigurationReturnsNullptr) { // Given a valid lola binding with a method which is disabled in the configuration @@ -223,6 +270,20 @@ TYPED_TEST(ProxyMethodFactoryTypedFixture, GetQueueSizeTerminatesForMethodNotInL score::cpp::ignore = detail::GetQueueSize(handle, wrong_name, MethodType::kMethod)); } +TYPED_TEST(ProxyMethodFactoryTypedFixture, ConstructingLolaMethodBindingWithUnknownMethodTypeTerminates) +{ + // Given a valid lola binding + const auto handle = this->GetValidLoLaHandle(); + this->InitialiseProxyWithConstructor(handle.GetInstanceIdentifier()); + + // When creating a ProxyMethod using MethodBindingFactory with MethodType::kUnknown + // Then the program terminates + using MethodSignature = TypeParam; + EXPECT_DEATH(score::cpp::ignore = ProxyMethodBindingFactory::Create( + handle, *this->proxy_, kDummyMethodName, MethodType::kUnknown), + ".*"); +} + TYPED_TEST(ProxyMethodFactoryTypedFixture, GetQueueSizeTerminatesForMethodInLolaDeploymentWithoutQueueSize) { // Given a handle to a valid lola deployment which contains a method with empty QueueSize diff --git a/score/mw/com/impl/proxy_field_test.cpp b/score/mw/com/impl/proxy_field_test.cpp index 6a65e0554..4f3f38234 100644 --- a/score/mw/com/impl/proxy_field_test.cpp +++ b/score/mw/com/impl/proxy_field_test.cpp @@ -391,16 +391,21 @@ class ProxyFieldGetSetFixture : public ::testing::Test TEST_F(ProxyFieldGetSetFixture, GetDelegatesToProxyMethodBinding) { - // Given a Get-enabled ProxyField and a mock method binding + // Given a Get-enabled ProxyField and a mock method binding with a value pre-written into the return buffer auto field = CreateFieldWithGetOnly(); + const TestSampleType expected_value{123U}; + return_type_buffer_[0] = static_cast(expected_value); + + // Expecting that the binding returns a buffer for the return value and then calls the method EXPECT_CALL(get_method_binding_mock_, GetReturnValueBuffer(0U)); EXPECT_CALL(get_method_binding_mock_, DoCall(0U)); // When calling Get() auto result = field.Get(); - // Then the call is delegated to the underlying method binding and succeeds - EXPECT_TRUE(result.has_value()); + // Then the call succeeds and returns the buffered value + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(*result.value(), expected_value); } TEST_F(ProxyFieldGetSetFixture, SetDelegatesToProxyMethodBindingAndCopiesValueIntoInArgsBuffer) @@ -408,6 +413,8 @@ TEST_F(ProxyFieldGetSetFixture, SetDelegatesToProxyMethodBindingAndCopiesValueIn // Given a ProxyField with a setter (WithSetter, WithNotifier) auto field = CreateFieldWithSetAndNotifier(); const TestSampleType value{42U}; + + // Expecting that the binding returns buffers for in-args and return value and then calls the method EXPECT_CALL(set_method_binding_mock_, GetInArgsBuffer(0U)); EXPECT_CALL(set_method_binding_mock_, GetReturnValueBuffer(0U)); EXPECT_CALL(set_method_binding_mock_, DoCall(0U)); @@ -415,7 +422,7 @@ TEST_F(ProxyFieldGetSetFixture, SetDelegatesToProxyMethodBindingAndCopiesValueIn // When Set is called auto result = field.Set(value); - // Then the call is delegated to the binding and the value lands in the in-args buffer + // Then the call succeeds and the value lands in the in-args buffer ASSERT_TRUE(result.has_value()); EXPECT_EQ(static_cast(in_args_buffer_[0]), value); } @@ -425,9 +432,11 @@ TEST_F(ProxyFieldGetSetFixture, GetPropagatesBindingError) // Given a Get-enabled ProxyField (WithGetter) auto field = CreateFieldWithGetOnly(); - // When calling Get() + // Expecting that the binding returns an error when asked for the return value buffer EXPECT_CALL(get_method_binding_mock_, GetReturnValueBuffer(0U)) .WillOnce(Return(MakeUnexpected(ComErrc::kBindingFailure))); + + // When calling Get() auto result = field.Get(); // Then the error is propagated back to the caller @@ -441,9 +450,11 @@ TEST_F(ProxyFieldGetSetFixture, SetPropagatesBindingError) auto field = CreateFieldWithSetAndNotifier(); const TestSampleType value{42U}; - // When Set is called + // Expecting that the binding returns an error when asked for the in-args buffer EXPECT_CALL(set_method_binding_mock_, GetInArgsBuffer(0U)) .WillOnce(Return(MakeUnexpected(ComErrc::kBindingFailure))); + + // When Set is called auto result = field.Set(value); // Then the error is propagated back to the caller