// academic 31xx 业务错误码单测(纯断言,不连库)。 // // 覆盖 AC-02 验收②:31xx 码全落 3100~3199 段、无重复、文案非空、 // 且与 infra/errors 通用码段(1xxx/2xxx/3xxx/5xxx)不重叠。 package apperr import "testing" // TestCodesInAcademicRange 断言全部业务码落在 3100~3199 且唯一。 func TestCodesInAcademicRange(t *testing.T) { allCodes := All() if len(allCodes) == 0 { t.Fatal("apperr.All() 不应为空") } seen := make(map[int]string, len(allCodes)) for _, e := range allCodes { if e == nil { t.Fatal("apperr.All() 含 nil") } if !IsAcademicCode(e.Code) { t.Fatalf("错误码 %d(%s)越出 academic 段位 3100~3199", e.Code, e.Msg) } if prev, dup := seen[e.Code]; dup { t.Fatalf("错误码 %d 重复定义:%q 与 %q", e.Code, prev, e.Msg) } seen[e.Code] = e.Msg if e.Msg == "" { t.Fatalf("错误码 %d 文案为空(禁止无文案 sentinel)", e.Code) } } } // TestKnownCodes 逐条断言设计 §10.1 的码值(防误改错位,造成前端契约漂移)。 func TestKnownCodes(t *testing.T) { pairs := []struct { name string got int want int }{ {"3101 余额不足", ErrBalanceInsufficient.Code, 3101}, {"3102 余额为0不可退费", ErrNoBalanceToRefund.Code, 3102}, {"3103 可退金额不足(warn)", ErrRefundableShort.Code, 3103}, {"3104 校区不存在", ErrCampusNotFound.Code, 3104}, {"3105 已报名", ErrActivityAlreadySigned.Code, 3105}, {"3106 老带新限一次", ErrRecommendLimited.Code, 3106}, {"3107 已审核不可取消", ErrActivitySignedAudited.Code, 3107}, {"3108 老带新已消费", ErrRecommendUsed.Code, 3108}, {"3109 赠送金额不足", ErrGiftAmountShort.Code, 3109}, {"3110 活动不可用", ErrActivityUnavailable.Code, 3110}, {"3111 分账额度超限", ErrDivideQuotaExceeded.Code, 3111}, {"3112 课酬方案未配置", ErrPayrollPlanMissing.Code, 3112}, {"3113 欠费核销失败", ErrArrearsCounteractFailed.Code, 3113}, {"3114 幂等重复(内部)", ErrRepeated.Code, 3114}, {"3120 清零前置不满足", ErrClearBalanceRejected.Code, 3120}, {"3121 上课状态非法", ErrRecordStateInvalid.Code, 3121}, {"3122 排班冲突", ErrScheduleConflict.Code, 3122}, {"3140 业务参数错", ErrBusinessParam.Code, 3140}, {"3141 报名人数已满", ErrActivityFull.Code, 3141}, } for _, p := range pairs { if p.got != p.want { t.Fatalf("%s:code = %d,期望 %d", p.name, p.got, p.want) } } if len(All()) != len(pairs) { t.Fatalf("All() 数量 = %d,期望 %d(新增码须同步本测试与设计 §10.1)", len(All()), len(pairs)) } } // TestAllReturnsCopy All() 返回新切片(调用方 append 不得污染内部全集)。 func TestAllReturnsCopy(t *testing.T) { a := All() a = append(a, ErrBalanceInsufficient) if len(All()) != len(a)-1 { t.Fatal("All() 未返回新切片:内部集合被调用方污染") } } // TestIsAcademicCode 段位边界(含端点/邻接非法值)。 func TestIsAcademicCode(t *testing.T) { cases := []struct { code int want bool }{ {3099, false}, {3100, true}, {3199, true}, {3200, false}, {1004, false}, {2001, false}, } for _, tc := range cases { if got := IsAcademicCode(tc.code); got != tc.want { t.Fatalf("IsAcademicCode(%d) = %v,期望 %v", tc.code, got, tc.want) } } }