Skip to content

Commit 4a8fb7b

Browse files
francktrouillezthdaraujo
authored andcommitted
Allow to forbid digits in Faker::Internet.password method
This change allows to allow or not digits inside the password. If `digits: true`, a digit is automatically added.
1 parent 789251c commit 4a8fb7b

File tree

2 files changed

+66
-26
lines changed

2 files changed

+66
-26
lines changed

lib/faker/default/internet.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def username(specifier: nil, separators: %w[. _])
108108
# @param max_length [Integer] The maximum length of the password
109109
# @param mix_case [Boolean] Toggles if uppercased letters are allowed. If true, at least one will be added.
110110
# @param special_characters [Boolean] Toggles if special characters are allowed. If true, at least one will be added.
111+
# @param digits [Boolean] Toggles if digits are allowed. If true, at least one will be added.
111112
#
112113
# @return [String]
113114
#
@@ -121,9 +122,13 @@ def username(specifier: nil, separators: %w[. _])
121122
# Faker::Internet.password(min_length: 10, max_length: 20, mix_case: true) #=> "3k5qS15aNmG"
122123
# @example
123124
# Faker::Internet.password(min_length: 10, max_length: 20, mix_case: true, special_characters: true) #=> "*%NkOnJsH4"
125+
# @example
126+
# Faker::Internet.password(min_length: 10, max_length: 20, mix_case: true, special_characters: true, digits: true) #=> "$f%Ym*sc91e4O^"
127+
# @example
128+
# Faker::Internet.password(min_length: 10, max_length: 20, mix_case: true, special_characters: true, digits: false) #=> "rI$XYZgmBONFKWIZ$B"
124129
#
125130
# @faker.version 2.1.3
126-
def password(min_length: 8, max_length: 16, mix_case: true, special_characters: false)
131+
def password(min_length: 8, max_length: 16, mix_case: true, special_characters: false, digits: true)
127132
raise ArgumentError, 'min_length and max_length must be greater than or equal to one' if min_length < 1 || max_length < 1
128133
raise ArgumentError, 'min_length must be smaller than or equal to max_length' unless min_length <= max_length
129134

