package user import "testing" func TestSanitizeForUsername(t *testing.T) { cases := []struct { in, want string }{ {"alice", "alice"}, {"Alice", "alice"}, {" Alice ", "alice"}, {"Alice Bob", "alice_bob"}, {"alice bob", "alice_bob"}, {"Alice!@#Bob", "alice_bob"}, {"-alice", "alice"}, {"_alice", "alice"}, {"alice_", "alice"}, {"alice--bob", "alice-bob"}, {"alice__bob", "alice_bob"}, {" ", ""}, {"", ""}, {"!!!", ""}, {"日本語", ""}, {"alice日本", "alice"}, {"thisusernameiswaytoolongtobevalid12345", "thisusernameiswaytoolongtobeva"}, } for _, tc := range cases { got := SanitizeForUsername(tc.in) if got != tc.want { t.Errorf("SanitizeForUsername(%q) = %q, want %q", tc.in, got, tc.want) } } } func TestSanitizeForUsernamePassesValidate(t *testing.T) { inputs := []string{"Alice Bob", " S0me User! ", "alice--bob"} for _, in := range inputs { s := SanitizeForUsername(in) if s == "" { t.Fatalf("unexpected empty sanitize for %q", in) } if err := ValidateUsername(s, nil); err != nil { t.Errorf("sanitized %q -> %q failed ValidateUsername: %v", in, s, err) } } } func TestCandidateFromMetadataPrecedence(t *testing.T) { const domain = "azzamo.net" reserved := []string{"admin"} cases := []struct { desc string name, dn, dnAlt, username, nip05, dom string want string }{ { desc: "nip05 local part wins when domain matches", name: "alice", nip05: "preferred@azzamo.net", dom: domain, want: "preferred", }, { desc: "nip05 ignored when domain differs", name: "alice", nip05: "preferred@other.example", dom: domain, want: "alice", }, { desc: "name takes precedence over display_name", name: "alice", dn: "Bob Builder", dom: domain, want: "alice", }, { desc: "falls back to display_name when name empty", dn: "Bob Builder", dom: domain, want: "bob_builder", }, { desc: "falls back to camelCase displayName when others empty", dnAlt: "Bob B", dom: domain, want: "bob_b", }, { desc: "falls back to deprecated username last", username: "legacy_user", dom: domain, want: "legacy_user", }, { desc: "skips fields that sanitize to empty", name: "!!!", dn: "Real Name", dom: domain, want: "real_name", }, { desc: "skips reserved words and falls through", name: "admin", dn: "Real Name", dom: domain, want: "real_name", }, { desc: "no usable field returns empty", name: "!!!", dom: domain, want: "", }, { desc: "bare nip05 with no @ is ignored", nip05: "alice", name: "fallback", dom: domain, want: "fallback", }, { desc: "empty service domain ignores nip05", name: "alice", nip05: "preferred@azzamo.net", want: "alice", }, } for _, tc := range cases { got := CandidateFromMetadata(tc.name, tc.dn, tc.dnAlt, tc.username, tc.nip05, tc.dom, reserved) if got != tc.want { t.Errorf("%s: got %q want %q", tc.desc, got, tc.want) } } }