/** * @file test_datarouter.c * @brief 数据路由库单元测试 * * 覆盖: * - 端口管理 * - send_type / recv_type 独立设置 * - 多 handler 增删 * - 发送调用(一对多广播) * - 接收回调 * - 发送/接收能力元数据各自独立 * - 错误处理 */ #include "datarouter.h" #include #include /* ================================================================ * 测试框架 * ================================================================ */ static int _total_run, _total_pass, _total_fail; static int _err; static const char *_cur_name; #define FIXTURE_MAX 16 typedef struct { datarouter_port_t ports[FIXTURE_MAX]; int count; } fixture_t; #define FIXTURE_INIT(f) memset((f), 0, sizeof(*(f))) #define FIXTURE_PUSH(f, p) do { if ((f)->count < FIXTURE_MAX) (f)->ports[(f)->count++] = (p); } while (0) #define FIXTURE_CLEAN(f) do { for (int _i = 0; _i < (f)->count; _i++) datarouter_port_delete((f)->ports[_i]); } while (0) #define FIXTURE_CREATE(f) ({ datarouter_port_t _p = datarouter_port_create(); FIXTURE_PUSH(f, _p); _p; }) #define TEST_START(name) \ static void test_##name(void) \ { \ fixture_t _fix; \ FIXTURE_INIT(&_fix); \ _cur_name = #name; \ _err = 0; #define TEST_END() \ cleanup: \ FIXTURE_CLEAN(&_fix); \ if (_err) { _total_fail++; printf(" FAIL %s\n", _cur_name); } \ else { _total_pass++; printf(" PASS %s\n", _cur_name); } \ _total_run++; \ } #define CHECK(cond, ...) do { \ if (!(cond)) { \ printf(" %s [line %d]: ", _cur_name, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ _err = 1; \ goto cleanup; \ } \ } while (0) /* ================================================================ * 测试用 handler * ================================================================ */ static int _h_cnt; static void _h(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } static void _h_a(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } static void _h_b(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } static void _h_c(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } static void _h_d(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _h_cnt++; } static void reset_h(void) { _h_cnt = 0; } /* ================================================================ * 1. 未初始化 * ================================================================ */ TEST_START(error_uninit) CHECK(datarouter_send_sensor(0, "d", 1) == -1, "expected -1"); TEST_END() /* ================================================================ * 2. 端口管理 * ================================================================ */ TEST_START(port_create_basic) CHECK(FIXTURE_CREATE(&_fix) >= 0, "create failed"); TEST_END() TEST_START(port_create_max) int c = 0; for (int i = 0; i < 64; i++) { datarouter_port_t p = datarouter_port_create(); if (p == DATAROUTER_INVALID_PORT) break; FIXTURE_PUSH(&_fix, p); c++; } CHECK(c >= 64, "got %d", c); CHECK(datarouter_port_create() == DATAROUTER_INVALID_PORT, NULL); TEST_END() TEST_START(port_delete_invalid) datarouter_port_delete(-1); datarouter_port_delete(999); TEST_END() TEST_START(port_default_state) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_get_send_type(p) == -1, "send_type should be -1"); CHECK(datarouter_port_get_recv_type(p) == -1, "recv_type should be -1"); CHECK(datarouter_port_handler_count(p) == 0, "handler count 0"); TEST_END() /* ================================================================ * 3. send_type / recv_type 独立设置 * ================================================================ */ TEST_START(send_type_set_get) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); CHECK(datarouter_port_get_send_type(p) == DATAROUTER_SEND_sensor, NULL); TEST_END() TEST_START(recv_type_set_get) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm); CHECK(datarouter_port_get_recv_type(p) == DATAROUTER_RECV_rtcm, NULL); TEST_END() TEST_START(types_independent) /* 一个端口同时设置 send_type 和 recv_type,互不干扰 */ datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_set_recv_type(p, DATAROUTER_RECV_command); CHECK(datarouter_port_get_send_type(p) == DATAROUTER_SEND_sensor, NULL); CHECK(datarouter_port_get_recv_type(p) == DATAROUTER_RECV_command, NULL); TEST_END() TEST_START(send_type_clear) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_set_send_type(p, -1); CHECK(datarouter_port_get_send_type(p) == -1, NULL); TEST_END() TEST_START(recv_type_clear) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm); datarouter_port_set_recv_type(p, -1); CHECK(datarouter_port_get_recv_type(p) == -1, NULL); TEST_END() TEST_START(types_from_invalid) CHECK(datarouter_port_get_send_type(-1) == -1, NULL); CHECK(datarouter_port_get_recv_type(-1) == -1, NULL); CHECK(datarouter_port_get_send_type(999) == -1, NULL); CHECK(datarouter_port_get_recv_type(999) == -1, NULL); TEST_END() /* ================================================================ * 4. 多 handler * ================================================================ */ TEST_START(handler_add_remove) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_add_handler(p, _h_a) == 0, NULL); CHECK(datarouter_port_add_handler(p, _h_b) == 0, NULL); CHECK(datarouter_port_handler_count(p) == 2, NULL); CHECK(datarouter_port_remove_handler(p, _h_a) == 0, NULL); CHECK(datarouter_port_handler_count(p) == 1, NULL); TEST_END() TEST_START(handler_clear) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_add_handler(p, _h); datarouter_port_clear_handlers(p); CHECK(datarouter_port_handler_count(p) == 0, NULL); TEST_END() /* ================================================================ * 5. 发送触发 * ================================================================ */ TEST_START(send_one_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); CHECK(datarouter_send_sensor(p, "d", 1) == 0, NULL); CHECK(_h_cnt == 1, "handler called %d times", _h_cnt); TEST_END() TEST_START(send_multi_handlers) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); datarouter_port_add_handler(p, _h_c); reset_h(); CHECK(datarouter_send_sensor(p, "d", 1) == 0, NULL); CHECK(_h_cnt == 3, "handler called %d times", _h_cnt); TEST_END() TEST_START(send_type_mismatch) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); CHECK(datarouter_send_status(p, "d", 1) == -3, "expected -3"); CHECK(_h_cnt == 0, NULL); TEST_END() TEST_START(send_no_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); CHECK(datarouter_send_sensor(p, "d", 1) == -4, "expected -4"); TEST_END() TEST_START(send_no_send_type) /* 端口只有 recv_type,没有 send_type */ datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_recv_type(p, DATAROUTER_RECV_rtcm); CHECK(datarouter_send_sensor(p, "d", 1) == -3, "expected -3 (send_type unset)"); TEST_END() TEST_START(send_remove_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); reset_h(); datarouter_send_sensor(p, "d", 1); CHECK(_h_cnt == 2, NULL); datarouter_port_remove_handler(p, _h_a); reset_h(); datarouter_send_sensor(p, "d", 1); CHECK(_h_cnt == 1, NULL); TEST_END() TEST_START(send_clear_handlers) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); datarouter_port_clear_handlers(p); CHECK(datarouter_send_sensor(p, "d", 1) == -4, "expected -4"); TEST_END() TEST_START(send_zero_length) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); CHECK(datarouter_send_sensor(p, "x", 0) == 0, NULL); CHECK(_h_cnt == 1, NULL); TEST_END() TEST_START(send_null_data) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); reset_h(); CHECK(datarouter_send_sensor(p, NULL, 0) == 0, NULL); CHECK(_h_cnt == 1, NULL); TEST_END() /* ================================================================ * 6. 接收回调 * ================================================================ */ static int _rx_r, _rx_c; void datarouter_on_recv_rtcm(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _rx_r++; } void datarouter_on_recv_command(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _rx_c++; } TEST_START(recv_callbacks) _rx_r = _rx_c = 0; datarouter_on_recv_rtcm(0, "d", 1); CHECK(_rx_r == 1 && _rx_c == 0, "rtcm=%d cmd=%d", _rx_r, _rx_c); datarouter_on_recv_command(1, "d", 1); CHECK(_rx_r == 1 && _rx_c == 1, "rtcm=%d cmd=%d", _rx_r, _rx_c); TEST_END() /* ================================================================ * 7. 能力元数据(两组独立) * ================================================================ */ TEST_START(send_cap_meta) CHECK(datarouter_send_cap_count() == 2, NULL); CHECK(strcmp(datarouter_send_cap_name(0), "sensor") == 0, NULL); CHECK(strcmp(datarouter_send_cap_desc(0), "Sensor data report") == 0, NULL); CHECK(strcmp(datarouter_send_cap_name(1), "status") == 0, NULL); CHECK(strcmp(datarouter_send_cap_desc(1), "Device status report") == 0, NULL); CHECK(datarouter_send_cap_name(-1) == NULL, NULL); CHECK(datarouter_send_cap_name(99) == NULL, NULL); TEST_END() TEST_START(recv_cap_meta) CHECK(datarouter_recv_cap_count() == 2, NULL); CHECK(strcmp(datarouter_recv_cap_name(0), "rtcm") == 0, NULL); CHECK(strcmp(datarouter_recv_cap_desc(0), "RTCM correction data") == 0, NULL); CHECK(strcmp(datarouter_recv_cap_name(1), "command") == 0, NULL); CHECK(strcmp(datarouter_recv_cap_desc(1), "Remote control command") == 0, NULL); CHECK(datarouter_recv_cap_name(-1) == NULL, NULL); CHECK(datarouter_recv_cap_desc(99) == NULL, NULL); TEST_END() /* ================================================================ * 8. 错误 * ================================================================ */ TEST_START(error_invalid_port) CHECK(datarouter_send_sensor(999, "d", 1) == -2, NULL); CHECK(datarouter_send_sensor(-1, "d", 1) == -2, NULL); TEST_END() TEST_START(error_deleted_port) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_send_type(p, DATAROUTER_SEND_sensor); datarouter_port_add_handler(p, _h); datarouter_port_delete(p); CHECK(datarouter_send_sensor(p, "d", 1) == -2, NULL); _fix.count--; TEST_END() /* ================================================================ * 主函数 * ================================================================ */ #define RUN(name) do { reset_h(); test_##name(); } while (0) int main(void) { printf("==== DataRouter Unit Tests ====\n\n"); printf("[uninitialized]\n"); RUN(error_uninit); datarouter_init(); printf("\n[port management]\n"); RUN(port_create_basic); RUN(port_create_max); RUN(port_delete_invalid); RUN(port_default_state); printf("\n"); datarouter_reset(); datarouter_init(); printf("[send_type / recv_type]\n"); RUN(send_type_set_get); RUN(recv_type_set_get); RUN(types_independent); RUN(send_type_clear); RUN(recv_type_clear); RUN(types_from_invalid); printf("\n"); printf("[handler add/remove]\n"); RUN(handler_add_remove); RUN(handler_clear); printf("\n"); printf("[send trigger]\n"); RUN(send_one_handler); RUN(send_multi_handlers); RUN(send_type_mismatch); RUN(send_no_handler); RUN(send_no_send_type); RUN(send_remove_handler); RUN(send_clear_handlers); RUN(send_zero_length); RUN(send_null_data); printf("\n"); printf("[receive callback]\n"); RUN(recv_callbacks); printf("\n"); printf("[capability metadata]\n"); RUN(send_cap_meta); RUN(recv_cap_meta); printf("\n"); printf("[error handling]\n"); RUN(error_invalid_port); RUN(error_deleted_port); printf("\n"); printf("==============================\n"); printf(" total: %d | pass: %d | fail: %d\n\n", _total_run, _total_pass, _total_fail); return _total_fail > 0 ? 1 : 0; }