2019-04-30 08:27:42 +08:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2013-06-06 22:40:10 +08:00
|
|
|
|
require "user_name_suggester"
|
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
|
RSpec.describe UserNameSuggester do
|
2013-06-06 22:40:10 +08:00
|
|
|
|
describe ".suggest" do
|
2013-08-29 22:15:02 +08:00
|
|
|
|
before do
|
2019-04-23 18:22:47 +08:00
|
|
|
|
SiteSetting.min_username_length = 3
|
|
|
|
|
SiteSetting.max_username_length = 15
|
2021-10-04 20:47:55 +08:00
|
|
|
|
SiteSetting.reserved_usernames = ""
|
2013-08-29 22:15:02 +08:00
|
|
|
|
end
|
2013-06-06 22:40:10 +08:00
|
|
|
|
|
2019-05-16 15:15:03 +08:00
|
|
|
|
it "keeps adding numbers to the username" do
|
|
|
|
|
Fabricate(:user, username: "sam")
|
|
|
|
|
Fabricate(:user, username: "sAm1")
|
|
|
|
|
Fabricate(:user, username: "sam2")
|
|
|
|
|
Fabricate(:user, username: "sam4")
|
|
|
|
|
|
|
|
|
|
expect(UserNameSuggester.suggest("saM")).to eq("saM3")
|
|
|
|
|
end
|
|
|
|
|
|
2021-10-12 21:25:54 +08:00
|
|
|
|
it "doesn't raise an error on nil username and suggest the fallback username" do
|
|
|
|
|
expect(UserNameSuggester.suggest(nil)).to eq(I18n.t("fallback_username"))
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2018-09-11 00:20:51 +08:00
|
|
|
|
it "doesn't raise an error on integer username" do
|
|
|
|
|
expect(UserNameSuggester.suggest(999)).to eq("999")
|
|
|
|
|
end
|
|
|
|
|
|
2013-06-06 22:40:10 +08:00
|
|
|
|
it "corrects weird characters" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("Darth%^Vader")).to eq("Darth_Vader")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds 1 to an existing username" do
|
|
|
|
|
user = Fabricate(:user)
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest(user.username)).to eq("#{user.username}1")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds numbers if it's too short" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("a")).to eq("a11")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2019-04-23 18:22:47 +08:00
|
|
|
|
it "is able to guess a decent username from an email" do
|
|
|
|
|
expect(UserNameSuggester.suggest("bob@example.com")).to eq("bob")
|
|
|
|
|
end
|
|
|
|
|
|
2013-06-06 22:40:10 +08:00
|
|
|
|
it "has a special case for me and i emails" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("me@eviltrout.com")).to eq("eviltrout")
|
|
|
|
|
expect(UserNameSuggester.suggest("i@eviltrout.com")).to eq("eviltrout")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "shortens very long suggestions" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("myreallylongnameisrobinwardesquire")).to eq(
|
|
|
|
|
"myreallylongnam",
|
|
|
|
|
)
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "makes room for the digit added if the username is too long" do
|
|
|
|
|
User.create(username: "myreallylongnam", email: "fake@discourse.org")
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("myreallylongnam")).to eq("myreallylongna1")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2015-08-26 04:33:50 +08:00
|
|
|
|
it "doesn't suggest reserved usernames" do
|
2016-01-27 16:04:11 +08:00
|
|
|
|
SiteSetting.reserved_usernames = "myadmin|steve|steve1"
|
|
|
|
|
expect(UserNameSuggester.suggest("myadmin@hissite.com")).to eq("myadmin1")
|
2015-08-26 04:33:50 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("steve")).to eq("steve2")
|
|
|
|
|
end
|
|
|
|
|
|
2016-01-27 16:04:11 +08:00
|
|
|
|
it "doesn't suggest generic usernames" do
|
|
|
|
|
UserNameSuggester::GENERIC_NAMES.each do |name|
|
|
|
|
|
expect(UserNameSuggester.suggest("#{name}@apple.org")).to eq("apple")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-12-04 20:45:19 +08:00
|
|
|
|
it "replaces the leading character with _ if it is not alphanumeric" do
|
|
|
|
|
expect(UserNameSuggester.suggest("=myname")).to eq("_myname")
|
2016-01-20 22:37:34 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "allows leading _" do
|
|
|
|
|
expect(UserNameSuggester.suggest("_myname")).to eq("_myname")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "removes trailing characters if they are invalid" do
|
2015-01-10 00:34:37 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("myname!^$=")).to eq("myname")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2021-10-04 20:47:55 +08:00
|
|
|
|
it "suggest a fallback username if name contains only invalid characters" do
|
|
|
|
|
suggestion = UserNameSuggester.suggest("---")
|
|
|
|
|
expect(suggestion).to eq(I18n.t("fallback_username"))
|
|
|
|
|
end
|
|
|
|
|
|
2016-01-20 22:37:34 +08:00
|
|
|
|
it "allows dots in the middle" do
|
|
|
|
|
expect(UserNameSuggester.suggest("my.name")).to eq("my.name")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2023-12-04 20:45:19 +08:00
|
|
|
|
it "replaces multiple dots in the middle with _" do
|
|
|
|
|
expect(UserNameSuggester.suggest("my..name")).to eq("my_name")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2023-12-04 20:45:19 +08:00
|
|
|
|
it "removes leading dots" do
|
|
|
|
|
expect(UserNameSuggester.suggest("..myname")).to eq("myname")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "removes trailing dots" do
|
|
|
|
|
expect(UserNameSuggester.suggest("myname..")).to eq("myname")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
|
|
|
|
|
2015-09-11 19:23:26 +08:00
|
|
|
|
it "handles usernames with a sequence of 2 or more special chars" do
|
|
|
|
|
expect(UserNameSuggester.suggest("Darth__Vader")).to eq("Darth_Vader")
|
|
|
|
|
expect(UserNameSuggester.suggest("Darth_-_Vader")).to eq("Darth_Vader")
|
|
|
|
|
end
|
|
|
|
|
|
2013-06-06 22:40:10 +08:00
|
|
|
|
it "should handle typical facebook usernames" do
|
2016-01-20 22:37:34 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("roger.nelson.3344913")).to eq("roger.nelson.33")
|
2013-06-06 22:40:10 +08:00
|
|
|
|
end
|
2016-02-22 06:11:52 +08:00
|
|
|
|
|
|
|
|
|
it "removes underscore at the end of long usernames that get truncated" do
|
|
|
|
|
expect(UserNameSuggester.suggest("uuuuuuuuuuuuuu_u")).to_not end_with("_")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds number if it's too short after removing trailing underscore" do
|
|
|
|
|
User.stubs(:username_length).returns(8..8)
|
|
|
|
|
expect(UserNameSuggester.suggest("uuuuuuu_u")).to eq("uuuuuuu1")
|
|
|
|
|
end
|
2013-06-06 22:40:10 +08:00
|
|
|
|
|
2021-12-07 00:49:04 +08:00
|
|
|
|
it "preserves current username" do
|
|
|
|
|
# if several users have username "bill" on the external site,
|
|
|
|
|
# they will have usernames bill, bill1, bill2 etc in Discourse:
|
|
|
|
|
Fabricate(:user, username: "bill")
|
|
|
|
|
Fabricate(:user, username: "bill1")
|
|
|
|
|
Fabricate(:user, username: "bill2")
|
|
|
|
|
Fabricate(:user, username: "bill3")
|
|
|
|
|
Fabricate(:user, username: "bill4")
|
|
|
|
|
|
|
|
|
|
# the number should be preserved, bill3 should remain bill3
|
2021-12-22 01:13:05 +08:00
|
|
|
|
suggestion = UserNameSuggester.suggest("bill", current_username: "bill3")
|
2021-12-07 00:49:04 +08:00
|
|
|
|
|
|
|
|
|
expect(suggestion).to eq "bill3"
|
|
|
|
|
end
|
|
|
|
|
|
2021-12-22 01:13:05 +08:00
|
|
|
|
it "skips input made entirely of disallowed characters" do
|
|
|
|
|
SiteSetting.unicode_usernames = false
|
|
|
|
|
|
|
|
|
|
input = %w[Πλάτων علي William]
|
|
|
|
|
suggestion = UserNameSuggester.suggest(*input)
|
|
|
|
|
|
|
|
|
|
expect(suggestion).to eq "William"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "uses the first item if it isn't made entirely of disallowed characters" do
|
|
|
|
|
SiteSetting.unicode_usernames = false
|
|
|
|
|
|
|
|
|
|
input = %w[William علي Πλάτων]
|
|
|
|
|
suggestion = UserNameSuggester.suggest(*input)
|
|
|
|
|
|
|
|
|
|
expect(suggestion).to eq "William"
|
|
|
|
|
end
|
|
|
|
|
|
2019-04-23 18:22:47 +08:00
|
|
|
|
context "with Unicode usernames disabled" do
|
|
|
|
|
before { SiteSetting.unicode_usernames = false }
|
|
|
|
|
|
|
|
|
|
it "transliterates some characters" do
|
|
|
|
|
expect(UserNameSuggester.suggest("Jørn")).to eq("Jorn")
|
|
|
|
|
end
|
|
|
|
|
|
2021-10-04 20:47:55 +08:00
|
|
|
|
it "uses fallback username if there are Unicode characters only" do
|
|
|
|
|
fallback_username = I18n.t("fallback_username")
|
|
|
|
|
expect(UserNameSuggester.suggest("طائر")).to eq(fallback_username)
|
|
|
|
|
expect(UserNameSuggester.suggest("πουλί")).to eq(fallback_username)
|
2019-04-23 18:22:47 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with Unicode usernames enabled" do
|
|
|
|
|
before { SiteSetting.unicode_usernames = true }
|
|
|
|
|
|
2020-12-23 05:51:36 +08:00
|
|
|
|
it "normalizes unicode usernames with Σ to lowercase" do
|
|
|
|
|
expect(UserNameSuggester.suggest('ΣΣ\'"ΣΣ')).to eq("σς_σς")
|
|
|
|
|
end
|
|
|
|
|
|
2019-04-23 18:22:47 +08:00
|
|
|
|
it "does not transliterate" do
|
|
|
|
|
expect(UserNameSuggester.suggest("Jørn")).to eq("Jørn")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not replace Unicode characters" do
|
|
|
|
|
expect(UserNameSuggester.suggest("طائر")).to eq("طائر")
|
|
|
|
|
expect(UserNameSuggester.suggest("πουλί")).to eq("πουλί")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "shortens usernames by counting grapheme clusters" do
|
|
|
|
|
SiteSetting.max_username_length = 10
|
|
|
|
|
expect(UserNameSuggester.suggest("बहुत-लंबा-उपयोगकर्ता-नाम")).to eq("बहुत-लंबा-उपयो")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds numbers if it's too short" do
|
|
|
|
|
expect(UserNameSuggester.suggest("鳥")).to eq("鳥11")
|
|
|
|
|
|
|
|
|
|
# grapheme cluster consists of 3 code points
|
|
|
|
|
expect(UserNameSuggester.suggest("য়া")).to eq("য়া11")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "normalizes usernames" do
|
|
|
|
|
actual = "Löwe" # NFD, "Lo\u0308we"
|
|
|
|
|
expected = "Löwe" # NFC, "L\u00F6we"
|
|
|
|
|
|
|
|
|
|
expect(UserNameSuggester.suggest(actual)).to eq(expected)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not suggest a username longer than max column size" do
|
|
|
|
|
SiteSetting.max_username_length = 40
|
|
|
|
|
|
|
|
|
|
expect(
|
|
|
|
|
UserNameSuggester.suggest(
|
|
|
|
|
"য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া",
|
2023-01-09 19:18:21 +08:00
|
|
|
|
),
|
2019-04-23 18:22:47 +08:00
|
|
|
|
).to eq("য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া")
|
|
|
|
|
end
|
2019-10-02 02:31:22 +08:00
|
|
|
|
|
2020-07-27 08:23:54 +08:00
|
|
|
|
it "uses allowlist" do
|
|
|
|
|
SiteSetting.allowed_unicode_username_characters = "[äöüßÄÖÜẞ]"
|
2019-10-02 02:31:22 +08:00
|
|
|
|
|
2021-10-04 20:47:55 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("πουλί")).to eq(I18n.t("fallback_username"))
|
2019-10-02 02:31:22 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("a鳥b")).to eq("a_b")
|
|
|
|
|
expect(UserNameSuggester.suggest("Löwe")).to eq("Löwe")
|
|
|
|
|
|
2020-07-27 08:23:54 +08:00
|
|
|
|
SiteSetting.allowed_unicode_username_characters = "[য়া]"
|
2019-10-02 02:31:22 +08:00
|
|
|
|
expect(UserNameSuggester.suggest("aয়াb鳥c")).to eq("aয়াb_c")
|
|
|
|
|
end
|
2019-04-23 18:22:47 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2013-08-29 22:15:02 +08:00
|
|
|
|
end
|