/**
 * @file    test_icp67.c
 * @brief   ICP67 协议库单元测试 — 覆盖帧操作、编解码、重传管理
 */
#include "myIcp67.h"
#include "icp67.h"
#include "myLog.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <semaphore.h>
#include <pthread.h>

static int  g_test_pass = 0;
static int  g_test_fail = 0;
static char g_test_name[128];

#define TEST(name) \
	do { \
		snprintf(g_test_name, sizeof(g_test_name), "%s", name); \
		printf("  TEST: %s ... ", g_test_name); \
	} while(0)

#define PASS() do { printf("PASS\n"); g_test_pass++; } while(0)
#define FAIL(msg) do { printf("FAIL: %s\n", msg); g_test_fail++; } while(0)

#define ASSERT_EQ(a, b) \
	do { \
		if((a) != (b)) { \
			char buf[128]; \
			snprintf(buf, sizeof(buf), "%s:%d ASSERT_EQ(%d, %d)", __func__, __LINE__, (int)(a), (int)(b)); \
			FAIL(buf); return; \
		} \
	} while(0)

#define ASSERT_TRUE(cond) \
	do { \
		if(!(cond)) { \
			char buf[128]; \
			snprintf(buf, sizeof(buf), "%s:%d ASSERT_TRUE failed", __func__, __LINE__); \
			FAIL(buf); return; \
		} \
	} while(0)

#define ASSERT_NULL(p) \
	do { \
		if(NULL != (p)) { \
			FAIL("expected NULL"); return; \
		} \
	} while(0)

#define ASSERT_NOT_NULL(p) \
	do { \
		if(NULL == (p)) { \
			FAIL("expected not NULL"); return; \
		} \
	} while(0)

/* =========================== 测试辅助: 模拟发送回调 =========================== */

static uint8_t  g_sent_buf[ICP67_TX_BUF_SIZE];
static uint16_t g_sent_len = 0;

static void test_send_cb(uint8_t *p_tx, uint16_t tx_len, void *arg)
{
	(void)arg;
	g_sent_len = tx_len;
	memcpy(g_sent_buf, p_tx, (tx_len < ICP67_TX_BUF_SIZE) ? tx_len : ICP67_TX_BUF_SIZE);
}

/* =========================== T1: 帧构造 =========================== */

static void test_make_head_tail(void)
{
	TEST("make_head + make_tail");
	uint8_t  buf[256];
	uint16_t tx_len = 0;

	icp67_make_head(ENUM_DEV_TYPE_SYS, TI_1, COT_5, 0, buf, &tx_len);
	ASSERT_TRUE(tx_len >= sizeof(stru_head));

	stru_head *p_head = (stru_head *)buf;
	ASSERT_EQ(p_head->head1, 0x67);
	ASSERT_EQ(p_head->head2, 0x67);
	ASSERT_EQ(p_head->ti, TI_1);
	ASSERT_EQ(p_head->cot, COT_5);

	icp67_make_tail(buf, &tx_len);
	ASSERT_EQ(buf[tx_len - 1], 0x16);  /* 帧尾 */

	p_head->len = tx_len - ICP67_HEAD_OVERHEAD;
	ASSERT_TRUE(p_head->len > 0);

	PASS();
}

/* =========================== T2: 帧搜索 =========================== */

static void test_search_frame_valid(void)
{
	TEST("search_frame valid");

	uint8_t buf[64] = {0};
	uint16_t tx_len = 0;

	/* 构造一个合法的 TI_5 对时帧 */
	icp67_make_head(ENUM_DEV_TYPE_SYS, TI_5, COT_5, 0, buf, &tx_len);
	stru_ti_5 *p_asdu = (stru_ti_5 *)&buf[tx_len];
	memset(p_asdu, 0, sizeof(stru_ti_5));
	tx_len += sizeof(stru_ti_5);
	icp67_make_tail(buf, &tx_len);

	uint16_t pos = 0, valid_len = 0;
	int ret = icp67_search_frame(buf, tx_len, &pos, &valid_len);
	ASSERT_EQ(ret, 0);
	ASSERT_EQ(pos, 0);
	ASSERT_EQ(valid_len, tx_len);

	PASS();
}

