Unverified Commit f0542c4e authored by Ken A. Redergård's avatar Ken A. Redergård Committed by GitHub
Browse files

Reduce boiler-plate code in tests (#125)

* Reduce boiler-plate code in tests

There is a lot of boiler-plate coded needed when writing tests.

This commit reduces the boiler plate code by introducing a wrapper around adapter_t.

Improved conversion from structs/enums to text are added.
Tests are updated to use these improvements.

Files affected by the change has been linted.

The tests are now built for all supported SoftDevice API versions making it easier to detect if the tests are working for the versions supported.
parent 15a5e753
enable_testing()
# Use the latest SoftDevice API version in the tests
list(GET SD_API_VER_NUMS -1 SD_API_VER)
#list(GET SD_API_VER_NUMS -1 SD_API_VER)
message(STATUS "Using SoftDevice API version ${SD_API_VER} in tests.")
......@@ -20,24 +20,27 @@ include_directories (
file(GLOB tests_src "test_*.cpp")
foreach(test_src ${tests_src})
get_filename_component(test_name ${test_src} NAME_WE)
# Build executable
add_executable(${test_name} ${test_src})
target_compile_definitions(${test_name} PRIVATE -DNRF_SD_BLE_API=${SD_API_VER} -DNRF_LOG_FILENAME="${test_name}.txt")
if(WIN32)
target_link_libraries(${test_name} PRIVATE pc_ble_driver_static_sd_api_v${SD_API_VER})
elseif(APPLE)
target_link_libraries(${test_name} PRIVATE pc_ble_driver_static_sd_api_v${SD_API_VER})
else()
# Assume Linux
target_link_libraries(${test_name} PRIVATE pc_ble_driver_static_sd_api_v${SD_API_VER} "pthread")
endif()
add_test(NAME ${test_name} COMMAND ${test_name})
message(STATUS "Added test ${test_src}, with test name ${test_name}.")
endforeach(test_src)
foreach(SD_API_VER ${SD_API_VER_NUMS})
foreach(test_src ${tests_src})
get_filename_component(test_name ${test_src} NAME_WE)
set(test_name "${test_name}_v${SD_API_VER}")
# Build executable
add_executable(${test_name} ${test_src})
target_compile_definitions(${test_name} PRIVATE -DNRF_SD_BLE_API=${SD_API_VER} -DNRF_LOG_FILENAME="${test_name}.txt")
target_include_directories(${test_name} PRIVATE ../src/sd_api_v${SD_API_VER}/sdk/components/softdevice/s132/headers)
if(WIN32)
target_link_libraries(${test_name} PRIVATE pc_ble_driver_static_sd_api_v${SD_API_VER})
elseif(APPLE)
target_link_libraries(${test_name} PRIVATE pc_ble_driver_static_sd_api_v${SD_API_VER})
else()
# Assume Linux
target_link_libraries(${test_name} PRIVATE pc_ble_driver_static_sd_api_v${SD_API_VER} "pthread")
endif()
add_test(NAME ${test_name} COMMAND ${test_name})
message(STATUS "Added test ${test_src}, with test name ${test_name}.")
endforeach(test_src)
endforeach(SD_API_VER)
......@@ -49,16 +49,11 @@
#include "test_setup.h"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <thread>
#include <random>
#include <iomanip>
#include <fstream>
#include <exception>
#include <chrono>
#if defined(_MSC_VER)
......@@ -76,7 +71,7 @@ public:
);
}
void statusCallback(sd_rpc_app_status_t code, const char *message)
void statusCallback(sd_rpc_app_status_t code, const char *message) const
{
NRF_LOG("[" << name << "][status] code: " << code << " message: " << message);
}
......@@ -84,10 +79,10 @@ public:
void dataCallback(uint8_t *data, size_t length)
{
incoming.assign(data, data + length);
NRF_LOG("[" << name << "][data]<- " << testutil::convertToString(incoming) << " length: " << length);
NRF_LOG("[" << name << "][data]<- " << testutil::asHex(incoming) << " length: " << length);
}
void logCallback(sd_rpc_log_severity_t severity, std::string message)
void logCallback(sd_rpc_log_severity_t severity, std::string message) const
{
NRF_LOG("[" << name << "][log] severity: " << severity << " message: " << message);
}
......@@ -101,12 +96,12 @@ public:
);
}
std::shared_ptr<test::H5TransportWrapper> get()
std::shared_ptr<test::H5TransportWrapper> get() const
{
return transport;
}
uint32_t wait()
uint32_t wait() const
{
return transport->waitForResult();
}
......@@ -122,7 +117,7 @@ public:
return transport->close();
}
payload_t in()
payload_t in() const
{
return incoming;
}
......@@ -174,7 +169,7 @@ TEST_CASE("H5Transport")
{
SECTION("fail_open_invalid_inbound")
{
auto lowerTransport = new test::VirtualTransportSendSync();
const auto lowerTransport = new test::VirtualTransportSendSync();
H5TransportTestSetup transportUnderTest("transportUnderTest", lowerTransport);
transportUnderTest.setup();
......@@ -293,10 +288,10 @@ TEST_CASE("H5Transport")
REQUIRE(std::equal(payloadToB.begin(), payloadToB.end(), h5TransportB.in().begin()) == true);
REQUIRE(std::equal(payloadToA.begin(), payloadToA.end(), h5TransportA.in().begin()) == true);
h5TransportA.close();
REQUIRE(h5TransportA.close() == NRF_SUCCESS);
REQUIRE(h5TransportA.state() == STATE_CLOSED);
h5TransportB.close();
REQUIRE(h5TransportB.close() == NRF_SUCCESS);
REQUIRE(h5TransportB.state() == STATE_CLOSED);
}
}
......@@ -49,7 +49,6 @@
#include <string>
#include <thread>
#include <iostream>
#include <sstream>
#define SCAN_INTERVAL 0x00A0 /**< Determines scan interval in units of 0.625 milliseconds. */
......@@ -62,7 +61,7 @@ typedef struct
uint16_t data_len; /**< Length of data. */
} data_t;
static adapter_t * m_adapter = NULL;
static adapter_t * m_adapter = nullptr;
#if NRF_SD_BLE_API >= 5
static uint32_t m_config_id = 1;
......@@ -73,14 +72,14 @@ static const ble_gap_scan_params_t m_scan_param =
1, // Active scanning set.
0, // Selective scanning not set.
#if NRF_SD_BLE_API == 2
NULL, // White-list not set.
nullptr, // White-list not set.
#endif
#if NRF_SD_BLE_API >= 3
0, // adv_dir_report not set.
#endif
(uint16_t)SCAN_INTERVAL,
(uint16_t)SCAN_WINDOW,
(uint16_t)SCAN_TIMEOUT
static_cast<uint16_t>(SCAN_INTERVAL),
static_cast<uint16_t>(SCAN_WINDOW),
static_cast<uint16_t>(SCAN_TIMEOUT)
};
/* Local function forward declarations */
......@@ -117,15 +116,14 @@ static void log_handler(adapter_t * adapter, sd_rpc_log_severity_t severity, con
static void on_adv_report(const ble_gap_evt_t * const p_ble_gap_evt)
{
// Log the Bluetooth device address of advertisement packet received.
auto address = testutil::ble_address_to_string_convert(p_ble_gap_evt->params.adv_report.peer_addr);
NRF_LOG("Received advertisement report with device address: " << address);
NRF_LOG("Received advertisement report with device address: " << testutil::asText(p_ble_gap_evt->params.adv_report.peer_addr));
}
static void on_timeout(const ble_gap_evt_t * const p_ble_gap_evt)
{
if (p_ble_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
{
auto result = sd_ble_gap_scan_start(m_adapter, &m_scan_param);
const auto result = sd_ble_gap_scan_start(m_adapter, &m_scan_param);
if (result != NRF_SUCCESS)
{
......@@ -137,21 +135,17 @@ static void on_timeout(const ble_gap_evt_t * const p_ble_gap_evt)
static adapter_t * adapter_init(const char * serial_port, uint32_t baud_rate)
{
physical_layer_t * phy;
data_link_layer_t * data_link_layer;
transport_layer_t * transport_layer;
phy = sd_rpc_physical_layer_create_uart(serial_port, baud_rate, SD_RPC_FLOW_CONTROL_NONE,
SD_RPC_PARITY_NONE);
data_link_layer = sd_rpc_data_link_layer_create_bt_three_wire(phy, 100);
transport_layer = sd_rpc_transport_layer_create(data_link_layer, 100);
physical_layer_t * phy = sd_rpc_physical_layer_create_uart(serial_port, baud_rate, SD_RPC_FLOW_CONTROL_NONE,
SD_RPC_PARITY_NONE);
data_link_layer_t * data_link_layer = sd_rpc_data_link_layer_create_bt_three_wire(phy, 100);
transport_layer_t * transport_layer = sd_rpc_transport_layer_create(data_link_layer, 100);
return sd_rpc_adapter_create(transport_layer);
}
static uint32_t ble_stack_init()
{
uint32_t err_code;
uint32_t * app_ram_base = NULL;
uint32_t * app_ram_base = nullptr;
#if NRF_SD_BLE_API <= 3
ble_enable_params_t ble_enable_params;
......@@ -166,7 +160,7 @@ static uint32_t ble_stack_init()
ble_enable_params.gap_enable_params.periph_conn_count = 1;
ble_enable_params.gap_enable_params.central_conn_count = 1;
ble_enable_params.gap_enable_params.central_sec_count = 1;
ble_enable_params.common_enable_params.p_conn_bw_counts = NULL;
ble_enable_params.common_enable_params.p_conn_bw_counts = nullptr;
ble_enable_params.common_enable_params.vs_uuid_count = 1;
#endif
......@@ -230,7 +224,7 @@ void ble_cfg_set(uint8_t conn_cfg_tag)
static void ble_evt_dispatch(adapter_t * adapter, ble_evt_t * p_ble_evt)
{
if (p_ble_evt == NULL)
if (p_ble_evt == nullptr)
{
NRF_LOG("Received an empty BLE event");
return;
......
......@@ -197,7 +197,7 @@ namespace test
uint32_t send(const std::vector<uint8_t> &data)
{
NRF_LOG("->" << testutil::convertToString(data) << " length: " << data.size());
NRF_LOG("->" << testutil::asHex(data) << " length: " << data.size());
return NRF_SUCCESS;
}
......
#ifndef TEST_UTIL_H__
#define TEST_UTIL_H__
#include "test_util_adapter_wrapper.h"
#include "test_util_conversion.h"
#include "test_util_role.h"
#include "ble.h"
#include <random>
#include <vector>
#include <algorithm>
#include <iterator>
namespace testutil
{
static std::string convertToString(const std::vector<uint8_t> &data) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
static std::vector<std::shared_ptr<testutil::AdapterWrapper>> adapters;
for (uint8_t const& value : data)
static void statusHandler(adapter_t *adapter, sd_rpc_app_status_t code, const char * message)
{
for (const auto& registeredAdapter : adapters)
{
ss << std::setw(2) << std::hex << static_cast<int>(value) << ' ';
if (registeredAdapter->unwrap()->internal == adapter->internal)
{
registeredAdapter->processStatus(code, message);
}
}
}
return ss.str();
static void eventHandler(adapter_t *adapter, ble_evt_t *p_ble_evt)
{
for (const auto &registeredAdapter : adapters)
{
if (registeredAdapter->unwrap()->internal == adapter->internal)
{
registeredAdapter->processEvent(p_ble_evt);
}
}
}
static std::string ble_address_to_string_convert(ble_gap_addr_t address)
static void logHandler(adapter_t *adapter, sd_rpc_log_severity_t severity, const char * log_message)
{
const int address_length = 6;
std::stringstream retval;
for (const auto &registeredAdapter : adapters)
{
if (registeredAdapter->unwrap()->internal == adapter->internal)
{
registeredAdapter->processLog(severity, log_message);
}
}
}
for (int i = sizeof(address.addr) - 1; i >= 0; --i)
/**
* @brief Function that find advertisement type data based on specified specified advertisement type
*
* @param[in] advType Advertisment type to search for
* @param[in] advData Advertisement data to parse
* @param[in,out] advTypeData Advertisement data found for provided advertisement type
*
* @return true if advertisement type was found, false if not.
*/
static bool advReportParse(const uint8_t advType, const std::vector<uint8_t> &advData, std::vector<uint8_t> &advTypeData)
{
auto typeDataBegin = advData.begin();
while (typeDataBegin != advData.end())
{
retval << std::hex << static_cast<unsigned int>(address.addr[i]);
auto fieldLength = *typeDataBegin++;
if (typeDataBegin == advData.end())
{
return false;
}
auto fieldType = *typeDataBegin++;
if (typeDataBegin == advData.end())
{
return false;
}
if (fieldType == advType)
{
const auto advTypeDataLength = fieldLength - 1;
const auto distance = std::distance(typeDataBegin, advData.end());
if (distance < advTypeDataLength)
{
return false;
}
const auto typeDataEnd = typeDataBegin + advTypeDataLength;
advTypeData.assign(typeDataBegin, typeDataEnd);
return true;
}
std::advance(typeDataBegin, fieldLength - 1);
}
return retval.str();
return false;
}
/**
* @brief Function that search for advertisement name in BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME or
* BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME
*
* @param[in] p_adv_report Pointer to advertisement report to search in
* @param[in] name_to_find Advertisement name to search for
*
* @return true if name is found, false if not
*/
static bool findAdvName(const ble_gap_evt_adv_report_t *p_adv_report, const std::string &name_to_find)
{
std::vector<uint8_t> advData;
advData.assign((uint8_t *)p_adv_report->data, (uint8_t *)p_adv_report->data + p_adv_report->dlen);
std::vector<uint8_t> advTypeData;
std::vector<uint8_t> nameToFind;
std::copy(name_to_find.begin(), name_to_find.end(), std::back_inserter(nameToFind));
auto found = [&](const uint8_t advType)
{
if (advReportParse(advType, advData, advTypeData))
{
if (nameToFind.size() > advTypeData.size())
{
return false;
}
if (std::equal(nameToFind.begin(), nameToFind.end(), advTypeData.begin()))
{
return true;
}
}
return false;
};
return found(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME) || found(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
}
/**
* @brief Function that append name to advertise to advertisement type BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME
*
* @param[in,out] advertisingData std::vector to append advertisement data to
* @param[in] name Name to append to advertisingData
*/
static void appendAdvertisingName(std::vector<uint8_t> &advertisingData, const std::string &name)
{
advertisingData.push_back((uint8_t)(name.length() + 1)); // Device name + advertisement type
advertisingData.push_back(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
std::copy(name.begin(), name.end(), std::back_inserter(advertisingData));
}
/*
* @brief Function that fills a std::vector<uint8_t> with random values
*
* @param[in,out] data vector to populate with random values
* @param[in] size number of random values to fill the vector with
*/
static void appendRandomData(std::vector<uint8_t> &data, const size_t size)
{
data.resize(size);
std::generate(data.begin(), data.end(), std::rand);
}
}
#endif // TEST_UTIL_H__
\ No newline at end of file
#endif // TEST_UTIL_H__
This diff is collapsed.
#ifndef TEST_UTIL_CONVERSION_H__
#define TEST_UTIL_CONVERSION_H__
#include "ble.h"
namespace testutil
{
/**
* @brief Function that convert data to string representation
* @param[in] data Data to represent as a string
* @return string representation of data
*/
static std::string asHex(const std::vector<uint8_t> &data) {
std::stringstream retval;
for (uint8_t const& value : data)
{
retval << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(value) << ' ';
}
return retval.str();
}
static std::string asHex(const uint16_t &data)
{
std::stringstream retval;
retval << std::setfill('0') << std::setw(2) << std::hex << data;
return retval.str();
}
/**
* @brief Function that convert a Bluetooth Low Energy address to string
*
* @param[in] address Bluetooth Lower Energy address
* @return string representation of provided address
*/
static std::string asText(const ble_gap_addr_t &address)
{
const int address_length = 6;
std::stringstream retval;
for (int i = sizeof(address.addr) - 1; i >= 0; --i)
{
retval << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(address.addr[i]);
if (i > 0)
{
retval << ":";
}
}
retval << "/";
switch (address.addr_type)
{
case BLE_GAP_ADDR_TYPE_PUBLIC:
retval << "PUBLIC";
break;
case BLE_GAP_ADDR_TYPE_RANDOM_STATIC:
retval << "RANDOM_STATIC";
break;
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE:
retval << "RANDOM_PRIVATE_RESOLVABLE";
break;
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE:
retval << "RANDOM_PRIVATE_NON_RESOLVABLE";
break;
default:
retval << "UNKNOWN";
break;
}
return retval.str();
}
/**
* @brief Function that convert an error code to string representation
*
* param[in] error code
*
* @return textual representation of the error
*/
static std::string errorToString(const uint32_t error_code)
{
std::stringstream retval;
retval << "error code: 0x" << std::setfill('0') << std::setw(2) << std::hex << error_code;
return retval.str();
}
/**
* @brief Function that convert a GATT status code to string representation
*
* param[in] code code
*
* @return textual representation of the code
*/
static std::string gattStatusToString(const uint16_t code)
{
std::stringstream retval;
retval << "GATT status code: 0x" << std::setfill('0') << std::setw(4) << std::hex << (uint32_t)code << ".";
return retval.str();
}
// Operator overloading for common types used
std::string asText(const sd_rpc_app_status_t &status)
{
switch (status)
{
case PKT_SEND_MAX_RETRIES_REACHED:
return "PKT_SEND_MAX_RETRIES_REACHED";
case PKT_UNEXPECTED:
return "PKT_UNEXPECTED";
case PKT_ENCODE_ERROR:
return "PKT_ENCODE_ERROR";
case PKT_DECODE_ERROR:
return "PKT_DECODE_ERROR";
case PKT_SEND_ERROR:
return "PKT_SEND_ERROR";
case IO_RESOURCES_UNAVAILABLE:
return "IO_RESOURCES_UNAVAILABLE";
case RESET_PERFORMED:
return "RESET_PERFORMED";
case CONNECTION_ACTIVE:
return "CONNECTION_ACTIVE";
default:
return "UNKNOWN";
}
}
static std::string asText(const uint16_t &value)
{
std::stringstream retval;
retval << "0x" << std::setfill('0') << std::setw(4) << std::hex << (uint32_t)value;
return retval.str();
}
static std::string asText(const uint8_t &value)
{
std::stringstream retval;
retval << "0x" << std::setfill('0') << std::setw(2) << std::hex << (uint32_t)value;
return retval.str();
}
static std::string asText(const ble_uuid_t &uuid)
{
std::stringstream retval;
retval << "uuid: [type: " << asText(uuid.type) << ", uuid: " << asText(uuid.uuid) << "]";
return retval.str();
}
static std::string asText(const ble_gattc_char_t &gattc_char)
{
std::stringstream retval;
retval << "characteristic: ["
<< "handle_decl: " << asText(gattc_char.handle_decl)
<< ", handle_value: " << asText(gattc_char.handle_value)
<< ", uuid: " << asText(gattc_char.uuid)
<< "]";
return retval.str();
}
static std::string asText(const ble_gattc_handle_range_t &gattc_handle_range)
{
std::stringstream retval;
retval << "handle range: ["
<< "start: " << asText(gattc_handle_range.start_handle)
<< ", end: " << asText(gattc_handle_range.end_handle)
<< "]";
return retval.str();
}
static std::string asText(const ble_gattc_desc_t &gattc_desc)
{
std::stringstream retval;
retval << "descriptor: ["
<< "handle: " << asText(gattc_desc.handle)
<< " " << asText(gattc_desc.uuid)
<< "]";
return retval.str();
}
static std::string asText(const sd_rpc_log_severity_t &severity)
{
switch (severity)
{
case SD_RPC_LOG_TRACE:
return "TRACE";
break;
case SD_RPC_LOG_DEBUG:
return