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.
pull/14254/head
Vincent Coubard 2021-02-09 14:39:17 +00:00
parent 4056fe0924
commit 0feaae6d18
3 changed files with 145 additions and 2 deletions

View File

@ -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

View File

@ -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<uint8_t> 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<GattReadAuthCallbackParams *>
read_cb;
FunctionPointerWithContext<GattWriteAuthCallbackParams *>
write_cb;
bool has_variable_len;
std::vector<uint8_t> value; // Use capacity to determine the max size.
std::vector<descriptor_t> descriptors;
};
// Service representation of a service registered with ble::test::register_services
struct service_t {
UUID uuid;
ble::attribute_handle_t handle;
std::vector<characteristic_t> characteristics;
};
void fake_register_services(GattService& gattService);
std::vector<service_t> services;
ble::attribute_handle_t current_handle = 1;
};
}

View File

@ -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);
}
}