""" P-05b: POST /api/auth/reset-password muss Passwoerter unter 8 Zeichen ablehnen. Prueft Pydantic-Validierung (HTTP 422) BEVOR die DB befragt wird. """ from __future__ import annotations import os from unittest.mock import MagicMock, patch import pytest from fastapi.testclient import TestClient os.environ.setdefault("SKIP_DB_MIGRATE", "1") from main import app @pytest.fixture def client() -> TestClient: return TestClient(app) def _mock_db_valid_token() -> MagicMock: mock_cur = MagicMock() mock_cur.fetchone.return_value = {"profile_id": 1} mock_conn = MagicMock() mock_cm = MagicMock() mock_cm.__enter__.return_value = mock_conn mock_cm.__exit__.return_value = False return mock_cm, mock_cur # ── Mindestlaenge-Grenzwerte ────────────────────────────────────────────────── @pytest.mark.parametrize("short_pw", ["", "a", "1234567"]) def test_reset_password_too_short_rejected(client: TestClient, short_pw: str) -> None: """Passwort < 8 Zeichen muss mit 422 abgelehnt werden (Pydantic-Validierung).""" r = client.post( "/api/auth/reset-password", json={"token": "sometoken", "new_password": short_pw}, ) assert r.status_code == 422, ( f"Erwartet 422 fuer Passwort {short_pw!r} ({len(short_pw)} Zeichen), " f"erhalten {r.status_code}" ) def test_reset_password_exactly_8_chars_accepted(client: TestClient) -> None: """Passwort mit genau 8 Zeichen muss die Validierung passieren.""" mock_cm, mock_cur = _mock_db_valid_token() with patch("routers.auth.get_db", return_value=mock_cm), patch( "routers.auth.get_cursor", return_value=mock_cur ): r = client.post( "/api/auth/reset-password", json={"token": "sometoken", "new_password": "12345678"}, ) assert r.status_code == 200 assert r.json().get("ok") is True def test_reset_password_long_password_accepted(client: TestClient) -> None: """Langes Passwort (>= 8 Zeichen) muss akzeptiert werden.""" mock_cm, mock_cur = _mock_db_valid_token() with patch("routers.auth.get_db", return_value=mock_cm), patch( "routers.auth.get_cursor", return_value=mock_cur ): r = client.post( "/api/auth/reset-password", json={"token": "sometoken", "new_password": "sicheresPasswort123!"}, ) assert r.status_code == 200 def test_reset_password_missing_field_rejected(client: TestClient) -> None: """Fehlendes new_password-Feld muss mit 422 abgelehnt werden.""" r = client.post( "/api/auth/reset-password", json={"token": "sometoken"}, ) assert r.status_code == 422 def test_reset_password_invalid_token_returns_400(client: TestClient) -> None: """Gueltiges Passwort aber ungueltiger Token muss 400 liefern.""" mock_cur = MagicMock() mock_cur.fetchone.return_value = None mock_conn = MagicMock() mock_cm = MagicMock() mock_cm.__enter__.return_value = mock_conn mock_cm.__exit__.return_value = False with patch("routers.auth.get_db", return_value=mock_cm), patch( "routers.auth.get_cursor", return_value=mock_cur ): r = client.post( "/api/auth/reset-password", json={"token": "ungueltig", "new_password": "validesPw123"}, ) assert r.status_code == 400