Skip to content

Commit

Permalink
Add introspection typesupport tests for C/C++ services
Browse files Browse the repository at this point in the history
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
  • Loading branch information
hidmic committed Jan 28, 2022
1 parent bf556b6 commit feb5ff9
Show file tree
Hide file tree
Showing 8 changed files with 2,183 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,35 @@ const char * get_message_name(const MessageDescriptorT * message_descriptor)
return message_descriptor->message_name_;
}

/// Get a service's namespace from its `service_descriptor`.
template<typename ServiceDescriptorT>
const char *
get_service_namespace(const ServiceDescriptorT * service_descriptor)
{
return service_descriptor->service_namespace_;
}

/// Get a service's name from its `service_descriptor`.
template<typename ServiceDescriptorT>
const char * get_service_name(const ServiceDescriptorT * service_descriptor)
{
return service_descriptor->service_name_;
}

/// Get a service request message descriptor from its `service_descriptor`.
template<typename ServiceDescriptorT>
auto get_service_request_descriptor(const ServiceDescriptorT * service_descriptor)
{
return service_descriptor->request_members_;
}

/// Get a service response message descriptor from its `service_descriptor`.
template<typename ServiceDescriptorT>
auto get_service_response_descriptor(const ServiceDescriptorT * service_descriptor)
{
return service_descriptor->response_members_;
}

/// Get a message's (base) size from its `message_descriptor`.
template<typename MessageDescriptorT>
size_t get_message_size(const MessageDescriptorT * message_descriptor)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ROSIDL_TYPESUPPORT_INTROSPECTION_TESTS__GTEST__SERVICE_INTROSPECTION_TEST_HPP_
#define ROSIDL_TYPESUPPORT_INTROSPECTION_TESTS__GTEST__SERVICE_INTROSPECTION_TEST_HPP_

#include <memory>

#include "rosidl_typesupport_introspection_tests/gtest/shared_library_test.hpp"
#include "rosidl_typesupport_introspection_tests/api.hpp"
#include "rosidl_typesupport_introspection_tests/type_traits.hpp"
#include "rosidl_typesupport_introspection_tests/types.hpp"

namespace rosidl_typesupport_introspection_tests
{
namespace testing
{

/// A GTest fixture for service introspection tests
/**
* \tparam ServiceT type of the service to test.
* introspection_traits<ServiceT> must exist.
* See test suite below for further reference
* on traits' requirements.
*/
template<typename ServiceT>
class ServiceIntrospectionTest : public SharedLibraryTest
{
public:
using TypeSupportLibraryT =
typename introspection_traits<ServiceT>::TypeSupportLibraryT;
using ServiceDescriptorT =
typename TypeSupportLibraryT::ServiceDescriptorT;

ServiceIntrospectionTest()
: SharedLibraryTest(TypeSupportLibraryT::name)
{
}

void SetUp() override
{
const char * typesupport_symbol =
introspection_traits<ServiceT>::typesupport.symbol;
auto service_typesupport_fetch =
reinterpret_cast<ServiceTypeSupportFetchFunctionT>(
this->GetSharedLibrary().get_symbol(typesupport_symbol));
ASSERT_NE(service_typesupport_fetch, nullptr);
const rosidl_service_type_support_t * service_typesupport =
get_service_typesupport_handle(
service_typesupport_fetch(),
TypeSupportLibraryT::identifier);
ASSERT_NE(service_typesupport, nullptr);
service_descriptor_ =
reinterpret_cast<const ServiceDescriptorT *>(
service_typesupport->data);
ASSERT_NE(service_descriptor_, nullptr);
}

const ServiceDescriptorT * GetServiceDescriptor() const
{
return service_descriptor_;
}

std::unique_ptr<void, std::function<void(void *)>>
MakeTypeErasedRequestMessage() const
{
using MessageDescriptorT =
typename TypeSupportLibraryT::MessageDescriptorT;
const MessageDescriptorT * request_message_descriptor =
get_service_request_descriptor(service_descriptor_);
using RequestMessageT = typename ServiceT::Request;
std::allocator<RequestMessageT> allocator;
std::function<void(void *)> type_erased_message_deleter = [ = ](void * ptr) mutable {
finalize_message(ptr, request_message_descriptor);
allocator.deallocate(reinterpret_cast<RequestMessageT *>(ptr), 1);
};
std::unique_ptr<void, std::function<void(void *)>> type_erased_message(
initialize_message(allocator.allocate(1), request_message_descriptor),
type_erased_message_deleter);
return type_erased_message;
}

std::unique_ptr<void, std::function<void(void *)>>
MakeTypeErasedResponseMessage() const
{
using MessageDescriptorT =
typename TypeSupportLibraryT::MessageDescriptorT;
const MessageDescriptorT * response_message_descriptor =
get_service_response_descriptor(service_descriptor_);
using ResponseMessageT = typename ServiceT::Response;
std::allocator<ResponseMessageT> allocator;
std::function<void(void *)> type_erased_message_deleter = [ = ](void * ptr) mutable {
finalize_message(ptr, response_message_descriptor);
allocator.deallocate(reinterpret_cast<ResponseMessageT *>(ptr), 1);
};
std::unique_ptr<void, std::function<void(void *)>> type_erased_message(
initialize_message(allocator.allocate(1), response_message_descriptor),
type_erased_message_deleter);
return type_erased_message;
}

private:
const ServiceDescriptorT * service_descriptor_{nullptr};
};

} // namespace testing
} // namespace rosidl_typesupport_introspection_tests

