#include #include "test_common.h" #include "../src/Drv/pages/menu/view.h" #include "../src/Drv/pages/menu/model.h" #include "../src/Drv/pages/menu/page.h" /* ------------------------------------------------------------------------- * 函数名: main * 功能: * 覆盖菜单模块的白盒/黑盒关键能力,验证: * 1) Model 初始化与辅助函数 * 2) 菜单树构建与显示名称装饰 * 3) View 初始化后的端口与接口绑定 * 4) MenuPage 生命周期入口是否完整绑定 * * 参数: * 无 * * 返回值: * - 0 : 测试通过 * ------------------------------------------------------------------------- */ int main(void) { /* 用于 MenuView_CharLenCal / Position 相关白盒测试的临时数组 */ tagPMenuItem first[4] = {0}; tagPMenuItem index[4] = {0}; uint8_t max_len; /* 页面实例:用于验证 MenuPage_GetInstance 生命周期回调绑定 */ page_t *menuPage; /* 真实菜单模型对象:用于测试 MenuModel_Init 及其派生结果 */ menu_model_t menuModel; /* 视图对象:用于验证 MenuView_Init 的接口与渲染端口初始化 */ MenuView view; /* 自定义最小菜单树:用于单独测试 BuildTree / DecorateDisplayNames */ tagMenuItem customItems[4]; tagMenuItem customItems2[7]; tagMenuModel customModelTab[4] = { {0, "Root", "", 0, 0x0000, 0, NULL}, {1, "ChildA", "", 0, 0x0000, 0, NULL}, {2, "Leaf", "", 0, 0x0000, 0, NULL}, {1, "ChildB", "", 0, 0x0000, 0, NULL} }; tagMenuModel customModelTab2[7] = { {0, "RootA", "", 0, 0x0000, 0, NULL}, {1, "A1", "", 0, 0x0000, 0, NULL}, {2, "A1a", "", 0, 0x0000, 0, NULL}, {1, "A2", "", 0, 0x0000, 0, NULL}, {0, "RootB", "", 0, 0x0000, 0, NULL}, {1, "B1", "", 0, 0x0000, 0, NULL}, {0, "RootC", "", 0, 0x0000, 0, NULL} }; /* --------------------------------------------------------------------- * Case 1: * 测试 MenuModel_Init / MenuModel_CountTopLevel * - 初始化真实菜单模型 * - 验证 0 级菜单数量统计结果有效 * --------------------------------------------------------------------- */ memset(&menuModel, 0, sizeof(menuModel)); MenuModel_Init(&menuModel); /* --------------------------------------------------------------------- * Case 2: * 测试 MenuView_Utf8LenCal * - 验证英文与中文字符串长度计算逻辑 * --------------------------------------------------------------------- */ ASSERT_EQ_INT(3, MenuModel_Utf8LenCal((uint8_t *)"ABC")); ASSERT_EQ_INT(2, MenuModel_Utf8LenCal((uint8_t *)"你")); /* --------------------------------------------------------------------- * Case 3: * 测试 MenuModel_IndexMenuItems / MenuModel_GetMenuMaxDisplayLen * - 使用真实菜单模型验证序号初始化、子节点数量统计与子菜单宽度统计 * --------------------------------------------------------------------- */ first[0] = &menuModel.menuItems[0]; index[0] = &menuModel.menuItems[0]; first[1] = menuModel.menuItems[0].links.lower; max_len = MenuModel_GetMenuMaxDisplayLen(first[1]); ASSERT_TRUE(max_len > 0); ASSERT_EQ_INT(0, menuModel.menuItems[0].rect.wPos); ASSERT_EQ_INT(0, first[1]->rect.wPos); ASSERT_TRUE(menuModel.menuItems[0].rect.wNum > 0); if (first[1]->links.lower == NULL) { ASSERT_EQ_INT(0, first[1]->rect.wNum); } else { ASSERT_TRUE(first[1]->rect.wNum > 0); } /* --------------------------------------------------------------------- * Case 4: * 测试 MenuModel_DecorateDisplayNames 的真实初始化结果 * - 验证存在子菜单的项名称非空,并被正确用于显示 * --------------------------------------------------------------------- */ /* 有子菜单的项会被装饰追加 '\x10'(右箭头标记) */ ASSERT_TRUE(((const char *)menuModel.menuItems[1].menuDef.byName)[0] != '\0'); /* --------------------------------------------------------------------- * Case 5: * 测试 MenuModel_BuildTree * - 使用自定义 4 节点菜单表验证父子、同层、闭环链路关系 * --------------------------------------------------------------------- */ memset(customItems, 0, sizeof(customItems)); MenuModel_BuildTree(customItems, customModelTab, 4); MenuModel_IndexMenuItems(customItems, 4); ASSERT_TRUE(customItems[0].links.lower == &customItems[1]); ASSERT_TRUE(customItems[1].links.higher == &customItems[0]); ASSERT_TRUE(customItems[1].links.lower == &customItems[2]); ASSERT_TRUE(customItems[2].links.higher == &customItems[1]); ASSERT_TRUE(customItems[1].links.behind == &customItems[3]); ASSERT_TRUE(customItems[3].links.before == &customItems[1]); ASSERT_TRUE(customItems[3].links.higher == &customItems[0]); ASSERT_TRUE(customItems[3].links.behind == &customItems[1]); /* 同层闭环 */ ASSERT_EQ_INT(0, customItems[0].rect.wPos); ASSERT_EQ_INT(2, customItems[0].rect.wNum); ASSERT_EQ_INT(0, customItems[1].rect.wPos); ASSERT_EQ_INT(1, customItems[1].rect.wNum); ASSERT_EQ_INT(1, customItems[3].rect.wPos); ASSERT_EQ_INT(0, customItems[3].rect.wNum); ASSERT_EQ_INT(0, customItems[2].rect.wPos); ASSERT_EQ_INT(0, customItems[2].rect.wNum); /* --------------------------------------------------------------------- * Case 5.1: * 强化测试 MenuModel_IndexMenuItems * - 覆盖多顶层、多兄弟、跨层回退后的 wPos / wNum 统计 * --------------------------------------------------------------------- */ memset(customItems2, 0, sizeof(customItems2)); MenuModel_BuildTree(customItems2, customModelTab2, 7); MenuModel_IndexMenuItems(customItems2, 7); ASSERT_EQ_INT(0, customItems2[0].rect.wPos); ASSERT_EQ_INT(2, customItems2[0].rect.wNum); ASSERT_EQ_INT(0, customItems2[1].rect.wPos); ASSERT_EQ_INT(1, customItems2[1].rect.wNum); ASSERT_EQ_INT(0, customItems2[2].rect.wPos); ASSERT_EQ_INT(0, customItems2[2].rect.wNum); ASSERT_EQ_INT(1, customItems2[3].rect.wPos); ASSERT_EQ_INT(0, customItems2[3].rect.wNum); ASSERT_EQ_INT(1, customItems2[4].rect.wPos); ASSERT_EQ_INT(1, customItems2[4].rect.wNum); ASSERT_EQ_INT(0, customItems2[5].rect.wPos); ASSERT_EQ_INT(0, customItems2[5].rect.wNum); ASSERT_EQ_INT(2, customItems2[6].rect.wPos); ASSERT_EQ_INT(0, customItems2[6].rect.wNum); /* --------------------------------------------------------------------- * Case 6: * 测试 MenuModel_DecorateDisplayNames * - 验证有子节点的项追加 '\x10' * - 验证叶子节点名称不被追加装饰符 * --------------------------------------------------------------------- */ MenuModel_DecorateDisplayNames(customItems, 4); ASSERT_TRUE(customItems[0].menuDef.byName[4] == '\x10'); ASSERT_TRUE(customItems[0].menuDef.byName[5] == '\0'); ASSERT_TRUE(customItems[1].menuDef.byName[6] == '\x10'); ASSERT_TRUE(customItems[1].menuDef.byName[7] == '\0'); ASSERT_TRUE(customItems[2].menuDef.byName[4] == '\0'); /* 叶子节点不追加 */ /* --------------------------------------------------------------------- * Case 7: * 测试 MenuView_Init / MenuView_GetPortForTest * - 验证 View 初始化后渲染端口、布局参数、接口函数指针均可用 * --------------------------------------------------------------------- */ /* View 初始化后,渲染端口派生数据和对外接口必须可用 */ memset(&view, 0, sizeof(view)); ASSERT_TRUE(MenuView_GetPortForTest() == NULL); MenuView_Init(&view); ASSERT_TRUE(MenuView_GetPortForTest() != NULL); ASSERT_TRUE(view.update_selection_new_level != NULL); ASSERT_TRUE(view.update_selection_same_level != NULL); ASSERT_TRUE(view.full_refresh != NULL); /* --------------------------------------------------------------------- * Case 8: * 测试 MenuPage_GetInstance * - 验证页面生命周期入口已经完整绑定 * --------------------------------------------------------------------- */ /* 页面生命周期入口必须完整绑定,避免注册后生命周期不执行 */ menuPage = MenuPage_GetInstance(); ASSERT_TRUE(menuPage != NULL); ASSERT_TRUE(menuPage->on_create != NULL); ASSERT_TRUE(menuPage->on_enter != NULL); ASSERT_TRUE(menuPage->on_exit != NULL); ASSERT_TRUE(menuPage->on_destroy != NULL); ASSERT_TRUE(menuPage->on_event != NULL); ASSERT_TRUE(menuPage->on_loop != NULL); return 0; }