Files
DTU-HMI/tests/test_p1_menu.c

201 lines
8.6 KiB
C

#include <string.h>
#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;
}