Generate a unique mention handle on API register and admin create, and fire user.Created from both paths so listeners run in the same write. Co-authored-by: Cursor <cursoragent@cursor.com>
79 lines
2.3 KiB
Go
79 lines
2.3 KiB
Go
package classes
|
|
|
|
import "testing"
|
|
|
|
// TestHandle: generator charset is a subset of MentionParser, uniqueness
|
|
// uses the smallest free integer suffix, and short names fall back to user{id}.
|
|
func TestHandle(t *testing.T) {
|
|
t.Parallel()
|
|
g := HandleGenerator{}
|
|
|
|
if got := g.Slug("Paweł"); got != "pawel" {
|
|
t.Fatalf("slug Paweł = %q, want pawel", got)
|
|
}
|
|
if got := g.Slug("John Doe"); got != "johndoe" {
|
|
t.Fatalf("slug John Doe = %q, want johndoe", got)
|
|
}
|
|
if got := g.Slug("Zoë"); got != "zoe" {
|
|
t.Fatalf("slug Zoë = %q, want zoe", got)
|
|
}
|
|
|
|
handle := g.Generate("James", func(string) bool { return false }, nil)
|
|
if handle != "james" {
|
|
t.Fatalf("generate James = %q, want james", handle)
|
|
}
|
|
if !validHandle(handle) {
|
|
t.Fatalf("generated %q is outside [a-z0-9._-]{2,255}", handle)
|
|
}
|
|
|
|
taken := map[string]struct{}{}
|
|
isTaken := func(c string) bool {
|
|
_, ok := taken[c]
|
|
return ok
|
|
}
|
|
first := g.Generate("James", isTaken, nil)
|
|
taken[first] = struct{}{}
|
|
second := g.Generate("James", isTaken, nil)
|
|
taken[second] = struct{}{}
|
|
third := g.Generate("James", isTaken, nil)
|
|
if first != "james" || second != "james1" || third != "james2" {
|
|
t.Fatalf("suffixes = %q %q %q, want james james1 james2", first, second, third)
|
|
}
|
|
|
|
id := uint(42)
|
|
if got := g.Generate("", func(string) bool { return false }, &id); got != "user42" {
|
|
t.Fatalf("empty name = %q, want user42", got)
|
|
}
|
|
if got := g.Generate("x", func(string) bool { return false }, &id); got != "user42" {
|
|
t.Fatalf("short name = %q, want user42", got)
|
|
}
|
|
if got := g.Generate("???", func(string) bool { return false }, &id); got != "user42" {
|
|
t.Fatalf("punctuation name = %q, want user42", got)
|
|
}
|
|
if got := g.Generate("", func(string) bool { return false }, nil); got != "user" {
|
|
t.Fatalf("no id = %q, want user", got)
|
|
}
|
|
|
|
names := []string{"James", "Paweł", "John Doe", "???", "a", "Zoë", " ", "....", "O'Brien"}
|
|
for _, name := range names {
|
|
got := g.Generate(name, func(string) bool { return false }, &id)
|
|
if !validHandle(got) {
|
|
t.Errorf("generated %q for %q is outside the MentionParser subset", got, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func validHandle(s string) bool {
|
|
if len(s) < 2 || len(s) > 255 {
|
|
return false
|
|
}
|
|
for _, r := range s {
|
|
switch {
|
|
case r >= 'a' && r <= 'z', r >= '0' && r <= '9', r == '.', r == '_', r == '-':
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|