package adapter import ( "strings" "testing" ) // 本文件覆盖 design/12 §6 策略一补充的归一化契约:结构分类(单一事实来源)、 // 种类合法性,以及把平台原生通知文本剥成安全文本的净化器。 func TestSystemNoticeClassify(t *testing.T) { t.Parallel() cases := []struct { name string in SystemNotice want NoticeClass }{ {"可忽略 → 仅登记", SystemNotice{Kind: NoticeJoin, Ignorable: true}, NoticeRegisterOnly}, {"高价值 → 升级真会话", SystemNotice{Kind: NoticeOther, HighValue: true}, NoticeEscalate}, {"其余 → 限定注入", SystemNotice{Kind: NoticeOther}, NoticeLimitedInject}, // 两个标志同时为真时取保守侧(不打扰为第一原则)。 {"既标可忽略又标高价值 → 仅登记", SystemNotice{Ignorable: true, HighValue: true}, NoticeRegisterOnly}, } for _, tc := range cases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() if got := tc.in.Classify(); got != tc.want { t.Fatalf("Classify() = %v, want %v", got, tc.want) } }) } } func TestNoticeKindValid(t *testing.T) { t.Parallel() for _, k := range []NoticeKind{NoticeJoin, NoticeLeave, NoticeRecall, NoticeTyping, NoticeBotAdd, NoticeOther} { if !k.Valid() { t.Errorf("%q 应合法", k) } } if NoticeKind("weird").Valid() { t.Error("未知 kind 不该合法") } } func TestSanitizeNoticeText(t *testing.T) { t.Parallel() cases := []struct { name string in string want string }{ {"空串", "", ""}, {"折叠换行与制表", "有人\n加入\t了群聊", "有人 加入 了群聊"}, {"吞掉 ANSI 序列", "\x1b[31m红\x1b[0m字", "红字"}, {"丢掉零宽与双向覆盖字符", "群\u200b聊\u202e事", "群聊事"}, {"丢掉其余控制字符", "系\x07统\x00通知", "系统通知"}, {"折叠多余空白", " a b ", "a b"}, } for _, tc := range cases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() if got := SanitizeNoticeText(tc.in); got != tc.want { t.Fatalf("SanitizeNoticeText(%q) = %q, want %q", tc.in, got, tc.want) } }) } } func TestSanitizeNoticeTextTruncates(t *testing.T) { t.Parallel() got := SanitizeNoticeText(strings.Repeat("啊", NoticeSafeTextMaxRunes+50)) if runes := []rune(got); len(runes) != NoticeSafeTextMaxRunes+1 { t.Fatalf("截断后 %d runes, want %d+1(含省略号)", len(runes), NoticeSafeTextMaxRunes) } if !strings.HasSuffix(got, "…") { t.Errorf("截断未加省略号:%q", got) } } // TestSanitizeNoticeTextNeverPanicsOnGarbage 钉住「畸形数据不炸流水线」: // 净化器对任意字节串都必须返回、不 panic,也绝不返回未净化的控制字符。 func TestSanitizeNoticeTextNeverPanicsOnGarbage(t *testing.T) { t.Parallel() for _, in := range []string{ "\x1b", "\x1b[", "\x1b[31", "正常\x1b[31m文本", "\u200b", "\ufeff", "\x7f", "a\x1b[1;2Hb", } { got := SanitizeNoticeText(in) for _, r := range got { if r == 0x1b || isInvisibleRune(r) { t.Fatalf("SanitizeNoticeText(%q) = %q 仍含异常字符", in, got) } } } }