static void test_search_frame_invalid_head(void)
{
	TEST("search_frame invalid head");

	uint8_t buf[32] = {0};
	uint16_t pos = 0, valid_len = 0;

	/* 无 0x67 帧头 */
	memset(buf, 0xFF, sizeof(buf));
	int ret = icp67_search_frame(buf, sizeof(buf), &pos, &valid_len);
	ASSERT_EQ(ret, -1);

	PASS();
}

static void test_search_frame_null(void)
{
	TEST("search_frame NULL params");

	uint16_t pos = 0, valid_len = 0;
	int ret = icp67_search_frame(NULL, 0, &pos, &valid_len);
	ASSERT_EQ(ret, -1);

	ret = icp67_search_frame(NULL, 10, NULL, &valid_len);
	ASSERT_EQ(ret, -1);

	PASS();
}

/* =========================== T3: CRC 校验 =========================== */

static void test_crc_basic(void)
{
	TEST("crc_check_sum basic");

	uint8_t data[] = {0x01, 0x02, 0x03};
	uint8_t crc = crc_check_sum(data, sizeof(data));
	ASSERT_EQ(crc, 0x06);  /* 1+2+3=6 */

	/* 溢出回绕: 0xFF + 0x01 = 0x00 */
	uint8_t data2[] = {0xFF, 0x01};
	crc = crc_check_sum(data2, sizeof(data2));
	ASSERT_EQ(crc, 0x00);

	PASS();
}

/* =========================== T4: 初始化 =========================== */

static void test_icp67_init(void)
{
	TEST("icp67_init");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));

	uint32_t interface = 42;
	icp67_init(&icp, test_send_cb, &interface, 0, 0);

	ASSERT_NOT_NULL(icp.send_cb);
	ASSERT_NOT_NULL(icp.search_frame_cb);
	ASSERT_NOT_NULL(icp.decode_cb);
	ASSERT_NOT_NULL(icp.timer_handler_cb);
	ASSERT_EQ(icp.rtx_flag, 0);
	ASSERT_EQ(icp.tm_out, ICP67_TM_OUT_DEF_MS / ICP67_TM_TICK_MS);

	/* sender 回调应初始化为内部函数 */
	ASSERT_NOT_NULL(icp.method.ao_get_cb);
	ASSERT_NOT_NULL(icp.method.ao_set_cb);
	ASSERT_NOT_NULL(icp.method.iec_point_tbl_get_cb);
	ASSERT_NOT_NULL(icp.method.time_set_cb);
	ASSERT_NOT_NULL(icp.method.self_check_get_cb);
	ASSERT_NOT_NULL(icp.method.upgrade_start_cb);
	ASSERT_NOT_NULL(icp.method.dir_read_cb);
	ASSERT_NOT_NULL(icp.method.file_read_act_cb);
	ASSERT_NOT_NULL(icp.method.file_read_confirm_cb);
	ASSERT_NOT_NULL(icp.method.file_write_act_cb);
	ASSERT_NOT_NULL(icp.method.file_write_cb);
	ASSERT_NOT_NULL(icp.method.file_write_end_confirm_cb);

	/* pop_out/trans 回调应初始化为 NULL */
	ASSERT_NULL(icp.method.ao_pop_out_cb);
	ASSERT_NULL(icp.method.mx_trans_cb);
	ASSERT_NULL(icp.method.st_trans_cb);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T5: 重传管理 =========================== */

