Files
2026-08-24 10:03:24 +08:00

402 lines
9.7 KiB
C

/*
* test-utils.c
* SPDX-FileCopyrightText: 2016-2025 BlueALSA developers
* SPDX-License-Identifier: MIT
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <bluetooth/bluetooth.h>
#include <check.h>
#include "error.h"
#include "hci.h"
#include "utils.h"
#include "shared/defs.h"
#include "shared/ffb.h"
#include "shared/hex.h"
#include "shared/nv.h"
#include "shared/rc.h"
#include "shared/rt.h"
#include "inc/check.inc"
CK_START_TEST(test_g_dbus_bluez_object_path_to_hci_dev_id) {
ck_assert_int_eq(g_dbus_bluez_object_path_to_hci_dev_id("/org/bluez"), -1);
ck_assert_int_eq(g_dbus_bluez_object_path_to_hci_dev_id("/org/bluez/hci0"), 0);
ck_assert_int_eq(g_dbus_bluez_object_path_to_hci_dev_id("/org/bluez/hci5"), 5);
} CK_END_TEST
CK_START_TEST(test_g_dbus_bluez_object_path_to_bdaddr) {
bdaddr_t addr_ok = {{ 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12 }};
bdaddr_t addr;
ck_assert_ptr_eq(g_dbus_bluez_object_path_to_bdaddr(
"/org/bluez/hci0/dev_12_34_56_78_9A_BC", &addr), &addr);
ck_assert_int_eq(bacmp(&addr, &addr_ok), 0);
ck_assert_ptr_eq(g_dbus_bluez_object_path_to_bdaddr(
"/org/bluez/dev_12_34_56_78_9A_BC/fd1", &addr), &addr);
ck_assert_int_eq(bacmp(&addr, &addr_ok), 0);
ck_assert_ptr_eq(g_dbus_bluez_object_path_to_bdaddr(
"/org/bluez/dev_12_34_56_78_9A_XX", &addr), NULL);
} CK_END_TEST
CK_START_TEST(test_g_variant_sanitize_object_path) {
char path1[] = "/some/valid_path/123";
char path2[] = "/a#$*/invalid-path";
ck_assert_str_eq(g_variant_sanitize_object_path(path1), "/some/valid_path/123");
ck_assert_str_eq(g_variant_sanitize_object_path(path2), "/a___/invalid_path");
} CK_END_TEST
#if DEBUG
CK_START_TEST(test_batostr_) {
const bdaddr_t ba = {{ 1, 2, 3, 4, 5, 6 }};
char tmp[18];
ba2str(&ba, tmp);
ck_assert_str_eq(batostr_(&ba), tmp);
} CK_END_TEST
#endif
CK_START_TEST(test_error_code_strerror) {
ck_assert_str_eq(error_code_strerror(ERROR_CODE_INVALID_SIZE), "Invalid size");
ck_assert_str_eq(error_code_strerror(0xFFFF), "Unknown error");
} CK_END_TEST
CK_START_TEST(test_nv_lookup_entry) {
const nv_entry_t entries[] = {
{ "name1", .v.i = 1 },
{ "name2", .v.i = 2 },
{ 0 }
};
ck_assert_ptr_eq(nv_lookup_entry(entries, "invalid"), NULL);
ck_assert_ptr_eq(nv_lookup_entry(entries, "name2"), &entries[1]);
} CK_END_TEST
CK_START_TEST(test_nv_name_from_int) {
const nv_entry_t entries[] = {
{ "name1", .v.i = 1 },
{ "name2", .v.i = -42 },
{ 0 }
};
ck_assert_ptr_eq(nv_name_from_int(entries, 0), NULL);
ck_assert_str_eq(nv_name_from_int(entries, -42), "name2");
} CK_END_TEST
CK_START_TEST(test_nv_name_from_uint) {
const nv_entry_t entries[] = {
{ "name1", .v.u = 1 },
{ "name2", .v.u = 0xFFEEDDCC },
{ 0 }
};
ck_assert_ptr_eq(nv_name_from_uint(entries, 0), NULL);
ck_assert_str_eq(nv_name_from_uint(entries, 0xFFEEDDCC), "name2");
} CK_END_TEST
CK_START_TEST(test_nv_join_names) {
const nv_entry_t entries_zero[] = {{ 0 }};
const nv_entry_t entries[] = {
{ "name1", .v.i = 1 },
{ "name2", .v.i = 2 },
{ 0 }
};
char *tmp;
ck_assert_str_eq(tmp = nv_join_names(entries_zero), "");
free(tmp);
ck_assert_str_eq(tmp = nv_join_names(entries), "name1, name2");
free(tmp);
} CK_END_TEST
struct test_rc {
rc_t rc;
bool freed;
};
static void test_rc_free(void * ptr) {
struct test_rc * tmp = ptr;
tmp->freed = true;
}
CK_START_TEST(test_rc_callback) {
struct test_rc rc;
rc_init(&rc.rc, test_rc_free);
ck_assert_int_eq(rc.rc.count, 1);
rc.freed = false;
ck_assert_ptr_eq(rc_ref(&rc), &rc);
ck_assert_int_eq(rc.rc.count, 2);
ck_assert_int_eq(rc.freed, false);
ck_assert_int_eq(rc_unref_with_count(&rc), 1);
ck_assert_int_eq(rc.rc.count, 1);
ck_assert_int_eq(rc.freed, false);
ck_assert_int_eq(rc_unref_with_count(&rc), 0);
ck_assert_int_eq(rc.rc.count, 0);
ck_assert_int_eq(rc.freed, true);
} CK_END_TEST
CK_START_TEST(test_difftimespec) {
struct timespec ts1, ts2, ts;
ts1.tv_sec = ts2.tv_sec = 12345;
ts1.tv_nsec = ts2.tv_nsec = 67890;
ck_assert_int_eq(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 0);
ck_assert_int_eq(ts.tv_nsec, 0);
ts1.tv_sec = 10;
ts1.tv_nsec = 100000000;
ts2.tv_sec = 10;
ts2.tv_nsec = 500000000;
ck_assert_int_gt(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 0);
ck_assert_int_eq(ts.tv_nsec, 400000000);
ts1.tv_sec = 10;
ts1.tv_nsec = 100000000;
ts2.tv_sec = 11;
ts2.tv_nsec = 500000000;
ck_assert_int_gt(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 1);
ck_assert_int_eq(ts.tv_nsec, 400000000);
ts1.tv_sec = 10;
ts1.tv_nsec = 800000000;
ts2.tv_sec = 12;
ts2.tv_nsec = 100000000;
ck_assert_int_gt(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 1);
ck_assert_int_eq(ts.tv_nsec, 300000000);
ts1.tv_sec = 10;
ts1.tv_nsec = 500000000;
ts2.tv_sec = 10;
ts2.tv_nsec = 100000000;
ck_assert_int_lt(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 0);
ck_assert_int_eq(ts.tv_nsec, 400000000);
ts1.tv_sec = 12;
ts1.tv_nsec = 100000000;
ts2.tv_sec = 10;
ts2.tv_nsec = 800000000;
ck_assert_int_lt(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 1);
ck_assert_int_eq(ts.tv_nsec, 300000000);
ts1.tv_sec = 12;
ts1.tv_nsec = 500000000;
ts2.tv_sec = 10;
ts2.tv_nsec = 500000000;
ck_assert_int_lt(difftimespec(&ts1, &ts2, &ts), 0);
ck_assert_int_eq(ts.tv_sec, 2);
ck_assert_int_eq(ts.tv_nsec, 0);
} CK_END_TEST
CK_START_TEST(test_ffb) {
ffb_t ffb_u8 = { 0 };
ffb_t ffb_16 = { 0 };
/* allow free before allocation */
ffb_free(&ffb_u8);
ffb_free(&ffb_16);
ck_assert_int_eq(ffb_init_uint8_t(&ffb_u8, 64), 0);
ck_assert_ptr_eq(ffb_u8.data, ffb_u8.tail);
ck_assert_int_eq(ffb_u8.nmemb, 64);
ck_assert_int_eq(ffb_init_int16_t(&ffb_16, 64), 0);
ck_assert_ptr_eq(ffb_16.data, ffb_16.tail);
ck_assert_int_eq(ffb_16.nmemb, 64);
memcpy(ffb_u8.data, "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ", 36);
ffb_seek(&ffb_u8, 36);
memcpy(ffb_16.data, "11223344556677889900AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ", 36 * 2);
ffb_seek(&ffb_16, 36);
ck_assert_int_eq(ffb_len_in(&ffb_u8), 64 - 36);
ck_assert_int_eq(ffb_blen_in(&ffb_u8), 64 - 36);
ck_assert_int_eq(ffb_len_out(&ffb_u8), 36);
ck_assert_int_eq(ffb_blen_out(&ffb_u8), 36);
ck_assert_int_eq(((uint8_t *)ffb_u8.tail)[-1], 'Z');
ck_assert_int_eq(ffb_len_in(&ffb_16), 64 - 36);
ck_assert_int_eq(ffb_blen_in(&ffb_16), (64 - 36) * 2);
ck_assert_int_eq(ffb_len_out(&ffb_16), 36);
ck_assert_int_eq(ffb_blen_out(&ffb_16), 36 * 2);
ck_assert_int_eq(((int16_t *)ffb_16.tail)[-1], 0x5a5a);
ck_assert_int_eq(ffb_shift(&ffb_u8, 33), 33);
ck_assert_int_eq(ffb_len_in(&ffb_u8), 64 - (36 - 33));
ck_assert_int_eq(ffb_len_out(&ffb_u8), 36 - 33);
ck_assert_mem_eq(ffb_u8.data, "XYZ", ffb_len_out(&ffb_u8));
ck_assert_int_eq(((uint8_t *)ffb_u8.tail)[-1], 'Z');
ck_assert_int_eq(ffb_shift(&ffb_u8, 100), 36 - 33);
ck_assert_ptr_eq(ffb_u8.data, ffb_u8.tail);
ffb_seek(&ffb_u8, 4);
ck_assert_ptr_ne(ffb_u8.data, ffb_u8.tail);
ffb_rewind(&ffb_u8);
ck_assert_ptr_eq(ffb_u8.data, ffb_u8.tail);
ffb_free(&ffb_u8);
ck_assert_ptr_eq(ffb_u8.data, NULL);
ffb_free(&ffb_16);
ck_assert_ptr_eq(ffb_16.data, NULL);
} CK_END_TEST
CK_START_TEST(test_ffb_static) {
ffb_t ffb = { 0 };
uint32_t buffer[64];
ffb_init_from_array(&ffb, buffer);
ck_assert_ptr_eq(ffb.data, buffer);
ck_assert_ptr_eq(ffb.tail, buffer);
ck_assert_uint_eq(ffb.nmemb, ARRAYSIZE(buffer));
ck_assert_uint_eq(ffb.size, 4);
} CK_END_TEST
CK_START_TEST(test_ffb_resize) {
const char *data = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const size_t data_len = strlen(data);
ffb_t ffb = { 0 };
ck_assert_int_eq(ffb_init_uint8_t(&ffb, 64), 0);
memcpy(ffb.data, data, data_len);
ffb_seek(&ffb, data_len);
ck_assert_int_eq(ffb_len_out(&ffb), data_len);
ck_assert_int_eq(ffb_len_in(&ffb), 64 - data_len);
ck_assert_mem_eq(ffb.data, data, data_len);
ck_assert_int_eq(ffb_init_uint8_t(&ffb, 128), 0);
ck_assert_int_eq(ffb_len_out(&ffb), data_len);
ck_assert_int_eq(ffb_len_in(&ffb), 128 - data_len);
ck_assert_mem_eq(ffb.data, data, data_len);
ffb_free(&ffb);
} CK_END_TEST
CK_START_TEST(test_bin2hex) {
const uint8_t bin[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0xFF };
char hex[sizeof(bin) * 2 + 1];
ck_assert_int_eq(bin2hex(bin, hex, sizeof(bin)), 12);
ck_assert_str_eq(hex, "deadbeef00ff");
} CK_END_TEST
CK_START_TEST(test_hex2bin) {
const uint8_t bin_ok[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00 };
const char hex[] = "DEADbeef\x00\xFF";
uint8_t bin[sizeof(bin_ok)];
ck_assert_int_eq(hex2bin(hex, bin, sizeof(hex) - 1), 5);
ck_assert_mem_eq(bin, bin_ok, sizeof(bin));
ck_assert_int_eq(hex2bin(hex, bin, 3), -1);
ck_assert_int_eq(errno, EINVAL);
} CK_END_TEST
int main(void) {
Suite *s = suite_create(__FILE__);
TCase *tc = tcase_create(__FILE__);
SRunner *sr = srunner_create(s);
suite_add_tcase(s, tc);
/* error.c */
tcase_add_test(tc, test_error_code_strerror);
/* shared/ffb.c */
tcase_add_test(tc, test_ffb);
tcase_add_test(tc, test_ffb_static);
tcase_add_test(tc, test_ffb_resize);
/* shared/hex.c */
tcase_add_test(tc, test_bin2hex);
tcase_add_test(tc, test_hex2bin);
/* shared/nv.c */
tcase_add_test(tc, test_nv_lookup_entry);
tcase_add_test(tc, test_nv_name_from_int);
tcase_add_test(tc, test_nv_name_from_uint);
tcase_add_test(tc, test_nv_join_names);
/* shared/rc.c */
tcase_add_test(tc, test_rc_callback);
/* shared/rt.c */
tcase_add_test(tc, test_difftimespec);
tcase_add_test(tc, test_g_dbus_bluez_object_path_to_hci_dev_id);
tcase_add_test(tc, test_g_dbus_bluez_object_path_to_bdaddr);
tcase_add_test(tc, test_g_variant_sanitize_object_path);
#if DEBUG
tcase_add_test(tc, test_batostr_);
#endif
srunner_run_all(sr, CK_ENV);
int nf = srunner_ntests_failed(sr);
srunner_free(sr);
return nf == 0 ? 0 : 1;
}