faker icon indicating copy to clipboard operation
faker copied to clipboard

FIX: Error when length less than 4 in Provider().password() #2176

Open DevFoxxx opened this issue 11 months ago • 3 comments

What does this change

Adds a warning message and adjusts the password length when the requested length is less than the number of required character categories (special characters, digits, uppercase, and lowercase).

What was wrong

When the password length was less than 4 (for example, 2), the password() function did not ensure that all required character types would be included, leading to unexpected behavior. This caused an error when the length was smaller than the minimum required for character categories.

How this fixes it

The modification checks if the requested password length is smaller than the number of required character categories. In that case, the function automatically adjusts the password length to the minimum value needed to fulfill the requirements for each character category. Additionally, a warning message is printed to inform the user of this adjustment.

Fixes #2176

Checklist

  • [x] I have read the documentation about CONTRIBUTING
  • [x] I have read the documentation about Coding style
  • [x] I have run make lint

DevFoxxx avatar Feb 14 '25 14:02 DevFoxxx

Hi @fcurella, I tested everything locally with this code:

import unittest
import string

# Correct import of the password function
from faker.password_generator import password  # Adjust the import to your project structure

class TestPasswordGenerator(unittest.TestCase):

    def test_length(self):
        # Test if the length of the password is correct
        pw = password(length=12)
        self.assertEqual(len(pw), 12, "Password length should be 12")

    def test_special_chars(self):
        # Test if the password contains at least one special character
        pw = password(special_chars=True, length=10)
        self.assertTrue(any(c in "!@#$%^&*()_+" for c in pw), "Password should contain at least one special character")

    def test_digits(self):
        # Test if the password contains at least one digit
        pw = password(digits=True, length=10)
        self.assertTrue(any(c in string.digits for c in pw), "Password should contain at least one digit")

    def test_upper_case(self):
        # Test if the password contains at least one uppercase letter
        pw = password(upper_case=True, length=10)
        self.assertTrue(any(c in string.ascii_uppercase for c in pw), "Password should contain at least one uppercase letter")

    def test_lower_case(self):
        # Test if the password contains at least one lowercase letter
        pw = password(lower_case=True, length=10)
        self.assertTrue(any(c in string.ascii_lowercase for c in pw), "Password should contain at least one lowercase letter")

    def test_no_special_chars(self):
        # Test if the password does not contain special characters when special_chars is False
        pw = password(special_chars=False, length=10)
        self.assertTrue(all(c not in "!@#$%^&*()_+" for c in pw), "Password should not contain special characters")

    def test_all_requirements(self):
        # Test if the password contains all the required character types
        pw = password(special_chars=True, digits=True, upper_case=True, lower_case=True, length=12)
        self.assertTrue(any(c in "!@#$%^&*()_+" for c in pw), "Password should contain at least one special character")
        self.assertTrue(any(c in string.digits for c in pw), "Password should contain at least one digit")
        self.assertTrue(any(c in string.ascii_uppercase for c in pw), "Password should contain at least one uppercase letter")
        self.assertTrue(any(c in string.ascii_lowercase for c in pw), "Password should contain at least one lowercase letter")

    def test_length_adjustment_for_required_characters(self):
        # Test if the length is increased when the required character types exceed the requested length
        pw = password(special_chars=True, digits=True, length=4)
        self.assertGreaterEqual(len(pw), 6, "Password length should be at least 6 if multiple character types are required")

if __name__ == "__main__":
    unittest.main()

Where and how should I add the tests you ask me?

DevFoxxx avatar Mar 05 '25 17:03 DevFoxxx

@DevFoxxx you can add it to this testcase

fcurella avatar Mar 05 '25 17:03 fcurella

As per the comment of @fcurella, please add the test case to the test suite in this PR.

Also, I would prefer to keep the error in case the password length is smaller than the number of required character categories. As end user, if I override the default length (10) to something lower then the categories... is because I want that length. but if it is not compatible with the categories, I would expect an error from the package.

joke2k avatar Apr 15 '25 18:04 joke2k