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 diff --git a/UNITTESTS/fakes/events/EventQueue.cpp b/UNITTESTS/fakes/events/EventQueue.cpp index ba4b739f08..4f937c240c 100644 --- a/UNITTESTS/fakes/events/EventQueue.cpp +++ b/UNITTESTS/fakes/events/EventQueue.cpp @@ -98,21 +98,22 @@ void EventQueue::process_events() { } /* dispatch all handlers that happen at this time */ - _handlers.erase( - std::remove_if( - _handlers.begin(), - _handlers.end(), - [earliest_tick](internal_event& element) -> bool { - if (earliest_tick >= element.tick) { - (*(element.handler))(); - return true; - } else { - return false; - } + auto found = std::remove_if( + _handlers.begin(), + _handlers.end(), + [earliest_tick](internal_event& element) -> bool { + if (earliest_tick >= element.tick) { + (*(element.handler))(); + return true; + } else { + return false; } - ), - _handlers.end() + } ); + + if (found != _handlers.end()) { + _handlers.erase(found, _handlers.end()); + } } } diff --git a/UNITTESTS/target_h/platform/mbed_retarget.h b/UNITTESTS/target_h/platform/mbed_retarget.h index aea425ed7f..cd71083c03 100644 --- a/UNITTESTS/target_h/platform/mbed_retarget.h +++ b/UNITTESTS/target_h/platform/mbed_retarget.h @@ -374,9 +374,17 @@ struct stat { off_t st_size; ///< Size of file in bytes + // st_atime, st_mtime and st_ctime are defined as macros + // on platform like iOS. +#ifndef st_atime time_t st_atime; ///< Time of last access +#endif +#ifndef st_mtime time_t st_mtime; ///< Time of last data modification +#endif +#ifndef st_ctime time_t st_ctime; ///< Time of last status change +#endif }; #endif diff --git a/connectivity/FEATURE_BLE/include/ble/common/ChainableEventHandler.h b/connectivity/FEATURE_BLE/include/ble/common/ChainableEventHandler.h index 7e3f06237d..616980154b 100644 --- a/connectivity/FEATURE_BLE/include/ble/common/ChainableEventHandler.h +++ b/connectivity/FEATURE_BLE/include/ble/common/ChainableEventHandler.h @@ -71,14 +71,14 @@ public: * * @param[in] event_handler Pointer to event handler to remove */ - void removeEventHandler(T* target) { + void removeEventHandler(T* event_handler) { node_t* to_remove = head; - if(head->eh == target) { + if(head->eh == event_handler) { head = head->next; } else { auto* it = head; while(it->next) { - if(it->next->eh == target) { + if(it->next->eh == event_handler) { to_remove = it->next; break; } @@ -94,6 +94,22 @@ public: delete to_remove; } + /** + * Test if an event handler is present in the chain or not. + * + * @param[in] event_handler Pointer to event handler to check + */ + bool isEventHandlerPresent(T* event_handler) { + auto* it = head; + while (it) { + if (it == event_handler) { + return true; + } + it = it->next; + } + return false; + } + protected: template diff --git a/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h b/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h index d5e88eedfb..cf310c3d4c 100644 --- a/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h +++ b/connectivity/FEATURE_BLE/include/ble/gatt/GattCharacteristic.h @@ -1579,6 +1579,17 @@ public: writeAuthorizationCallback.attach(object, member); } + /** + * Return the callback registered to handle client's write. + * + * @return the callback that handles client's write requests. + */ + const FunctionPointerWithContext& + getWriteAuthorizationCallback() const + { + return writeAuthorizationCallback; + } + /** * Register the read requests event handler. * @@ -1616,6 +1627,17 @@ public: readAuthorizationCallback.attach(object, member); } + /** + * Return the callback registered to handle client's read. + * + * @return the callback that handles client's read requests. + */ + const FunctionPointerWithContext& + getReadAuthorizationCallback() const + { + return readAuthorizationCallback; + } + /** * Invoke the write authorization callback. *