diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 9a77e09..99fb425 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
struct test_pdu *pdu_list;
enum context_type context_type;
bt_uuid_t *uuid;
- size_t num_services;
- const struct gatt_service **services;
+ struct gatt_db *source_db;
const void *step;
};
.size = sizeof(data(args)), \
}
-#define define_test(name, function, type, bt_uuid, bt_services, \
+#define define_test(name, function, type, bt_uuid, db, \
test_step, args...) \
do { \
const struct test_pdu pdus[] = { \
data.context_type = type; \
data.uuid = bt_uuid; \
data.step = test_step; \
- data.services = bt_services; \
- data.num_services = sizeof(bt_services) / \
- sizeof(bt_services[0]); \
+ data.source_db = db; \
data.pdu_list = g_malloc(sizeof(pdus)); \
memcpy(data.pdu_list, pdus, sizeof(pdus)); \
g_test_add_data_func(name, &data, function); \
#define define_test_att(name, function, bt_uuid, test_step, args...) \
define_test(name, function, ATT, bt_uuid, NULL, test_step, args)
-#define define_test_client(name, function, bt_services, test_step, args...)\
- define_test(name, function, CLIENT, NULL, bt_services, test_step, args)
+#define define_test_client(name, function, source_db, test_step, args...)\
+ define_test(name, function, CLIENT, NULL, source_db, test_step, args)
-#define define_test_server(name, function, bt_services, test_step, args...)\
- define_test(name, function, SERVER, NULL, bt_services, test_step, args)
+#define define_test_server(name, function, source_db, test_step, args...)\
+ define_test(name, function, SERVER, NULL, source_db, test_step, args)
#define SERVICE_DATA_1_PDU \
raw_pdu(0x02, 0x00, 0x02), \
g_print("%s%s\n", prefix, str);
}
-static void assert_service(const struct gatt_service *a,
- struct gatt_db_attribute *attr)
+typedef void (*test_step_t)(struct context *context);
+
+struct test_step {
+ test_step_t func;
+ uint16_t handle;
+ uint16_t end_handle;
+ uint8_t uuid[16];
+ uint8_t expected_att_ecode;
+ const uint8_t *value;
+ uint16_t length;
+};
+
+struct db_attribute_test_data {
+ struct gatt_db_attribute *match;
+ bool found;
+};
+
+static bool matching_desc_data(struct gatt_db_attribute *a,
+ struct gatt_db_attribute *b)
{
- uint16_t start_handle, end_handle;
- bool primary;
- bt_uuid_t uuid;
- uint128_t u128;
+ uint16_t a_handle, b_handle;
+ const bt_uuid_t *a_uuid, *b_uuid;
- g_assert(gatt_db_attribute_get_service_data(attr, &start_handle,
- &end_handle,
- &primary, &uuid));
+ a_handle = gatt_db_attribute_get_handle(a);
+ b_handle = gatt_db_attribute_get_handle(b);
- u128 = uuid.value.u128;
+ a_uuid = gatt_db_attribute_get_type(a);
+ b_uuid = gatt_db_attribute_get_type(b);
- g_assert(a->primary && primary);
- g_assert(a->start_handle == start_handle);
- g_assert(a->end_handle == end_handle);
- g_assert(memcmp(a->uuid, u128.data, sizeof(u128.data)) == 0);
+ return a_handle == b_handle && !bt_uuid_cmp(a_uuid, b_uuid);
}
-static void assert_chrc(const struct gatt_chrc *a,
- struct gatt_db_attribute *attr)
+static void find_matching_desc(struct gatt_db_attribute *source_desc_attr,
+ void *user_data)
{
- uint16_t handle, value_handle;
- uint8_t properties;
- bt_uuid_t uuid;
- uint128_t u128;
-
- g_assert(gatt_db_attribute_get_char_data(attr, &handle,
- &value_handle,
- &properties, &uuid));
+ struct db_attribute_test_data *desc_test_data = user_data;
- u128 = uuid.value.u128;
+ if (desc_test_data->found)
+ return;
- g_assert(a->handle == handle);
- g_assert(a->value_handle == value_handle);
- g_assert(a->properties == properties);
- g_assert(memcmp(a->uuid, u128.data, sizeof(u128.data)) == 0);
+ desc_test_data->found = matching_desc_data(desc_test_data->match,
+ source_desc_attr);
}
-static void assert_desc(const struct gatt_desc *a,
- struct gatt_db_attribute *attr)
+static void match_descs(struct gatt_db_attribute *client_desc_attr,
+ void *user_data)
{
- uint16_t handle;
- const bt_uuid_t *uuid;
- uint128_t u128;
+ struct gatt_db_attribute *source_char_attr = user_data;
+ struct db_attribute_test_data desc_test_data;
- handle = gatt_db_attribute_get_handle(attr);
- uuid = gatt_db_attribute_get_type(attr);
+ desc_test_data.match = client_desc_attr;
+ desc_test_data.found = false;
- u128 = uuid->value.u128;
+ gatt_db_service_foreach_desc(source_char_attr, find_matching_desc,
+ &desc_test_data);
- g_assert(a->handle == handle);
- g_assert(memcmp(a->uuid, u128.data, sizeof(u128.data)) == 0);
+ g_assert(desc_test_data.found);
}
-typedef void (*test_step_t)(struct context *context);
-
-struct test_step {
- test_step_t func;
- uint16_t handle;
- uint16_t end_handle;
- uint8_t uuid[16];
- uint8_t expected_att_ecode;
- const uint8_t *value;
- uint16_t length;
-};
-
-struct service_test_data {
- const struct test_data *data;
- size_t svc_index;
- size_t chrc_index;
- size_t desc_index;
-};
+static bool matching_char_data(struct gatt_db_attribute *a,
+ struct gatt_db_attribute *b)
+{
+ uint16_t a_handle, b_handle, a_value_handle, b_value_handle;
+ uint8_t a_properties, b_properties;
+ bt_uuid_t a_uuid, b_uuid;
+
+ gatt_db_attribute_get_char_data(a, &a_handle, &a_value_handle,
+ &a_properties, &a_uuid);
+ gatt_db_attribute_get_char_data(b, &b_handle, &b_value_handle,
+ &b_properties, &b_uuid);
+
+ return a_handle == b_handle && a_value_handle == b_value_handle &&
+ a_properties == b_properties &&
+ !bt_uuid_cmp(&a_uuid, &b_uuid);
+}
-static void compare_desc(struct gatt_db_attribute *attr, void *user_data)
+static void find_matching_char(struct gatt_db_attribute *source_char_attr,
+ void *user_data)
{
- struct service_test_data *test_data = user_data;
- const struct gatt_service *svc;
- const struct gatt_chrc *chrc;
+ struct db_attribute_test_data *char_test_data = user_data;
- svc = test_data->data->services[test_data->svc_index];
- chrc = svc->chars[test_data->chrc_index];
- g_assert(test_data->desc_index < chrc->num_descs);
+ if (char_test_data->found)
+ return;
- assert_desc(&chrc->descs[test_data->desc_index], attr);
+ if (matching_char_data(char_test_data->match, source_char_attr)) {
- test_data->desc_index++;
+ gatt_db_service_foreach_desc(char_test_data->match, match_descs,
+ source_char_attr);
+ char_test_data->found = true;
+ }
}
-static void compare_chrc(struct gatt_db_attribute *attr, void *user_data)
+static void match_chars(struct gatt_db_attribute *client_char_attr,
+ void *user_data)
{
- struct service_test_data *test_data = user_data;
- const struct gatt_service *svc;
- const struct gatt_chrc *chrc;
+ struct gatt_db_attribute *source_serv_attr = user_data;
+ struct db_attribute_test_data char_test_data;
- svc = test_data->data->services[test_data->svc_index];
- g_assert(test_data->chrc_index < svc->num_chars);
- chrc = svc->chars[test_data->chrc_index];
+ char_test_data.match = client_char_attr;
+ char_test_data.found = false;
- assert_chrc(chrc, attr);
+ gatt_db_service_foreach_char(source_serv_attr, find_matching_char,
+ &char_test_data);
- test_data->desc_index = 0;
+ g_assert(char_test_data.found);
+}
- gatt_db_service_foreach_desc(attr, compare_desc, test_data);
- g_assert(test_data->desc_index == chrc->num_descs);
+static bool matching_service_data(struct gatt_db_attribute *a,
+ struct gatt_db_attribute *b)
+{
+ uint16_t a_start, b_start, a_end, b_end;
+ bool a_primary, b_primary;
+ bt_uuid_t a_uuid, b_uuid;
- test_data->chrc_index++;
+ gatt_db_attribute_get_service_data(a, &a_start, &a_end, &a_primary,
+ &a_uuid);
+ gatt_db_attribute_get_service_data(b, &b_start, &b_end, &b_primary,
+ &b_uuid);
+
+ return a_start == b_start && a_end == b_end && a_primary == b_primary &&
+ !bt_uuid_cmp(&a_uuid, &b_uuid);
}
-static void compare_service(struct gatt_db_attribute *attr, void *user_data)
+static void find_matching_service(struct gatt_db_attribute *source_serv_attr,
+ void *user_data)
{
- struct service_test_data *test_data = user_data;
- const struct gatt_service *svc;
+ struct db_attribute_test_data *serv_test_data = user_data;
+
+ if (serv_test_data->found)
+ return;
- g_assert(test_data->svc_index < test_data->data->num_services);
- svc = test_data->data->services[test_data->svc_index];
+ if (matching_service_data(serv_test_data->match, source_serv_attr)) {
+ gatt_db_service_foreach_char(serv_test_data->match, match_chars,
+ source_serv_attr);
+ serv_test_data->found = true;
+ }
+}
- assert_service(test_data->data->services[test_data->svc_index], attr);
+static void match_services(struct gatt_db_attribute *client_serv_attr,
+ void *user_data)
+{
+ struct gatt_db *source_db = user_data;
+ struct db_attribute_test_data serv_test_data;
- test_data->chrc_index = 0;
+ serv_test_data.match = client_serv_attr;
+ serv_test_data.found = false;
- gatt_db_service_foreach_char(attr, compare_chrc, test_data);
- g_assert(test_data->chrc_index == svc->num_chars);
+ gatt_db_foreach_service(source_db,
+ find_matching_service, &serv_test_data);
- test_data->svc_index++;
+ g_assert(serv_test_data.found);
}
static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
{
struct context *context = user_data;
- struct service_test_data test_data;
g_assert(success);
- test_data.data = context->data;
- test_data.svc_index = 0;
-
- if (!test_data.data->services) {
+ if (!context->data->source_db) {
context_quit(context);
return;
}
g_assert(context->client);
g_assert(context->client_db);
- gatt_db_foreach_service(context->client_db, compare_service,
- &test_data);
- g_assert(test_data.svc_index == test_data.data->num_services);
+ gatt_db_foreach_service(context->client_db, match_services,
+ context->data->source_db);
if (context->data->step) {
const struct test_step *step = context->data->step;
.expected_att_ecode = 0x08,
};
+static void att_write_cb(struct gatt_db_attribute *att, int err,
+ void *user_data)
+{
+ g_assert(!err);
+}
+
+static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
+ struct gatt_db_attribute *service_att,
+ bt_uuid_t *uuid,
+ uint32_t att_permissions,
+ uint8_t char_properties,
+ const void *value, size_t len)
+{
+ struct gatt_db_attribute *attrib;
+
+ attrib = gatt_db_service_add_characteristic(service_att, uuid,
+ att_permissions,
+ char_properties,
+ NULL, NULL,
+ NULL);
+
+ gatt_db_attribute_write(attrib, 0, value, len, 0x00, NULL, att_write_cb,
+ NULL);
+
+ return attrib;
+}
+
+static struct gatt_db_attribute *
+add_user_description(struct gatt_db_attribute *chrc_att, const char *desc,
+ bool writable)
+{
+ struct gatt_db_attribute *desc_att;
+ bt_uuid_t uuid;
+ uint32_t permissions = BT_ATT_PERM_READ;
+
+ if (writable)
+ permissions |= BT_ATT_PERM_WRITE;
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
+ desc_att = gatt_db_service_add_descriptor(chrc_att, &uuid, permissions,
+ NULL, NULL, NULL);
+
+ gatt_db_attribute_write(desc_att, 0, (uint8_t *)desc, strlen(desc),
+ 0x00, NULL, att_write_cb, NULL);
+
+ return desc_att;
+}
+
+
+typedef struct gatt_db_attribute (*add_service_func) (struct gatt_db *db,
+ uint16_t handle,
+ bool primary,
+ uint16_t extra_handles);
+
+static struct gatt_db *make_service_data_1_db(void)
+{
+ struct gatt_db *db = gatt_db_new();
+ struct gatt_db_attribute *serv_att, *chrc_att;
+ bt_uuid_t uuid;
+
+ bt_string_to_uuid(&uuid, GATT_UUID);
+ serv_att = gatt_db_insert_service(db, 0x0001, &uuid, true, 4);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
+ chrc_att = add_char_with_value(db, serv_att, &uuid, BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ, "BlueZ", 5);
+
+ add_user_description(chrc_att, "Device Name", false);
+
+ bt_string_to_uuid(&uuid, HEART_RATE_UUID);
+ serv_att = gatt_db_insert_service(db, 0x0005, &uuid, true, 4);
+
+ bt_uuid16_create(&uuid, GATT_CHARAC_MANUFACTURER_NAME_STRING);
+ chrc_att = gatt_db_service_add_characteristic(serv_att, &uuid,
+ BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ,
+ NULL, NULL, NULL);
+
+ add_user_description(chrc_att, "Manufacturer Name", false);
+
+ return db;
+}
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(512, data);
int main(int argc, char *argv[])
{
+ struct gatt_db *service_db_1;
+
g_test_init(&argc, &argv, NULL);
+ service_db_1 = make_service_data_1_db();
+
/*
* Server Configuration
*
raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
0x05, 0x29));
- define_test_client("/TP/GAR/CL/BV-01-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BV-01-C", test_client, service_db_1,
&test_read_1,
SERVICE_DATA_1_PDU,
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x0b, 0x01, 0x02, 0x03));
- define_test_client("/TP/GAR/CL/BI-01-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-01-C", test_client, service_db_1,
&test_read_2,
SERVICE_DATA_1_PDU,
raw_pdu(0x0a, 0x00, 0x00),
raw_pdu(0x01, 0x0a, 0x00, 0x00, 0x01));
- define_test_client("/TP/GAR/CL/BI-02-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-02-C", test_client, service_db_1,
&test_read_3,
SERVICE_DATA_1_PDU,
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x02));
- define_test_client("/TP/GAR/CL/BI-03-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-03-C", test_client, service_db_1,
&test_read_4,
SERVICE_DATA_1_PDU,
raw_pdu(0x0a, 0x03, 0x00),
raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0c));
- define_test_client("/TP/GAR/CL/BV-05-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BV-05-C", test_client, service_db_1,
&test_multiple_read_1,
SERVICE_DATA_1_PDU,
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x0f, 0x01, 0x02, 0x03));
- define_test_client("/TP/GAR/CL/BI-18-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-18-C", test_client, service_db_1,
&test_multiple_read_2,
SERVICE_DATA_1_PDU,
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x02));
- define_test_client("/TP/GAR/CL/BI-19-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-19-C", test_client, service_db_1,
&test_multiple_read_3,
SERVICE_DATA_1_PDU,
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x01));
- define_test_client("/TP/GAR/CL/BI-20-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-20-C", test_client, service_db_1,
&test_multiple_read_4,
SERVICE_DATA_1_PDU,
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x08));
- define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_db_1,
&test_multiple_read_5,
SERVICE_DATA_1_PDU,
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x05));
- define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_data_1,
+ define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_db_1,
&test_multiple_read_6,
SERVICE_DATA_1_PDU,
raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),