static void test_rtx_flag_set_get(void)
{
	TEST("rtx_flag_set + rtx_flag_get");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	/* 设置 TX_FLAG */
	icp67_rtx_flag_set(&icp, ICP67_TX_FLAG, 0, 0);

	uint8_t  flag = 0, resend_cnt = 0xFF;
	uint32_t tm_cnt = 0xFFFFFFFF;

	icp67_rtx_flag_get(&icp, &flag, &resend_cnt, &tm_cnt);
	ASSERT_EQ(flag, ICP67_TX_FLAG);
	ASSERT_EQ(resend_cnt, 0);
	ASSERT_EQ(tm_cnt, 0);

	/* 设置 RX_FLAG */
	icp67_rtx_flag_set(&icp, ICP67_RX_FLAG, 0, 111);
	icp67_rtx_flag_get(&icp, &flag, &resend_cnt, &tm_cnt);
	ASSERT_EQ(flag, ICP67_RX_FLAG);
	ASSERT_EQ(tm_cnt, 111);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

static void test_rtx_resend_inc(void)
{
	TEST("rtx_resend_inc");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	icp67_rtx_flag_set(&icp, ICP67_TX_FLAG, 0, 50);
	icp67_rtx_resend_inc(&icp);

	uint8_t  flag = 0, resend_cnt = 0;
	uint32_t tm_cnt = 0xFFFF;

	icp67_rtx_flag_get(&icp, &flag, &resend_cnt, &tm_cnt);
	ASSERT_EQ(resend_cnt, 1);  /* 递增后 >= 1 */
	ASSERT_EQ(tm_cnt, 0);      /* 递增后复位为 0 */

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T6: 回调注册 =========================== */

static void test_cb_st_trans(void)
{
	TEST("icp67_set_st_trans_cb");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	ASSERT_NULL(icp.method.st_trans_cb);

	/* 注册一个 dummy 回调 */
	icp67_set_st_trans_cb(&icp, (icp67_st_trans_cb)0xDEADBEEF);
	ASSERT_NOT_NULL(icp.method.st_trans_cb);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

static void test_cb_all_setters(void)
{
	TEST("all 17 setters non-crash");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	/* 对 17 个 setter 分别注册 NULL 回调 (确保不崩溃) */
	icp67_set_ao_pop_out_cb(&icp, NULL);
	icp67_set_iec_point_tbl_pop_out_cb(&icp, NULL);
	icp67_set_self_check_pop_out_cb(&icp, NULL);
	icp67_set_dir_pop_out_cb(&icp, NULL);
	icp67_set_file_read_act_confirm_cb(&icp, NULL);
	icp67_set_file_read_cb(&icp, NULL);
	icp67_set_file_write_act_confirm_cb(&icp, NULL);
	icp67_set_file_write_confirm_cb(&icp, NULL);
	icp67_set_file_write_end_cb(&icp, NULL);
	icp67_set_zip_dir_pop_out_cb(&icp, NULL);
	icp67_set_zip_file_pop_out_cb(&icp, NULL);
	icp67_set_mx_trans_cb(&icp, NULL);
	icp67_set_st_trans_cb(&icp, NULL);
	icp67_set_dd_trans_cb(&icp, NULL);
	icp67_set_soe_trans_cb(&icp, NULL);
	icp67_set_fault_trans_cb(&icp, NULL);
	icp67_set_mx_change_cb(&icp, NULL);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T7: 解码无效帧 =========================== */

static void test_decode_invalid(void)
{
	TEST("icp67_decode invalid params");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	int ret = icp67_decode(NULL, NULL, 0);
	ASSERT_EQ(ret, -1);

	ret = icp67_decode(&icp, NULL, 0);
	ASSERT_EQ(ret, -1);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T8: 定时器 =========================== */

static void test_timer_handler_null(void)
{
	TEST("icp67_timer_handler NULL");

	/* NULL 参数应不崩溃 */
	icp67_timer_handler(NULL);
	PASS();
}

static void test_timer_handler_idle(void)
{
	TEST("icp67_timer_handler idle (no TX_FLAG)");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	/* 没有设置 TX_FLAG, timer 不应触发发送 */
	g_sent_len = 0;
	icp67_timer_handler(&icp);
	/* 计数器应递增, 但不应触发发送 */
	uint8_t  flag = 0, resend_cnt = 0;
	uint32_t tm_cnt = 0;

	icp67_rtx_flag_get(&icp, &flag, &resend_cnt, &tm_cnt);
	ASSERT_EQ(flag, 0);
	ASSERT_TRUE(tm_cnt >= 1);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T9: MD5 配置 =========================== */

static void test_set_ao_cfg_md5(void)
{
	TEST("icp67_set_ao_cfg_md5");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	uint8_t md5[ICP67_MD5_LEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
	                               0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};

	int ret = icp67_set_ao_cfg_md5(&icp, md5);
	ASSERT_EQ(ret, 0);
	ASSERT_EQ(memcmp(icp.md5, md5, ICP67_MD5_LEN), 0);

	/* NULL 参数应返回 -1 */
	ret = icp67_set_ao_cfg_md5(&icp, NULL);
	ASSERT_EQ(ret, -1);

	ret = icp67_set_ao_cfg_md5(NULL, md5);
	ASSERT_EQ(ret, -1);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T10: 解码无效 TI =========================== */

static void test_decode_unknown_ti(void)
{
	TEST("icp67_decode unknown TI");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	/* 构造一个 TI=0xFF (不存在) 的帧 */
	uint8_t buf[64] = {0};
	uint16_t tx_len = 0;

	icp67_make_head(ENUM_DEV_TYPE_SYS, 0xFF, COT_5, 0, buf, &tx_len);
	icp67_make_tail(buf, &tx_len);

	int ret = icp67_decode(&icp, buf, tx_len);
	ASSERT_EQ(ret, -1);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T11: Sender 函数基础测试 =========================== */

static void test_sender_self_check_get(void)
{
	TEST("icp67_self_check_get (sender)");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	g_sent_len = 0;
	icp.method.self_check_get_cb(&icp);

	ASSERT_TRUE(g_sent_len > sizeof(stru_head));
	stru_head *p_head = (stru_head *)g_sent_buf;
	ASSERT_EQ(p_head->ti, TI_6);
	ASSERT_EQ(p_head->cot, COT_5);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

static void test_sender_iec_point_tbl_get(void)
{
	TEST("icp67_iec_point_tbl_get (sender)");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	g_sent_len = 0;
	icp.method.iec_point_tbl_get_cb(&icp, MX_INFO_ADDR);

	ASSERT_TRUE(g_sent_len > sizeof(stru_head));
	stru_head *p_head = (stru_head *)g_sent_buf;
	ASSERT_EQ(p_head->ti, TI_3);
	ASSERT_EQ(p_head->info_addr, MX_INFO_ADDR);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

static void test_sender_null_params(void)
{
	TEST("sender functions NULL safety");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	/* 各 sender 函数的 NULL 参数应不崩溃 */
	icp.method.ao_get_cb(NULL, NULL, 0);
	icp.method.ao_set_cb(NULL, NULL, 0);
	icp.method.time_set_cb(NULL, NULL);
	icp.method.upgrade_start_cb(NULL, 0);
	icp.method.dir_read_cb(NULL, NULL, 0, NULL, NULL);
	icp.method.file_read_act_cb(NULL, NULL, 0);
	icp.method.file_write_act_cb(NULL, NULL, 0, 0, 0, 0);
	icp.method.file_write_cb(NULL, 0, 0, 0, NULL, 0);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T12: 解码特定 TI 函数 (基本路径) =========================== */

static void test_decode_ti_1_md5_mismatch(void)
{
	TEST("decode TI_1 MD5 mismatch");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	/* 设置预期 MD5 */
	uint8_t md5[ICP67_MD5_LEN] = {0};
	icp67_set_ao_cfg_md5(&icp, md5);

	/* 构造 TI_1 帧 (COT_7, 但空 MD5 可能与预期不匹配) */
	uint8_t buf[256] = {0};
	uint16_t tx_len = 0;

	icp67_make_head(ENUM_DEV_TYPE_SYS, TI_1, COT_7, 0, buf, &tx_len);
	stru_ti_1_2 *p_asdu = (stru_ti_1_2 *)&buf[tx_len];
	memcpy(p_asdu->md5, md5, ICP67_MD5_LEN);
	p_asdu->num = 0;
	tx_len += sizeof(stru_ti_1_2);
	icp67_make_tail(buf, &tx_len);

	/* 解码应成功 (MD5 匹配) */
	int ret = icp67_decode(&icp, buf, tx_len);
	ASSERT_EQ(ret, 0);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

static void test_decode_ti_4_stub(void)
{
	TEST("decode TI_4 (stub)");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	uint8_t buf[64] = {0};
	uint16_t tx_len = 0;

	icp67_make_head(ENUM_DEV_TYPE_SYS, TI_4, COT_7, 0, buf, &tx_len);
	icp67_make_tail(buf, &tx_len);

	/* 空桩函数应返回 0 */
	int ret = icp67_decode(&icp, buf, tx_len);
	ASSERT_EQ(ret, 0);

	sem_destroy(&icp.rtx_sem);

	PASS();
}

/* =========================== T13: 多实例独立 =========================== */

static void test_multi_instance_isolation(void)
{
	TEST("multi-instance callback isolation");

	stru_icp67 icp1, icp2;
	memset(&icp1, 0, sizeof(icp1));
	memset(&icp2, 0, sizeof(icp2));

	uint32_t if1 = 1, if2 = 2;
	icp67_init(&icp1, test_send_cb, &if1, 0, 0);
	icp67_init(&icp2, test_send_cb, &if2, 0, 0);

	/* 为 icp1 注册 mx_trans_cb, icp2 不注册 */
	icp67_set_mx_trans_cb(&icp1, (icp67_mx_trans_cb)0xCAFE);
	icp67_set_mx_trans_cb(&icp2, (icp67_mx_trans_cb)0xBEEF);

	/* icp1 和 icp2 应有不同的回调 */
	ASSERT_NOT_NULL(icp1.method.mx_trans_cb);
	ASSERT_NOT_NULL(icp2.method.mx_trans_cb);
	ASSERT_TRUE(icp1.method.mx_trans_cb != icp2.method.mx_trans_cb);

	/* icp1 的 ao_pop_out_cb 应仍是 NULL */
	ASSERT_NULL(icp1.method.ao_pop_out_cb);

	sem_destroy(&icp1.rtx_sem);
	sem_destroy(&icp2.rtx_sem);

	PASS();
}

/* =========================== T13: 可配置参数 =========================== */

static void test_configurable_params(void)
{
	TEST("configurable tm_out_ms + resend_max");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 500, 3);

	ASSERT_EQ(icp.resend_max, 3);
	ASSERT_EQ(icp.tm_out_ms, 500);
	ASSERT_EQ(icp.tm_out, 500 / ICP67_TM_TICK_MS);

	sem_destroy(&icp.rtx_sem);
	PASS();
}

static void test_configurable_params_default(void)
{
	TEST("configurable params default (0,0)");

	stru_icp67 icp;
	memset(&icp, 0, sizeof(icp));
	icp67_init(&icp, test_send_cb, NULL, 0, 0);

	ASSERT_EQ(icp.resend_max, ICP67_RESEND_MAX_DEF);
	ASSERT_EQ(icp.tm_out_ms,  ICP67_TM_OUT_DEF_MS);

	sem_destroy(&icp.rtx_sem);
	PASS();
}

/* =========================== T14: 环形缓冲区搜索 =========================== */

static void test_ring_search_basic(void)
{
	TEST("ring search basic");

	uint8_t ring[512] = {0};
	uint16_t tx_len = 0;

	/* 构造帧 */
	icp67_make_head(ENUM_DEV_TYPE_SYS, TI_5, COT_5, 0, ring, &tx_len);
	stru_ti_5 *p_asdu = (stru_ti_5 *)&ring[tx_len];
	memset(p_asdu, 0, sizeof(stru_ti_5));
	tx_len += sizeof(stru_ti_5);
	icp67_make_tail(ring, &tx_len);

	/* 在环形缓冲区中搜索 (rptr=0, cnt=tx_len) */
	uint16_t pos = 0, valid_len = 0;
	int ret = icp67_search_frame_in_ring(ring, 512, 0, tx_len, &pos, &valid_len);

	ASSERT_EQ(ret, 0);
	ASSERT_EQ(pos, 0);
	ASSERT_EQ(valid_len, tx_len);

	PASS();
}

static void test_ring_search_wrap(void)
{
	TEST("ring search with wrap-around");

	uint8_t ring[512] = {0};
	uint16_t tx_len = 0;

	/* 构造帧 */
	icp67_make_head(ENUM_DEV_TYPE_SYS, TI_6, COT_5, 0, ring, &tx_len);
	icp67_make_tail(ring, &tx_len);

	/* 模拟环形缓冲: rptr 靠近末尾, 帧在 rptr 开始 */
	uint16_t rptr = 250;

	memcpy(ring + rptr, ring, tx_len);

	uint16_t pos = 0, valid_len = 0;
	int ret = icp67_search_frame_in_ring(ring, 512, rptr, tx_len, &pos, &valid_len);

	ASSERT_EQ(ret, 0);
	ASSERT_EQ(pos, 0);
	ASSERT_EQ(valid_len, tx_len);

	PASS();
}

static void test_ring_search_no_frame(void)
{
	TEST("ring search no frame");

	uint8_t ring[512] = {0};
	memset(ring, 0xFF, 512);

	uint16_t pos = 0, valid_len = 0;
	int ret = icp67_search_frame_in_ring(ring, 512, 0, 50, &pos, &valid_len);

	ASSERT_EQ(ret, -1);

	PASS();
}

/* =========================== 运行入口 =========================== */

int main(void)
{
	printf("\n=== ICP67 Unit Tests ===\n\n");

	/* T1: 帧构造 */
	test_make_head_tail();

	/* T2: 帧搜索 */
	test_search_frame_valid();
	test_search_frame_invalid_head();
	test_search_frame_null();

	/* T3: CRC */
	test_crc_basic();

	/* T4: 初始化 */
	test_icp67_init();

	/* T5: 重传管理 */
	test_rtx_flag_set_get();
	test_rtx_resend_inc();

	/* T6: 回调注册 */
	test_cb_st_trans();
	test_cb_all_setters();

	/* T7: 解码无效帧 */
	test_decode_invalid();

	/* T8: 定时器 */
	test_timer_handler_null();
	test_timer_handler_idle();

	/* T9: MD5 */
	test_set_ao_cfg_md5();

	/* T10: 未知 TI */
	test_decode_unknown_ti();

	/* T11: Sender 函数 */
	test_sender_self_check_get();
	test_sender_iec_point_tbl_get();
	test_sender_null_params();

	/* T12: 解码特定 TI */
	test_decode_ti_1_md5_mismatch();
	test_decode_ti_4_stub();

	/* T13: 多实例 */
	test_multi_instance_isolation();

	/* T14: 可配置参数 */
	test_configurable_params();
	test_configurable_params_default();

	/* T15: 环形缓冲区搜索 */
	test_ring_search_basic();
	test_ring_search_wrap();
	test_ring_search_no_frame();

	printf("\n=== Results: %d passed, %d failed ===\n", g_test_pass, g_test_fail);

	return (g_test_fail > 0) ? 1 : 0;
}
