mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-11 12:28:54 +00:00
Six public commands let any member of a chat curate two lists of text and ask whether a given text is blocked: /blacklist_add, /blacklist_del, /whitelist_add, /whitelist_del, /blacklist_rules and /blacklist_check. The module is passive. It never reads ordinary chat messages and never deletes, warns or restricts anyone; the lists stay inert until /blacklist_check asks about a specific text. Scope is one forum topic, keyed (Chat.ID, MessageThreadID) and gated on IsTopicMessage so a reply chain in a plain supergroup does not become its own unreachable scope. A plain group, a DM and a forum's General topic all resolve to one chat-wide list. Matching is substring, after NFKC composition, case folding and whitespace collapse. Diacritics stay significant, so ma, má and mà are three entries. A whitelist entry rescues a blacklist match only when it spans that match, which is what keeps "I met an assassin, dumbass" blocked. Entry text is percent-encoded before it becomes a storage key, since keys forbid '/' and cap at 1500 bytes, and is capped at 200 bytes before and after normalization because NFKC can expand as well as contract. /blacklist_rules reads each list with Scan, so listing costs one round trip per list rather than a Get per entry.
58 lines
1.5 KiB
Go
58 lines
1.5 KiB
Go
package blacklist
|
|
|
|
import "testing"
|
|
|
|
func TestNormalize_ComposesVietnamese(t *testing.T) {
|
|
// The same word as a client sending NFC and a client sending NFD. Without
|
|
// composition these are different strings and would never match.
|
|
nfc := "má" // U+00E1 precomposed
|
|
nfd := "má" // "a" + combining acute
|
|
gotNFC, ok := Normalize(nfc)
|
|
if !ok {
|
|
t.Fatal("NFC form rejected")
|
|
}
|
|
gotNFD, ok := Normalize(nfd)
|
|
if !ok {
|
|
t.Fatal("NFD form rejected")
|
|
}
|
|
if gotNFC != gotNFD {
|
|
t.Fatalf("NFC %q and NFD %q normalize differently", gotNFC, gotNFD)
|
|
}
|
|
}
|
|
|
|
func TestNormalize_FoldsCaseButKeepsDiacritics(t *testing.T) {
|
|
upper, _ := Normalize("MÁ")
|
|
lower, _ := Normalize("má")
|
|
if upper != lower {
|
|
t.Fatalf("case not folded: %q vs %q", upper, lower)
|
|
}
|
|
|
|
bare, _ := Normalize("ma")
|
|
if bare == lower {
|
|
t.Fatalf("diacritic was stripped: %q == %q", bare, lower)
|
|
}
|
|
}
|
|
|
|
func TestNormalize_FoldsCompatibilityVariants(t *testing.T) {
|
|
full, _ := Normalize("AB") // full-width AB
|
|
plain, _ := Normalize("ab")
|
|
if full != plain {
|
|
t.Fatalf("full-width %q did not fold to %q", full, plain)
|
|
}
|
|
}
|
|
|
|
func TestNormalize_CollapsesWhitespace(t *testing.T) {
|
|
got, ok := Normalize(" cat \n dog ")
|
|
if !ok || got != "cat dog" {
|
|
t.Fatalf("Normalize = %q, %v; want \"cat dog\", true", got, ok)
|
|
}
|
|
}
|
|
|
|
func TestNormalize_RejectsEmpty(t *testing.T) {
|
|
for _, in := range []string{"", " ", "\n\t "} {
|
|
if got, ok := Normalize(in); ok {
|
|
t.Fatalf("Normalize(%q) = %q, true; want not ok", in, got)
|
|
}
|
|
}
|
|
}
|