/** * @file test_datarouter.c * @brief 数据路由库单元测试 * * 覆盖: * - 端口管理(创建/删除/复用/边界) * - 端口类型与多 handler 增删查 * - 通道元数据查询 * - 一对多广播发送(多 handler 逐一调用) * - 运行时增删 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 int _h_total; static int _h_ids[16]; static void _h(uint32_t p, const void *d, size_t l) { (void)d; (void)l; if (_h_cnt < 16) _h_ids[_h_cnt] = (int)p; _h_cnt++; _h_total++; } 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_hstate(void) { _h_cnt = _h_total = 0; memset(_h_ids, 0, sizeof(_h_ids)); } /* ================================================================ * 1. 未初始化 * ================================================================ */ TEST_START(error_uninit) int ret = datarouter_send_sensor(0, "d", 1); CHECK(ret == -1, "expected -1, got %d", ret); TEST_END() /* ================================================================ * 2. 端口管理 * ================================================================ */ TEST_START(port_create_basic) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(p >= 0, "create returned %d", p); TEST_END() TEST_START(port_create_multiple) datarouter_port_t p1 = FIXTURE_CREATE(&_fix); datarouter_port_t p2 = FIXTURE_CREATE(&_fix); datarouter_port_t p3 = FIXTURE_CREATE(&_fix); CHECK(p1 >= 0 && p2 >= 0 && p3 >= 0, "some invalid"); CHECK(p1 != p2 && p2 != p3, "IDs should be unique"); TEST_END() TEST_START(port_create_reuse) datarouter_port_t p1 = FIXTURE_CREATE(&_fix); datarouter_port_delete(p1); datarouter_port_t p2 = FIXTURE_CREATE(&_fix); CHECK(p1 == p2, "expected reuse ID %d, got %d", p1, p2); TEST_END() TEST_START(port_delete_invalid) datarouter_port_delete(-1); datarouter_port_delete(9999); TEST_END() TEST_START(port_delete_twice) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_delete(p); datarouter_port_delete(p); _fix.count--; TEST_END() TEST_START(port_default_state) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_get_type(p) == -1, "type should be -1"); CHECK(datarouter_port_handler_count(p) == 0, "handler count should be 0"); TEST_END() TEST_START(port_create_max) int created = 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); created++; } CHECK(created >= 64, "expected 64, got %d", created); CHECK(datarouter_port_create() == DATAROUTER_INVALID_PORT, "expected INVALID after exhaustion"); TEST_END() /* ================================================================ * 3. 类型 * ================================================================ */ TEST_START(type_set_get) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); CHECK(datarouter_port_get_type(p) == DATAROUTER_CHANNEL_sensor, "type mismatch"); TEST_END() TEST_START(type_clear) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_set_type(p, -1); CHECK(datarouter_port_get_type(p) == -1, "should be -1"); TEST_END() TEST_START(type_switch) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_set_type(p, DATAROUTER_CHANNEL_status); CHECK(datarouter_port_get_type(p) == DATAROUTER_CHANNEL_status, "should be status"); TEST_END() TEST_START(type_from_invalid) CHECK(datarouter_port_get_type(-1) == -1, NULL); CHECK(datarouter_port_get_type(999) == -1, NULL); TEST_END() /* ================================================================ * 4. 多 handler 增删查 * ================================================================ */ TEST_START(handler_add_one) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_add_handler(p, _h) == 0, "add failed"); CHECK(datarouter_port_handler_count(p) == 1, "count=%d", datarouter_port_handler_count(p)); TEST_END() TEST_START(handler_add_multiple) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_add_handler(p, _h_a) == 0, "add a"); CHECK(datarouter_port_add_handler(p, _h_b) == 0, "add b"); CHECK(datarouter_port_add_handler(p, _h_c) == 0, "add c"); CHECK(datarouter_port_handler_count(p) == 3, "count=%d", datarouter_port_handler_count(p)); TEST_END() TEST_START(handler_add_duplicate) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_add_handler(p, _h) == 0, "first add"); CHECK(datarouter_port_add_handler(p, _h) == -3, "duplicate should return -3"); TEST_END() TEST_START(handler_add_max) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_add_handler(p, _h_a) == 0, "add a"); CHECK(datarouter_port_add_handler(p, _h_b) == 0, "add b"); CHECK(datarouter_port_add_handler(p, _h_c) == 0, "add c"); CHECK(datarouter_port_add_handler(p, _h_d) == 0, "add d"); CHECK(datarouter_port_handler_count(p) == DATAROUTER_MAX_HANDLERS_PER_PORT, "count=%d", datarouter_port_handler_count(p)); /* 第 5 个应返回 -2(已满) */ CHECK(datarouter_port_add_handler(p, _h) == -2, "expected -2 (full), got %d", datarouter_port_add_handler(p, _h)); TEST_END() TEST_START(handler_remove) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); datarouter_port_add_handler(p, _h_c); CHECK(datarouter_port_remove_handler(p, _h_b) == 0, "remove b"); CHECK(datarouter_port_handler_count(p) == 2, "count should be 2, got %d", datarouter_port_handler_count(p)); TEST_END() TEST_START(handler_remove_not_found) datarouter_port_t p = FIXTURE_CREATE(&_fix); CHECK(datarouter_port_remove_handler(p, _h) == -2, "expected -2"); TEST_END() TEST_START(handler_clear) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); datarouter_port_clear_handlers(p); CHECK(datarouter_port_handler_count(p) == 0, "count should be 0"); TEST_END() TEST_START(handler_from_invalid) CHECK(datarouter_port_handler_count(-1) == -1, NULL); CHECK(datarouter_port_handler_count(999) == -1, NULL); CHECK(datarouter_port_add_handler(-1, _h) == -1, NULL); CHECK(datarouter_port_remove_handler(999, _h) == -1, NULL); TEST_END() /* ================================================================ * 5. 通道元数据 * ================================================================ */ TEST_START(channel_count) CHECK(datarouter_channel_count() == 3, "expected 3"); TEST_END() TEST_START(channel_names) CHECK(strcmp(datarouter_channel_name(0), "sensor") == 0, NULL); CHECK(strcmp(datarouter_channel_name(1), "status") == 0, NULL); CHECK(strcmp(datarouter_channel_name(2), "control") == 0, NULL); TEST_END() TEST_START(channel_descs) CHECK(strcmp(datarouter_channel_desc(0), "Sensor data") == 0, NULL); CHECK(strcmp(datarouter_channel_desc(1), "Status report") == 0, NULL); CHECK(strcmp(datarouter_channel_desc(2), "Control command") == 0, NULL); TEST_END() TEST_START(channel_invalid_id) CHECK(datarouter_channel_name(-1) == NULL, NULL); CHECK(datarouter_channel_name(99) == NULL, NULL); CHECK(datarouter_channel_desc(-1) == NULL, NULL); CHECK(datarouter_channel_desc(99) == NULL, NULL); TEST_END() /* ================================================================ * 6. 发送 — 一对多广播 * ================================================================ */ TEST_START(send_one_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h); reset_hstate(); CHECK(datarouter_send_sensor(p, "d", 1) == 0, "send failed"); 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_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); datarouter_port_add_handler(p, _h_c); reset_hstate(); CHECK(datarouter_send_sensor(p, "d", 1) == 0, "send failed"); CHECK(_h_cnt == 3, "expected 3 handler calls, got %d", _h_cnt); TEST_END() TEST_START(send_type_mismatch) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h); reset_hstate(); CHECK(datarouter_send_status(p, "d", 1) == -3, "expected -3"); CHECK(_h_cnt == 0, "handler should not fire"); TEST_END() TEST_START(send_no_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); reset_hstate(); CHECK(datarouter_send_sensor(p, "d", 1) == -4, "expected -4"); TEST_END() TEST_START(send_three_channels) /* 三个通道各一个端口 */ datarouter_port_t p1 = FIXTURE_CREATE(&_fix); datarouter_port_t p2 = FIXTURE_CREATE(&_fix); datarouter_port_t p3 = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p1, DATAROUTER_CHANNEL_sensor); datarouter_port_set_type(p2, DATAROUTER_CHANNEL_status); datarouter_port_set_type(p3, DATAROUTER_CHANNEL_control); datarouter_port_add_handler(p1, _h); datarouter_port_add_handler(p2, _h); datarouter_port_add_handler(p3, _h); reset_hstate(); CHECK(datarouter_send_sensor(p1, "a", 1) == 0, NULL); CHECK(datarouter_send_status(p2, "b", 1) == 0, NULL); CHECK(datarouter_send_control(p3, "c", 1) == 0, NULL); CHECK(_h_cnt == 3, "expected 3 total calls, got %d", _h_cnt); TEST_END() /* ================================================================ * 7. 发送 — 运行时增删 handler * ================================================================ */ TEST_START(send_remove_handler) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); reset_hstate(); datarouter_send_sensor(p, "d", 1); CHECK(_h_cnt == 2, "2 handlers: count=%d", _h_cnt); datarouter_port_remove_handler(p, _h_a); reset_hstate(); datarouter_send_sensor(p, "d", 1); CHECK(_h_cnt == 1, "after remove: count=%d", _h_cnt); TEST_END() TEST_START(send_clear_handlers) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h_a); datarouter_port_add_handler(p, _h_b); datarouter_port_clear_handlers(p); CHECK(datarouter_send_sensor(p, "d", 1) == -4, "expected -4 after clear"); TEST_END() /* ================================================================ * 8. 接收回调 * ================================================================ */ static int _rx_s; static void rx_s(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _rx_s++; } static int _rx_t; static void rx_t(uint32_t p, const void *d, size_t l) { (void)p; (void)d; (void)l; _rx_t++; } void datarouter_on_recv_sensor(uint32_t p, const void *d, size_t l) { rx_s(p, d, l); } void datarouter_on_recv_status(uint32_t p, const void *d, size_t l) { rx_t(p, d, l); } TEST_START(recv_callback) _rx_s = _rx_t = 0; datarouter_on_recv_sensor(0, "data", 4); CHECK(_rx_s == 1, "sensor cb: %d", _rx_s); CHECK(_rx_t == 0, "status cb: %d", _rx_t); datarouter_on_recv_status(1, "data", 4); CHECK(_rx_t == 1, "status cb: %d", _rx_t); CHECK(_rx_s == 1, "sensor cb unchanged: %d", _rx_s); TEST_END() /* ================================================================ * 9. 错误处理 * ================================================================ */ 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_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h); datarouter_port_delete(p); CHECK(datarouter_send_sensor(p, "d", 1) == -2, "expected -2"); _fix.count--; TEST_END() /* ================================================================ * 10. 零长与 NULL * ================================================================ */ TEST_START(send_zero_length) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h); reset_hstate(); CHECK(datarouter_send_sensor(p, "x", 0) == 0, NULL); CHECK(_h_cnt == 1, "handler called %d", _h_cnt); TEST_END() TEST_START(send_null_data) datarouter_port_t p = FIXTURE_CREATE(&_fix); datarouter_port_set_type(p, DATAROUTER_CHANNEL_sensor); datarouter_port_add_handler(p, _h); reset_hstate(); CHECK(datarouter_send_sensor(p, NULL, 0) == 0, NULL); CHECK(_h_cnt == 1, "handler called %d", _h_cnt); TEST_END() /* ================================================================ * 主函数 * ================================================================ */ #define RUN(name) do { reset_hstate(); 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_multiple); RUN(port_create_reuse); RUN(port_delete_invalid); RUN(port_delete_twice); RUN(port_default_state); RUN(port_create_max); printf("\n"); datarouter_reset(); datarouter_init(); printf("[type set/get]\n"); RUN(type_set_get); RUN(type_clear); RUN(type_switch); RUN(type_from_invalid); printf("\n"); printf("[multi-handler add/remove]\n"); RUN(handler_add_one); RUN(handler_add_multiple); RUN(handler_add_duplicate); RUN(handler_add_max); RUN(handler_remove); RUN(handler_remove_not_found); RUN(handler_clear); RUN(handler_from_invalid); printf("\n"); printf("[channel introspection]\n"); RUN(channel_count); RUN(channel_names); RUN(channel_descs); RUN(channel_invalid_id); printf("\n"); printf("[send — one-to-many broadcast]\n"); RUN(send_one_handler); RUN(send_multi_handlers); RUN(send_type_mismatch); RUN(send_no_handler); RUN(send_three_channels); RUN(send_remove_handler); RUN(send_clear_handlers); RUN(send_zero_length); RUN(send_null_data); printf("\n"); printf("[receive callback]\n"); RUN(recv_callback); 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; }