#endif // ROSIDL_TYPESUPPORT_INTROSPECTION_TESTS__GTEST__SERVICE_INTROSPECTION_TEST_HPP_
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,34 @@ getitem(const std::array<T, N> & array, const size_t index)
DEFINE_GETITEM_OVERLOAD_FOR_C_MESSAGE_SEQUENCE_MEMBER(type) \
DEFINE_LENGTH_OVERLOAD_FOR_C_MESSAGE_SEQUENCE_MEMBER(type)

#define C_MESSAGE_NAME(package_name, interface_type, message_name) \
package_name ## __ ## interface_type ## __ ## message_name
#define C_INTERFACE_NAME(package_name, interface_type, interface_name) \
RCUTILS_JOIN( \
RCUTILS_JOIN( \
RCUTILS_JOIN( \
RCUTILS_JOIN( \
package_name, __), interface_type), __), interface_name)

/// Defines C++ helper API for a C message.
#define DEFINE_CXX_API_FOR_C_MESSAGE(package_name, interface_type, message_name) \
DEFINE_CXX_API_FOR_C_MESSAGE_MEMBER( \
C_MESSAGE_NAME(package_name, interface_type, message_name)) \
C_INTERFACE_NAME(package_name, interface_type, message_name)) \
DEFINE_CXX_API_FOR_C_MESSAGE_SEQUENCE_MEMBER( \
RCUTILS_JOIN( \
C_MESSAGE_NAME(package_name, interface_type, message_name), __Sequence))
RCUTILS_JOIN(C_INTERFACE_NAME(package_name, interface_type, message_name), __Sequence))

/// Defines C++ helper API for a C service.
#define DEFINE_CXX_API_FOR_C_SERVICE(package_name, interface_type, service_name) \
DEFINE_CXX_API_FOR_C_MESSAGE_MEMBER( \
C_INTERFACE_NAME(package_name, interface_type, RCUTILS_JOIN(service_name, _Request))) \
DEFINE_CXX_API_FOR_C_MESSAGE_MEMBER( \
C_INTERFACE_NAME(package_name, interface_type, RCUTILS_JOIN(service_name, _Response))) \
struct C_INTERFACE_NAME (package_name, interface_type, service_name) { \
using Request = C_INTERFACE_NAME( \
package_name, interface_type, RCUTILS_JOIN( \
service_name, \
_Request)); \
using Response = \
C_INTERFACE_NAME(package_name, interface_type, RCUTILS_JOIN(service_name, _Response)); \
};

// Extra C++ APIs to homogeneize access to rosidl_runtime_c primitives
DEFINE_CXX_API_FOR_C_MESSAGE_MEMBER(rosidl_runtime_c__String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
namespace rosidl_typesupport_introspection_tests
{

// Base definition, to be specialized
template<typename InterfaceT>
struct interface_traits;

// Base definition, to be specialized
template<typename InterfaceT>
struct introspection_traits;
Expand Down
Loading

0 comments on commit feb5ff9

Please sign in to comment.