import pytest from password_generator.constants import LETTERS, NUMBERS, SYMBOLS from password_generator.generator import generate_easy_password, generate_hard_password def test_easy_password_is_ordered_letters_symbols_numbers(): password = generate_easy_password(4, 2, 2) assert len(password) == 8 assert all(c in LETTERS for c in password[:4]) assert all(c in SYMBOLS for c in password[4:6]) assert all(c in NUMBERS for c in password[6:]) def test_hard_password_has_requested_composition(): password = generate_hard_password(5, 3, 4) assert len(password) == 12 assert sum(c in LETTERS for c in password) == 5 assert sum(c in SYMBOLS for c in password) == 3 assert sum(c in NUMBERS for c in password) == 4 def test_hard_password_is_shuffled(): # 20 letters then 20 numbers in that exact order is astronomically unlikely after a shuffle. results = {generate_hard_password(20, 0, 20) for _ in range(5)} assert any(not (p[:20].isalpha() and p[20:].isdigit()) for p in results) def test_zero_counts_give_empty_password(): assert generate_easy_password(0, 0, 0) == "" assert generate_hard_password(0, 0, 0) == "" @pytest.mark.parametrize("func", [generate_easy_password, generate_hard_password]) def test_negative_counts_raise(func): with pytest.raises(ValueError): func(-1, 0, 0)