"""Password Handler 单元测试.""" from __future__ import annotations import pytest from packages.application.auth.password_handler import ( PasswordHandler, configure_password_handler, get_password_handler, ) @pytest.fixture def password_handler(): return PasswordHandler(rounds=4) # 用低rounds加速测试 class TestPasswordHandler: """PasswordHandler 测试""" def test_hash_password_returns_string(self, password_handler): """哈希密码返回非空字符串""" hashed = password_handler.hash_password("MyP@ssw0rd!") assert isinstance(hashed, str) assert len(hashed) > 0 assert hashed != "MyP@ssw0rd!" def test_hash_password_different_each_time(self, password_handler): """同一密码每次哈希结果不同(加盐)""" h1 = password_handler.hash_password("TestPass123") h2 = password_handler.hash_password("TestPass123") assert h1 != h2 def test_verify_password_correct(self, password_handler): """正确密码验证通过""" hashed = password_handler.hash_password("CorrectPass1!") assert password_handler.verify_password("CorrectPass1!", hashed) is True def test_verify_password_wrong(self, password_handler): """错误密码验证失败""" hashed = password_handler.hash_password("RightPass1!") assert password_handler.verify_password("WrongPass1!", hashed) is False def test_verify_password_empty_string(self, password_handler): """空字符串密码也能正确验证(不匹配)""" hashed = password_handler.hash_password("SomePass1!") assert password_handler.verify_password("", hashed) is False def test_hash_empty_password_raises(self, password_handler): """空密码哈希抛出 ValueError""" with pytest.raises(ValueError): password_handler.hash_password("") def test_needs_rehash_with_different_rounds(self): """不同 rounds 的哈希需要重新计算""" handler_low = PasswordHandler(rounds=4) handler_high = PasswordHandler(rounds=5) hashed = handler_low.hash_password("TestPass1!") assert handler_low.needs_rehash(hashed) is False assert handler_high.needs_rehash(hashed) is True def test_validate_strength_strong_password(self, password_handler): """强密码通过强度验证""" valid, error = password_handler.validate_strength("Str0ngP@ss!") assert valid is True assert error is None def test_validate_strength_too_short(self, password_handler): """密码太短不通过""" valid, error = password_handler.validate_strength("Sh0rt!") assert valid is False assert error is not None assert "长度" in error or "length" in error.lower() or "8" in error def test_validate_strength_no_uppercase(self, password_handler): """没有大写字母不通过""" valid, error = password_handler.validate_strength("lowercase1!") assert valid is False assert error is not None def test_validate_strength_no_lowercase(self, password_handler): """没有小写字母不通过""" valid, error = password_handler.validate_strength("UPPERCASE1!") assert valid is False assert error is not None def test_validate_strength_no_digit(self, password_handler): """没有数字不通过""" valid, error = password_handler.validate_strength("NoDigitPass!") assert valid is False assert error is not None def test_validate_strength_special_not_required(self, password_handler): """默认不要求特殊字符""" valid, error = password_handler.validate_strength("NoSpecial1") # 没有特殊字符也应该通过(require_special=False) assert valid is True assert error is None def test_validate_strength_empty_string(self, password_handler): """空字符串验证失败""" valid, error = password_handler.validate_strength("") assert valid is False assert error is not None def test_hash_and_verify_roundtrip(self, password_handler): """哈希-验证完整往返""" passwords = [ "Simple12", "C0mpl3x!Pass", "12345678aA", "user@example.com1", ] for pwd in passwords: hashed = password_handler.hash_password(pwd) assert password_handler.verify_password(pwd, hashed) assert not password_handler.verify_password(pwd + "x", hashed) class TestGlobalPasswordHandler: """全局密码处理器配置测试""" def test_get_password_handler_default(self): """未配置时 get_password_handler 返回默认实例""" import packages.application.auth.password_handler as pw_module pw_module._default_handler = None handler = get_password_handler() assert isinstance(handler, PasswordHandler) def test_configure_creates_handler(self): """configure_password_handler 创建并返回 handler""" import packages.application.auth.password_handler as pw_module pw_module._default_handler = None handler = configure_password_handler(rounds=4) assert isinstance(handler, PasswordHandler) assert get_password_handler() is handler def test_configure_overwrites_existing(self): """重新配置会覆盖之前的 handler""" import packages.application.auth.password_handler as pw_module pw_module._default_handler = None handler1 = configure_password_handler(rounds=4) handler2 = configure_password_handler(rounds=5) assert handler1 is not handler2 assert get_password_handler() is handler2 def test_get_password_handler_lazy_init(self): """未配置时首次调用 get_password_handler 会懒初始化""" import packages.application.auth.password_handler as pw_module pw_module._default_handler = None assert pw_module._default_handler is None handler = get_password_handler() assert pw_module._default_handler is not None assert pw_module._default_handler is handler