package model import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/mysql" "gorm.io/gorm" ) // setupMenuTestDB 创建菜单测试数据库(使用MySQL) func setupMenuTestDB(t *testing.T) *gorm.DB { t.Helper() dsn := "root:dev123456@tcp(219.159.132.177:17173)/base?charset=utf8mb4&parseTime=true&loc=Local" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) require.NoError(t, err) err = db.AutoMigrate(&Menu{}) require.NoError(t, err) // 清理所有数据确保测试隔离(运行后需重启后端以恢复种子数据) db.Exec("SET FOREIGN_KEY_CHECKS = 0") db.Exec("TRUNCATE TABLE menu") db.Exec("SET FOREIGN_KEY_CHECKS = 1") return db } // createTestMenu 创建测试菜单 func createTestMenu(t *testing.T, db *gorm.DB) *Menu { t.Helper() now := time.Now() menu := &Menu{ Name: "测试菜单", Path: "/test", Icon: "Star", Type: "config", SortOrder: 1, Visible: true, Status: 1, CreatedAt: now, UpdatedAt: now, } err := db.Create(menu).Error require.NoError(t, err) return menu } // TestMenuInsert 测试插入菜单 func TestMenuInsert(t *testing.T) { db := setupMenuTestDB(t) ctx := context.Background() menu := &Menu{ Name: "新菜单", Path: "/new", Icon: "Plus", Type: "config", SortOrder: 5, Visible: true, Status: 1, } id, err := MenuInsert(ctx, db, menu) require.NoError(t, err) assert.Greater(t, id, int64(0)) assert.Equal(t, id, menu.Id) // 验证数据已保存 saved, err := MenuFindOne(ctx, db, id) require.NoError(t, err) assert.Equal(t, "新菜单", saved.Name) assert.Equal(t, "/new", saved.Path) assert.Equal(t, "Plus", saved.Icon) assert.Equal(t, 5, saved.SortOrder) } // TestMenuFindOne 测试根据ID查询菜单 func TestMenuFindOne(t *testing.T) { db := setupMenuTestDB(t) menu := createTestMenu(t, db) ctx := context.Background() found, err := MenuFindOne(ctx, db, menu.Id) require.NoError(t, err) require.NotNil(t, found) assert.Equal(t, menu.Id, found.Id) assert.Equal(t, "测试菜单", found.Name) assert.Equal(t, "/test", found.Path) assert.Equal(t, "Star", found.Icon) } // TestMenuFindOne_NotFound 测试查询不存在的菜单 func TestMenuFindOne_NotFound(t *testing.T) { db := setupMenuTestDB(t) ctx := context.Background() found, err := MenuFindOne(ctx, db, 99999) require.Error(t, err) require.Nil(t, found) assert.Equal(t, ErrNotFound, err) } // TestMenuFindAll 测试查询所有启用的菜单 func TestMenuFindAll(t *testing.T) { db := setupMenuTestDB(t) ctx := context.Background() // 创建3个菜单:2个启用,1个禁用 now := time.Now() menus := []Menu{ {Name: "菜单A", Path: "/a", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "菜单B", Path: "/b", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "菜单C", Path: "/c", SortOrder: 3, Status: 1, CreatedAt: now, UpdatedAt: now}, } for i := range menus { err := db.Create(&menus[i]).Error require.NoError(t, err) } // 将菜单C设为禁用(status=0是零值,GORM Create时会使用default:1,需要单独更新) db.Model(&menus[2]).Update("status", 0) // 查询所有启用的菜单 result, err := MenuFindAll(ctx, db) require.NoError(t, err) assert.Len(t, result, 2) // 验证按 sort_order 排序 assert.Equal(t, "菜单B", result[0].Name) // sort_order=1 assert.Equal(t, "菜单A", result[1].Name) // sort_order=2 } // TestMenuFindByIds 测试根据ID列表查询菜单 func TestMenuFindByIds(t *testing.T) { db := setupMenuTestDB(t) ctx := context.Background() // 创建3个菜单 now := time.Now() menus := []Menu{ {Name: "菜单1", Path: "/1", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "菜单2", Path: "/2", SortOrder: 2, Status: 1, CreatedAt: now, UpdatedAt: now}, {Name: "菜单3", Path: "/3", SortOrder: 3, Status: 1, CreatedAt: now, UpdatedAt: now}, } for i := range menus { err := db.Create(&menus[i]).Error require.NoError(t, err) } // 查询其中2个 ids := []int64{menus[0].Id, menus[2].Id} result, err := MenuFindByIds(ctx, db, ids) require.NoError(t, err) assert.Len(t, result, 2) assert.Equal(t, "菜单1", result[0].Name) assert.Equal(t, "菜单3", result[1].Name) } // TestMenuUpdate 测试更新菜单 func TestMenuUpdate(t *testing.T) { db := setupMenuTestDB(t) menu := createTestMenu(t, db) ctx := context.Background() // 修改菜单数据 menu.Name = "更新后的菜单" menu.Path = "/updated" err := MenuUpdate(ctx, db, menu) require.NoError(t, err) // 验证更新结果 updated, err := MenuFindOne(ctx, db, menu.Id) require.NoError(t, err) assert.Equal(t, "更新后的菜单", updated.Name) assert.Equal(t, "/updated", updated.Path) } // TestMenuDelete 测试删除菜单 func TestMenuDelete(t *testing.T) { db := setupMenuTestDB(t) menu := createTestMenu(t, db) menuId := menu.Id ctx := context.Background() err := MenuDelete(ctx, db, menuId) require.NoError(t, err) // 验证菜单已被删除 _, err = MenuFindOne(ctx, db, menuId) require.Error(t, err) assert.Equal(t, ErrNotFound, err) } // TestMenuHasChildren 测试检查菜单是否有子菜单 func TestMenuHasChildren(t *testing.T) { db := setupMenuTestDB(t) ctx := context.Background() now := time.Now() // 创建父菜单 parent := &Menu{ Name: "父菜单", Path: "/parent", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now, } err := db.Create(parent).Error require.NoError(t, err) // 创建子菜单 child := &Menu{ ParentId: parent.Id, Name: "子菜单", Path: "/parent/child", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now, } err = db.Create(child).Error require.NoError(t, err) // 创建无子菜单的孤立菜单 orphan := &Menu{ Name: "孤立菜单", Path: "/orphan", SortOrder: 1, Status: 1, CreatedAt: now, UpdatedAt: now, } err = db.Create(orphan).Error require.NoError(t, err) // 验证父菜单有子菜单 hasChildren, err := MenuHasChildren(ctx, db, parent.Id) require.NoError(t, err) assert.True(t, hasChildren) // 验证孤立菜单没有子菜单 hasChildren, err = MenuHasChildren(ctx, db, orphan.Id) require.NoError(t, err) assert.False(t, hasChildren) }