From 0feaae6d1862420ca3858c48ea1ab9bdf4c98dbc Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Tue, 9 Feb 2021 14:39:17 +0000 Subject: [PATCH] Add fake implementation for GattServerMock::addService. It is not easy to write expectations for this function: - The data in input is a complex tree that is not comparable. - The data in input is modified: The attributes of each element of the tree is added by the server. To ease test, a default implementation has been added but it is still possible to override it or set expectations. That default implementation set unique attribute handles for each element of the service and _copy_ it in the GattServerMock. The copy does *not* follow standard BLE API, it is a _POD_ where each element of the object is accessible as a field. Childs are stored in vector to ease iteration and memory management. The representation of the services registered into the mock are accessible in GattServerMock::services. --- UNITTESTS/fakes/ble/CMakeLists.txt | 6 ++ UNITTESTS/fakes/ble/GattServerImpl_mock.h | 45 ++++++++- .../fakes/ble/source/GattServerImpl_mock.cpp | 96 +++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 UNITTESTS/fakes/ble/source/GattServerImpl_mock.cpp diff --git a/UNITTESTS/fakes/ble/CMakeLists.txt b/UNITTESTS/fakes/ble/CMakeLists.txt index 1c1b32d75f..0dd25e965f 100644 --- a/UNITTESTS/fakes/ble/CMakeLists.txt +++ b/UNITTESTS/fakes/ble/CMakeLists.txt @@ -24,6 +24,12 @@ target_sources(mbed-os-fakes-ble ${MBED_PATH}/connectivity/FEATURE_BLE/source/GattServer.cpp ${MBED_PATH}/connectivity/FEATURE_BLE/source/SecurityManager.cpp ${MBED_PATH}/UNITTESTS/fakes/ble/BLE.cpp + ${MBED_PATH}/UNITTESTS/fakes/ble/source/GattServerImpl_mock.cpp + ${MBED_PATH}/UNITTESTS/fakes/ble/ble_mocks.h + ${MBED_PATH}/UNITTESTS/fakes/ble/GapImpl_mock.h + ${MBED_PATH}/UNITTESTS/fakes/ble/GattClientImpl_mock.h + ${MBED_PATH}/UNITTESTS/fakes/ble/GattServerImpl_mock.h + ${MBED_PATH}/UNITTESTS/fakes/ble/SecurityManagerImpl_mock.h ) target_link_libraries(mbed-os-fakes-ble diff --git a/UNITTESTS/fakes/ble/GattServerImpl_mock.h b/UNITTESTS/fakes/ble/GattServerImpl_mock.h index 7ade69615f..bfafb52400 100644 --- a/UNITTESTS/fakes/ble/GattServerImpl_mock.h +++ b/UNITTESTS/fakes/ble/GattServerImpl_mock.h @@ -25,10 +25,10 @@ namespace ble { class GattServerMock : public ble::impl::GattServer { public: - GattServerMock() {}; + GattServerMock(); GattServerMock(const GattServerMock&) = delete; GattServerMock& operator=(const GattServerMock&) = delete; - virtual ~GattServerMock() {}; + virtual ~GattServerMock(); MOCK_METHOD(ble_error_t, reset, (ble::GattServer* server), (override)); MOCK_METHOD(void, setEventHandler, (EventHandler *handler), (override)); @@ -57,6 +57,47 @@ public: MOCK_METHOD(void, handleDataReadEvent, (const GattReadCallbackParams *params), (override)); MOCK_METHOD(void, handleEvent, (GattServerEvents::gattEvent_e type, ble::connection_handle_t connHandle, GattAttribute::Handle_t attributeHandle), (override)); MOCK_METHOD(void, handleDataSentEvent, (unsigned count), (override)); + + // Fake part + // Descriptor representation of a descriptor registered with ble::test::register_services + struct descriptor_t { + UUID uuid; + ble::attribute_handle_t handle; + ble::att_security_requirement_t read_security = ble::att_security_requirement_t::NONE; + ble::att_security_requirement_t write_security = ble::att_security_requirement_t::NONE; + bool is_readable; + bool is_writable; + std::vector value; // Use capacity to determine the max size. + }; + + // Characteristic representation of a characteristic registered with ble::test::register_services + struct characteristic_t { + UUID uuid; + ble::attribute_handle_t value_handle; + uint8_t properties; + ble::att_security_requirement_t read_security = ble::att_security_requirement_t::NONE; + ble::att_security_requirement_t write_security = ble::att_security_requirement_t::NONE; + ble::att_security_requirement_t update_security = ble::att_security_requirement_t::NONE; + FunctionPointerWithContext + read_cb; + FunctionPointerWithContext + write_cb; + bool has_variable_len; + std::vector value; // Use capacity to determine the max size. + std::vector descriptors; + }; + + // Service representation of a service registered with ble::test::register_services + struct service_t { + UUID uuid; + ble::attribute_handle_t handle; + std::vector characteristics; + }; + + void fake_register_services(GattService& gattService); + + std::vector services; + ble::attribute_handle_t current_handle = 1; }; } diff --git a/UNITTESTS/fakes/ble/source/GattServerImpl_mock.cpp b/UNITTESTS/fakes/ble/source/GattServerImpl_mock.cpp new file mode 100644 index 0000000000..74d94ef304 --- /dev/null +++ b/UNITTESTS/fakes/ble/source/GattServerImpl_mock.cpp @@ -0,0 +1,96 @@ +/* mbed Microcontroller Library + * Copyright (c) 2021 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +#include "GattServerImpl_mock.h" + +namespace ble { + +GattServerMock::GattServerMock() +{ + ON_CALL(*this, addService).WillByDefault([this](GattService &service) { + // Fake registration, it populates the handles of the input and store its + // representation in the services field. + fake_register_services(service); + return BLE_ERROR_NONE; + }); +} + +GattServerMock::~GattServerMock() {}; + +void GattServerMock::fake_register_services(GattService& gattService) +{ + gattService.setHandle(current_handle++); + service_t result { + gattService.getUUID(), + gattService.getHandle() + }; + + for (size_t i = 0; i < gattService.getCharacteristicCount(); ++i) { + current_handle++; // Increment for the characteristic declaration handle + auto& ref = *gattService.getCharacteristic(i); + ref.getValueAttribute().setHandle(current_handle++); + + characteristic_t c; + c.uuid = ref.getValueAttribute().getUUID(); + c.value_handle = ref.getValueHandle(); + c.properties = ref.getProperties(); + c.read_security = ref.getReadSecurityRequirement(); + c.write_security = ref.getWriteSecurityRequirement(); + c.update_security = ref.getUpdateSecurityRequirement(); + c.read_cb = ref.getReadAuthorizationCallback(); + c.write_cb = ref.getWriteAuthorizationCallback(); + c.value.reserve(ref.getValueAttribute().getMaxLength()); + c.value.resize(ref.getValueAttribute().getLength()); + { + auto value_ptr = ref.getValueAttribute().getValuePtr(); + if (value_ptr) { + std::copy(value_ptr, value_ptr + c.value.size(), c.value.begin()); + } + } + c.has_variable_len = ref.getValueAttribute().hasVariableLength(); + + for (size_t j = 0; j < ref.getDescriptorCount(); ++j) { + auto& ref_desc = *ref.getDescriptor(j); + ref_desc.setHandle(current_handle++); + + descriptor_t d; + d.uuid = ref_desc.getUUID(); + d.handle = ref_desc.getHandle(); + d.read_security = ref_desc.getReadSecurityRequirement(); + d.write_security = ref_desc.getWriteSecurityRequirement(); + d.is_readable = ref_desc.isReadAllowed(); + d.is_writable = ref_desc.isWriteAllowed(); + d.value.reserve(ref_desc.getMaxLength()); + d.value.resize(ref_desc.getLength()); + { + auto value_ptr = ref_desc.getValuePtr(); + if (value_ptr) { + std::copy(value_ptr, value_ptr + d.value.size(), d.value.begin()); + } + } + + c.descriptors.push_back(d); + } + + result.characteristics.push_back(c); + } + + services.push_back(result); +} + + +} \ No newline at end of file