2019-04-29 19:27:42 -05:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2013-06-06 09:40:10 -05:00
|
|
|
|
require 'user_name_suggester'
|
|
|
|
|
|
2022-07-27 21:27:38 -05:00
|
|
|
|
RSpec.describe UserNameSuggester do
|
2013-06-06 09:40:10 -05:00
|
|
|
|
describe '.suggest' do
|
2013-08-29 09:15:02 -05:00
|
|
|
|
before do
|
2019-04-23 05:22:47 -05:00
|
|
|
|
SiteSetting.min_username_length = 3
|
|
|
|
|
SiteSetting.max_username_length = 15
|
2021-10-04 07:47:55 -05:00
|
|
|
|
SiteSetting.reserved_usernames = ''
|
2013-08-29 09:15:02 -05:00
|
|
|
|
end
|
2013-06-06 09:40:10 -05:00
|
|
|
|
|
2019-05-16 02:15:03 -05: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 08:25:54 -05: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 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
2018-09-10 11:20:51 -05:00
|
|
|
|
it "doesn't raise an error on integer username" do
|
|
|
|
|
expect(UserNameSuggester.suggest(999)).to eq('999')
|
|
|
|
|
end
|
|
|
|
|
|
2013-06-06 09:40:10 -05:00
|
|
|
|
it 'corrects weird characters' do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest("Darth%^Vader")).to eq('Darth_Vader')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'adds 1 to an existing username' do
|
|
|
|
|
user = Fabricate(:user)
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest(user.username)).to eq("#{user.username}1")
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "adds numbers if it's too short" do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest('a')).to eq('a11')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
2019-04-23 05:22:47 -05: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 09:40:10 -05:00
|
|
|
|
it "has a special case for me and i emails" do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest('me@eviltrout.com')).to eq('eviltrout')
|
|
|
|
|
expect(UserNameSuggester.suggest('i@eviltrout.com')).to eq('eviltrout')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "shortens very long suggestions" do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest("myreallylongnameisrobinwardesquire")).to eq('myreallylongnam')
|
2013-06-06 09:40:10 -05: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-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest("myreallylongnam")).to eq('myreallylongna1')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
2015-08-25 15:33:50 -05:00
|
|
|
|
it "doesn't suggest reserved usernames" do
|
2016-01-27 02:04:11 -06:00
|
|
|
|
SiteSetting.reserved_usernames = 'myadmin|steve|steve1'
|
|
|
|
|
expect(UserNameSuggester.suggest("myadmin@hissite.com")).to eq('myadmin1')
|
2015-08-25 15:33:50 -05:00
|
|
|
|
expect(UserNameSuggester.suggest("steve")).to eq('steve2')
|
|
|
|
|
end
|
|
|
|
|
|
2016-01-27 02:04:11 -06: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
|
|
|
|
|
|
2013-06-06 09:40:10 -05:00
|
|
|
|
it "removes leading character if it is not alphanumeric" do
|
2016-01-20 08:37:34 -06:00
|
|
|
|
expect(UserNameSuggester.suggest(".myname")).to eq('myname')
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "allows leading _" do
|
|
|
|
|
expect(UserNameSuggester.suggest("_myname")).to eq('_myname')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "removes trailing characters if they are invalid" do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest("myname!^$=")).to eq('myname')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
2021-10-04 07:47:55 -05: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 08:37:34 -06:00
|
|
|
|
it "allows dots in the middle" do
|
|
|
|
|
expect(UserNameSuggester.suggest("my.name")).to eq('my.name')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "remove leading dots" do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest(".myname")).to eq('myname')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "remove trailing dots" do
|
2015-01-09 10:34:37 -06:00
|
|
|
|
expect(UserNameSuggester.suggest("myname.")).to eq('myname')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
|
|
|
|
|
2015-09-11 06:23:26 -05: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 09:40:10 -05:00
|
|
|
|
it 'should handle typical facebook usernames' do
|
2016-01-20 08:37:34 -06:00
|
|
|
|
expect(UserNameSuggester.suggest('roger.nelson.3344913')).to eq('roger.nelson.33')
|
2013-06-06 09:40:10 -05:00
|
|
|
|
end
|
2016-02-21 16:11:52 -06: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 09:40:10 -05:00
|
|
|
|
|
2021-12-06 10:49:04 -06: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-21 11:13:05 -06:00
|
|
|
|
suggestion = UserNameSuggester.suggest("bill", current_username: "bill3")
|
2021-12-06 10:49:04 -06:00
|
|
|
|
|
|
|
|
|
expect(suggestion).to eq "bill3"
|
|
|
|
|
end
|
|
|
|
|
|
2021-12-21 11:13:05 -06: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 05:22:47 -05: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 07:47:55 -05: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 05:22:47 -05:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with Unicode usernames enabled" do
|
|
|
|
|
before { SiteSetting.unicode_usernames = true }
|
|
|
|
|
|
2020-12-22 15:51:36 -06:00
|
|
|
|
it "normalizes unicode usernames with Σ to lowercase" do
|
|
|
|
|
expect(UserNameSuggester.suggest('ΣΣ\'"ΣΣ')).to eq('σς_σς')
|
|
|
|
|
end
|
|
|
|
|
|
2019-04-23 05:22:47 -05: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('য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া'))
|
|
|
|
|
.to eq('য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া-য়া')
|
|
|
|
|
end
|
2019-10-01 13:31:22 -05:00
|
|
|
|
|
2020-07-26 19:23:54 -05:00
|
|
|
|
it "uses allowlist" do
|
|
|
|
|
SiteSetting.allowed_unicode_username_characters = "[äöüßÄÖÜẞ]"
|
2019-10-01 13:31:22 -05:00
|
|
|
|
|
2021-10-04 07:47:55 -05:00
|
|
|
|
expect(UserNameSuggester.suggest('πουλί')).to eq(I18n.t('fallback_username'))
|
2019-10-01 13:31:22 -05:00
|
|
|
|
expect(UserNameSuggester.suggest('a鳥b')).to eq('a_b')
|
|
|
|
|
expect(UserNameSuggester.suggest('Löwe')).to eq('Löwe')
|
|
|
|
|
|
2020-07-26 19:23:54 -05:00
|
|
|
|
SiteSetting.allowed_unicode_username_characters = "[য়া]"
|
2019-10-01 13:31:22 -05:00
|
|
|
|
expect(UserNameSuggester.suggest('aয়াb鳥c')).to eq('aয়াb_c')
|
|
|
|
|
end
|
2019-04-23 05:22:47 -05:00
|
|
|
|
end
|
|
|
|
|
end
|
2013-08-29 09:15:02 -05:00
|
|
|
|
end
|