@@ -24,7 +24,7 @@ class WeakPasswordTest < Authentication::ByPasswordTest
2424 user = user_with_password . call ( 'weakpassword' )
2525
2626 assert_not user . valid?
27- assert_equal User :: STRONG_PASSWORD_FAIL_MSG , user . errors [ :password ] . first
27+ assert_equal "is too short (minimum is 15 characters)" , user . errors [ :password ] . first
2828 end
2929
3030 test 'weak password must be present' do
@@ -52,7 +52,7 @@ class ExistingUsersTest < Authentication::ByPasswordTest
5252 @user . password = "nononono"
5353 @user . valid?
5454
55- assert_equal User :: STRONG_PASSWORD_FAIL_MSG , @user . errors [ :password ] . first
55+ assert_equal "is too short (minimum is 15 characters)" , @user . errors [ :password ] . first
5656 end
5757
5858 test 'password is not validated when user is sample data' do
@@ -66,17 +66,24 @@ class ExistingUsersTest < Authentication::ByPasswordTest
6666
6767 class ValidationsTest < Authentication ::ByPasswordTest
6868 test 'should be valid with ASCII printable characters and longer than 15 characters' do
69- user = @buyer . users . new password : "StrongPass123-+_!$#.@" , password_confirmation : "StrongPass123-+_!$#.@"
70- user . valid?
69+ user = user_with_password . call ( 'StrongPass123-+_!$#.@' )
70+
71+ assert user . valid?
72+ assert user . errors [ :password ] . blank?
73+ end
7174
75+ test 'should be valid with Unicode characters and longer than 15 characters' do
76+ user = user_with_password . call ( 'contraseña12345' )
77+
78+ assert user . valid?
7279 assert user . errors [ :password ] . blank?
7380 end
7481
7582 test 'should be invalid if shorter than 15 characters' do
7683 user = user_with_password . call ( 'Pas$123' )
7784 user . valid?
7885
79- assert_equal User :: STRONG_PASSWORD_FAIL_MSG , user . errors [ :password ] . first
86+ assert_equal "is too short (minimum is 15 characters)" , user . errors [ :password ] . first
8087 end
8188
8289 test 'should be invalid if password and password confirmation do not match' do
@@ -87,6 +94,41 @@ class ValidationsTest < Authentication::ByPasswordTest
8794 end
8895 end
8996
97+ class UnicodeNormalizationTest < Authentication ::ByPasswordTest
98+ test 'password is normalized to NFC before saving' do
99+ # "café" with e + combining acute accent (NFD form)
100+ password_nfd = "cafe\u0301 _secretpass"
101+ # "café" with precomposed é (NFC form)
102+ password_nfc = "café_secretpass"
103+
104+ assert_not_equal password_nfd , password_nfc
105+ assert_equal password_nfd . unicode_normalize ( :nfc ) , password_nfc
106+
107+ user = user_with_password . call ( password_nfd )
108+ user . password_confirmation = password_nfd
109+ user . save!
110+
111+ assert user . authenticated? ( password_nfc ) , 'Should authenticate with NFC form'
112+ assert user . authenticated? ( password_nfd ) , 'Should authenticate with NFD form (normalized before comparison)'
113+ end
114+
115+ test 'password length is counted after NFC normalization' do
116+ # 15 characters in NFD (e + combining accent = 2 code points)
117+ password_nfd = "contraseñas123" . unicode_normalize ( :nfd )
118+ # 14 characters in NFC (ñ = 1 code point)
119+ password_nfc = "contraseñas123" . unicode_normalize ( :nfc )
120+
121+ assert_equal 15 , password_nfd . length
122+ assert_equal 14 , password_nfc . length
123+
124+ user = user_with_password . call ( password_nfd )
125+ user . password_confirmation = password_nfd
126+
127+ assert_not user . valid? , 'Should be invalid because NFC-normalized length is 14 (< 15)'
128+ assert_equal "is too short (minimum is 15 characters)" , user . errors [ :password ] . first
129+ end
130+ end
131+
90132 class MethodsTest < Authentication ::ByPasswordTest
91133 class ValidatePasswordTest < MethodsTest
92134 setup do
0 commit comments