@@ -140,6 +145,11 @@ def password(min_length: 8, max_length: 16, mix_case: true, special_characters:
140145
required_min_length += 1
141146
end
142147

148+
if digits
149+
character_types << :digits
150+
required_min_length += 1
151+
end
152+
143153
raise ArgumentError, "min_length should be at least #{required_min_length} to enable #{character_types.join(', ')} configuration" if min_length < required_min_length
144154

145155
target_length = rand(min_length..max_length)
@@ -152,10 +162,6 @@ def password(min_length: 8, max_length: 16, mix_case: true, special_characters:
152162
password << sample(lower_chars)
153163
character_bag += lower_chars
154164

155-
digits = ('0'..'9').to_a
156-
password << sample(digits)
157-
character_bag += digits
158-
159165
if mix_case
160166
upper_chars = self::ULetters
161167
password << sample(upper_chars)
@@ -168,6 +174,12 @@ def password(min_length: 8, max_length: 16, mix_case: true, special_characters:
168174
character_bag += special_chars
169175
end
170176

177+
if digits
178+
digits_chars = ('0'..'9').to_a
179+
password << sample(digits_chars)
180+
character_bag += digits_chars
181+
end
182+
171183
password << sample(character_bag) while password.length < target_length
172184

173185
shuffle(password).join

test/faker/default/test_faker_internet.rb

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ def test_password_with_min_length_eq_1_without_mix_case
232232
end
233233

234234
def test_password_with_min_length_and_max_length
235-
min_length = 2
236-
max_length = 5
235+
min_length = 3
236+
max_length = 6
237237
password = @tester.password(min_length: min_length, max_length: max_length)
238238

239239
assert_match(/\w+/, password)
@@ -265,34 +265,45 @@ def test_password_without_special_chars
265265
assert_match(/[^!@#$%\^&*]+/, @tester.password(min_length: 8, max_length: 12, mix_case: true))
266266
end
267267

268-
def test_password_with_special_chars_and_mixed_case
268+
def test_password_with_digits
269+
assert_match(/[0-9]+/, @tester.password(min_length: 8, max_length: 12, digits: true))
270+
end
271+
272+
def test_password_without_digits
273+
assert_match(/^[^0-9]+$/, @tester.password(min_length: 8, max_length: 12, digits: false))
274+
end
275+
276+
def test_password_with_special_chars_and_mixed_case_and_digits
269277
32.times do
270-
password = @tester.password(min_length: 4, max_length: 6, mix_case: true, special_characters: true)
278+
password = @tester.password(min_length: 4, max_length: 6, mix_case: true, special_characters: true, digits: true)
271279

272280
assert_match(/[!@#$%\^&*]+/, password)
273281
assert_match(/[A-z]+/, password)
282+
assert_match(/[0-9]+/, password)
274283
end
275284
end
276285

277-
def test_deterministic_password_with_special_chars_and_mixed_case
278-
deterministically_verify -> { @tester.password(min_length: 4, max_length: 6, mix_case: true, special_characters: true) }, depth: 4 do |password|
286+
def test_deterministic_password_with_special_chars_and_mixed_case_and_digits
287+
deterministically_verify -> { @tester.password(min_length: 4, max_length: 6, mix_case: true, special_characters: true, digits: true) }, depth: 4 do |password|
279288
assert_match(/[!@#$%\^&*]+/, password)
280289
assert_match(/[A-z]+/, password)
290+
assert_match(/[0-9]+/, password)
281291
end
282292
end
283293

284-
def test_password_with_special_chars_and_mixed_case_on_3chars_password
294+
def test_password_with_special_chars_and_mixed_case_and_digits_on_4chars_password
285295
16.times do
286-
password = @tester.password(min_length: 3, max_length: 6, mix_case: true, special_characters: true)
296+
password = @tester.password(min_length: 4, max_length: 6, mix_case: true, special_characters: true, digits: true)
287297

288298
assert_match(/[!@#$%\^&*]+/, password)
289299
assert_match(/[A-z]+/, password)
300+
assert_match(/[0-9]+/, password)
290301
end
291302
end
292303

293-
def test_password_with_invalid_min_length_for_mix_case_and_special_characters
294-
assert_raise_message 'min_length should be at least 3 to enable mix_case, special_characters configuration' do
295-
@tester.password(min_length: 1, mix_case: true, special_characters: true)
304+
def test_password_with_invalid_min_length_for_mix_case_and_special_characters_and_digits
305+
assert_raise_message 'min_length should be at least 4 to enable mix_case, special_characters, digits configuration' do
306+
@tester.password(min_length: 1, mix_case: true, special_characters: true, digits: true)
296307
end
297308
end
298309

@@ -306,35 +317,52 @@ def test_password_with_invalid_min_max_length
306317

307318
def test_password_with_invalid_min_length_for_special_characters_only
308319
error = assert_raises(ArgumentError) do
309-
@tester.password(min_length: 0, mix_case: false, special_characters: true)
320+
@tester.password(min_length: 0, mix_case: false, special_characters: true, digits: false)
310321
end
311322

312323
assert_equal 'min_length and max_length must be greater than or equal to one', error.message
313324
end
314325

315326
def test_password_with_invalid_min_length_for_mix_case_only
316327
error = assert_raises(ArgumentError) do
317-
@tester.password(min_length: 1, mix_case: true)
328+
@tester.password(min_length: 1, mix_case: true, special_characters: false, digits: false)
318329
end
319330

320331
assert_equal 'min_length should be at least 2 to enable mix_case configuration', error.message
321332
end
322333

334+
def test_password_with_invalid_min_length_for_digits_only
335+
error = assert_raises(ArgumentError) do
336+
@tester.password(min_length: 0, mix_case: false, special_characters: false, digits: true)
337+
end
338+
339+
assert_equal 'min_length and max_length must be greater than or equal to one', error.message
340+
end
341+
323342
def test_password_with_compatible_min_length_and_requirements
324343
assert_nothing_raised do
325-
[false, true].each do |value|
326-
min_length = value ? 2 : 1
327-
@tester.password(min_length: min_length, mix_case: value, special_characters: !value)
344+
[false, true].each do |mix_case|
345+
[false, true].each do |special_characters|
346+
[false, true].each do |digits|
347+
min_length = [[mix_case ? 2 : 0, special_characters ? 1 : 0, digits ? 1 : 0].sum, 1].max
348+
349+
@tester.password(min_length: min_length, mix_case: mix_case, special_characters: special_characters, digits: digits)
350+
end
351+
end
328352
end
329353
end
330354
end
331355

332356
def test_deterministic_password_with_compatible_min_length_and_requirements
333-
[false, true].each do |value|
334-
min_length = value ? 2 : 1
335-
336-
deterministically_verify -> { @tester.password(min_length: min_length, mix_case: value, special_characters: !value) }, depth: 4 do |password|
337-
assert_nothing_raised { password }
357+
[false, true].each do |mix_case|
358+
[false, true].each do |special_characters|
359+
[false, true].each do |digits|
360+
min_length = [[mix_case ? 2 : 0, special_characters ? 1 : 0, digits ? 1 : 0].sum, 1].max
361+
362+
deterministically_verify -> { @tester.password(min_length: min_length, mix_case: mix_case, special_characters: special_characters, digits: digits) }, depth: 4 do |password|
363+
assert_nothing_raised { password }
364+
end
365+
end
338366
end
339367
end
340368
end

0 commit comments

Comments
 (0)