"""Тесты для app/core/password.py — bcrypt hash/verify (#2550).""" from __future__ import annotations import pytest from app.core.password import hash_password, verify_password def test_roundtrip() -> None: """hash_password → verify_password с тем же паролем возвращает True.""" hashed = hash_password("correct horse battery staple") assert verify_password("correct horse battery staple", hashed) is True def test_wrong_password_returns_false() -> None: """Неверный пароль против валидного хеша → False.""" hashed = hash_password("correct horse battery staple") assert verify_password("wrong password", hashed) is False def test_hash_too_long_raises_value_error() -> None: """Пароль >72 байт в UTF-8 → ValueError в hash_password (нет silent truncation).""" long_password = "a" * 73 with pytest.raises(ValueError): hash_password(long_password) def test_hash_exactly_72_bytes_ok() -> None: """Ровно 72 байта — граничное значение, ещё допустимо.""" password = "a" * 72 hashed = hash_password(password) assert verify_password(password, hashed) is True def test_hash_too_long_multibyte_raises_value_error() -> None: """40 кириллических символов = 80 байт UTF-8 (2 байта/символ) → ValueError. Проверяет, что лимит считается в байтах, а не в символах — иначе 40-символьный кириллический пароль (< 72 символов, но 80 байт) прошёл бы мимо guard'а. """ long_cyrillic_password = "а" * 40 assert len(long_cyrillic_password.encode("utf-8")) == 80 with pytest.raises(ValueError): hash_password(long_cyrillic_password) def test_verify_too_long_returns_false_not_raise() -> None: """verify_password на >72-байтовом пароле возвращает False, НЕ raise.""" hashed = hash_password("some valid password") long_password = "a" * 73 assert verify_password(long_password, hashed) is False def test_hash_empty_raises_value_error() -> None: """Пустой пароль → ValueError в hash_password.""" with pytest.raises(ValueError): hash_password("") def test_verify_empty_returns_false() -> None: """Пустой пароль в verify_password → False (не raise).""" hashed = hash_password("some valid password") assert verify_password("", hashed) is False def test_hash_is_unique_due_to_salt() -> None: """Два хеша одного пароля различаются (уникальная соль на каждый вызов).""" password = "correct horse battery staple" hash1 = hash_password(password) hash2 = hash_password(password) assert hash1 != hash2 assert verify_password(password, hash1) is True assert verify_password(password, hash2) is True def test_verify_malformed_hash_returns_false() -> None: """Некорректный (не-bcrypt) хеш в verify_password → False, не raise.""" assert verify_password("some password", "not-a-bcrypt-hash") is False