Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions score/mw/com/impl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,13 @@ 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"],
Expand Down Expand Up @@ -1243,9 +1250,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",
],
)

Expand Down
61 changes: 61 additions & 0 deletions score/mw/com/impl/method_type_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/********************************************************************************
* 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 <gtest/gtest.h>

namespace score::mw::com::impl
{
namespace
{

TEST(MethodTypeToStringTest, ReturnsMethodForKMethod)
{
// When converting a MethodType of kMethod to string
// Then the result is "Method"
EXPECT_EQ(to_string(MethodType::kMethod), "Method");
}

TEST(MethodTypeToStringTest, ReturnsGetForKGet)
{
// When converting a MethodType of kGet to string
// Then the result is "Get"
EXPECT_EQ(to_string(MethodType::kGet), "Get");
}

TEST(MethodTypeToStringTest, ReturnsSetForKSet)
{
// When converting a MethodType of kSet to string
// Then the result is "Set"
EXPECT_EQ(to_string(MethodType::kSet), "Set");
}

TEST(MethodTypeToStringTest, ReturnsUnknownForKUnknown)
{
// When converting a MethodType of kUnknown 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<MethodType>(255U);

// When converting to string
// Then the result is "Invalid"
EXPECT_EQ(to_string(invalid_value), "Invalid");
}

} // namespace
} // namespace score::mw::com::impl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ Result<std::unique_ptr<ProxyMethodBinding>> ProxyMethodBindingFactoryImpl<Return
const std::string_view method_name,
MethodType method_type) noexcept
{
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(method_type != MethodType::kUnknown,
"MethodType::kUnknown is not a valid method type");

auto method_name_str = std::string{method_name};

using LambdaReturnType = Result<std::unique_ptr<ProxyMethodBinding>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
{

Expand All @@ -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();
Expand Down Expand Up @@ -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<MethodSignature>::Create(handle, *this->proxy_, kDummyFieldName, method_type);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should also have a death test in case MethodType::kUnknown is provided (if we don't already have one)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added an assert and added a test too.


// 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
Expand Down Expand Up @@ -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<MethodSignature>::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
Expand Down
132 changes: 132 additions & 0 deletions score/mw/com/impl/proxy_field_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <array>
#include <cstddef>
#include <memory>
#include <string_view>
#include <type_traits>

namespace score::mw::com::impl
Expand Down Expand Up @@ -330,5 +338,129 @@ TEST(ProxyFieldNotifierGatingTest, OnlyNotifierApiExistsWhenNoTagsArePresent)
static_assert(!has_set<DefaultField>::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<std::byte>>{
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<std::byte>>{
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<std::byte>>{
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<std::byte>>{
score::cpp::span{in_args_buffer_.data(), in_args_buffer_.size()}}));
ON_CALL(set_method_binding_mock_, DoCall(0)).WillByDefault(Return(score::ResultBlank{}));
}

ProxyField<TestSampleType, WithGetter> CreateFieldWithGetOnly(const std::string_view name = "TestField")
{
return ProxyField<TestSampleType, WithGetter>{
name,
std::make_unique<mock_binding::ProxyEventFacade<TestSampleType>>(proxy_event_mock_),
nullptr,
std::make_unique<mock_binding::ProxyMethodFacade>(get_method_binding_mock_)};
}

ProxyField<TestSampleType, WithSetter, WithNotifier> CreateFieldWithSetAndNotifier(
const std::string_view name = "TestField")
{
return ProxyField<TestSampleType, WithSetter, WithNotifier>{
name,
std::make_unique<mock_binding::ProxyEventFacade<TestSampleType>>(proxy_event_mock_),
std::make_unique<mock_binding::ProxyMethodFacade>(set_method_binding_mock_)};
}

alignas(8) std::array<std::byte, 1024U> return_type_buffer_{};
alignas(8) std::array<std::byte, 1024U> in_args_buffer_{};
RuntimeMockGuard runtime_mock_guard_{};
mock_binding::ProxyEvent<TestSampleType> 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 with a value pre-written into the return buffer
auto field = CreateFieldWithGetOnly();
const TestSampleType expected_value{123U};
return_type_buffer_[0] = static_cast<std::byte>(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();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also put a value in the return buffer and check that it's returned in result?


// Then the call succeeds and returns the buffered value
ASSERT_TRUE(result.has_value());
EXPECT_EQ(*result.value(), expected_value);
}

TEST_F(ProxyFieldGetSetFixture, SetDelegatesToProxyMethodBindingAndCopiesValueIntoInArgsBuffer)
{
// 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));

// When Set is called
auto result = field.Set(value);

// Then the call succeeds and the value lands in the in-args buffer
ASSERT_TRUE(result.has_value());
EXPECT_EQ(static_cast<TestSampleType>(in_args_buffer_[0]), value);
}

TEST_F(ProxyFieldGetSetFixture, GetPropagatesBindingError)
{
// Given a Get-enabled ProxyField (WithGetter)
auto field = CreateFieldWithGetOnly();

// 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
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};

// 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
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error(), ComErrc::kBindingFailure);
}

} // namespace
} // namespace score::mw::com::impl
Loading