113 lines
4.4 KiB
Go
113 lines
4.4 KiB
Go
package logic
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
|
||
"tool-api/internal/consts"
|
||
)
|
||
|
||
// ============================================================================
|
||
// T04 自动排座「排除」语义单测(纯函数,不依赖 DB)
|
||
//
|
||
// 覆盖:
|
||
// - 排除桌上的座位/人员完全不被触碰(不分配、不清手工号、不计 manual_overridden);
|
||
// - fail-closed:全部桌被排除 → 4018 且 message 列出被排除的桌;
|
||
// - 部分排除 / 无桌 → 放行。
|
||
// ============================================================================
|
||
|
||
// TestPlanAutoAssignExcludesTable 排除桌的座位不参与分配,且不计入 manual_overridden。
|
||
func TestPlanAutoAssignExcludesTable(t *testing.T) {
|
||
seats := []seatBrief{
|
||
// 1 号桌:参与
|
||
{Id: 1, TableId: 1, SeatNo: 1, EmployeeId: 0},
|
||
{Id: 2, TableId: 1, SeatNo: 2, IsManual: true, EmployeeId: 0}, // 参与桌的手工位:reorder 可用
|
||
// 2 号桌:被排除(不参与自动排序)
|
||
{Id: 3, TableId: 2, SeatNo: 1, IsManual: true, EmployeeId: 0, Excluded: true}, // 排除桌的手工空位
|
||
{Id: 4, TableId: 2, SeatNo: 2, EmployeeId: 0, Excluded: true}, // 排除桌的普通空位
|
||
}
|
||
assigns, remaining, overridden := planAutoAssign(seats, []int64{101, 102, 103}, consts.SeatModeReorder)
|
||
|
||
// 排除桌 id=3、id=4 一律不可被占用
|
||
for _, a := range assigns {
|
||
if a.SeatId == 3 || a.SeatId == 4 {
|
||
t.Fatalf("排除桌的座位不应被分配,got %v", assigns)
|
||
}
|
||
}
|
||
// 参与桌有 2 个可用位(id=1、id=2),故只分配 2 人,剩 1 人
|
||
if len(assigns) != 2 {
|
||
t.Fatalf("应分配 2 人(仅参与桌),got %d (%v)", len(assigns), assigns)
|
||
}
|
||
if len(remaining) != 1 || remaining[0] != 103 {
|
||
t.Fatalf("remaining=%v want [103]", remaining)
|
||
}
|
||
// manual_overridden 只统计**参与桌**的手工位(id=2),排除桌的手工位(id=3)不计入
|
||
if overridden != 1 {
|
||
t.Fatalf("排除桌的手工位不应计入 manual_overridden,got %d want 1", overridden)
|
||
}
|
||
}
|
||
|
||
// TestPlanAutoAssignExcludesTableFill 排除桌在 fill 模式下同样不被触碰。
|
||
func TestPlanAutoAssignExcludesTableFill(t *testing.T) {
|
||
seats := []seatBrief{
|
||
{Id: 1, TableId: 1, SeatNo: 1, EmployeeId: 0},
|
||
{Id: 2, TableId: 2, SeatNo: 1, EmployeeId: 0, Excluded: true},
|
||
}
|
||
assigns, _, _ := planAutoAssign(seats, []int64{101, 102}, consts.SeatModeFill)
|
||
if len(assigns) != 1 || assigns[0].SeatId != 1 {
|
||
t.Fatalf("fill 应只填参与桌 id=1,got %v", assigns)
|
||
}
|
||
}
|
||
|
||
// TestPlanAutoGuardsAllExcluded 全部桌被排除 → 4018,且 message 列出被排除的桌。
|
||
func TestPlanAutoGuardsAllExcluded(t *testing.T) {
|
||
tables := []tableBrief{
|
||
{Id: 1, Name: "主桌", ExcludeAuto: 1},
|
||
{Id: 2, TableNo: "2", ExcludeAuto: 1},
|
||
}
|
||
err := planAutoGuards(tables)
|
||
if err == nil {
|
||
t.Fatalf("全部桌被排除应报错(fail-closed)")
|
||
}
|
||
if code := gerror.Code(err).Code(); code != consts.CodeSeatAutoInvalid {
|
||
t.Fatalf("错误码应为 %d,got %d", consts.CodeSeatAutoInvalid, code)
|
||
}
|
||
msg := err.Error()
|
||
if !strings.Contains(msg, "主桌") || !strings.Contains(msg, "2 号桌") {
|
||
t.Fatalf("错误信息应列出被排除的桌,got: %s", msg)
|
||
}
|
||
}
|
||
|
||
// TestPlanAutoGuardsPartialExcluded 部分桌可参与 → 放行(含仅 1 张桌可参与)。
|
||
func TestPlanAutoGuardsPartialExcluded(t *testing.T) {
|
||
tables := []tableBrief{
|
||
{Id: 1, Name: "签到台", ExcludeAuto: 1},
|
||
{Id: 2, Name: "1 号桌", ExcludeAuto: 0}, // 仅此 1 张可参与 → 允许
|
||
}
|
||
if err := planAutoGuards(tables); err != nil {
|
||
t.Fatalf("有 1 张可参与桌时应放行,got %v", err)
|
||
}
|
||
}
|
||
|
||
// TestPlanAutoGuardsNoTables 无桌 → 放行(交由后续逻辑自然得到 0 结果,保持老行为)。
|
||
func TestPlanAutoGuardsNoTables(t *testing.T) {
|
||
if err := planAutoGuards(nil); err != nil {
|
||
t.Fatalf("无桌不应触发 fail-closed,got %v", err)
|
||
}
|
||
}
|
||
|
||
// TestTableDisplayName 桌名回退:Name > 桌号 > id。
|
||
func TestTableDisplayName(t *testing.T) {
|
||
if got := tableDisplayName(tableBrief{Id: 1, Name: "主桌", TableNo: "1"}); got != "主桌" {
|
||
t.Fatalf("应优先用 Name,got %q", got)
|
||
}
|
||
if got := tableDisplayName(tableBrief{Id: 2, TableNo: "3"}); got != "3 号桌" {
|
||
t.Fatalf("无 Name 时用「桌号 号桌」,got %q", got)
|
||
}
|
||
if got := tableDisplayName(tableBrief{Id: 7}); got != "桌#7" {
|
||
t.Fatalf("无桌名桌号时回退 id,got %q", got)
|
||
}
|
||
}
|