"""Сборка DSN из настроек. Регрессия: `PostgresDsn.build` не экранирует username/password сам — спецсимвол в пароле (запятая, `@`, `:`, `/`) ломает разбор URL. Баг воспроизводится только с «настоящим» паролем и незаметен на тестовых значениях вроде `test` или `postgres`. """ from __future__ import annotations import pytest from app.core.config import Settings def _settings(**overrides: str) -> Settings: defaults = { "secret_key": "test-secret-key", "encryption_key": "dGVzdC1lbmNyeXB0aW9uLWtleS0zMi1ieXRlcyEh", "postgres_host": "postgres", "postgres_port": 5432, "postgres_db": "lux_fiscal", "postgres_user": "lux_fiscal", "postgres_password": "postgres", } return Settings(**{**defaults, **overrides}) # type: ignore[arg-type] @pytest.mark.parametrize( "password", [ "Jvth,fqkjn2020", # запятая — реальный пароль из этого проекта "p@ss:word/with#special?chars", "простой-пароль-с-кириллицей", ], ) def test_database_url_survives_special_characters_in_password(password: str) -> None: settings = _settings(postgres_password=password) url = settings.database_url assert url.startswith("postgresql+asyncpg://") # Порт обязан остаться числом 5432 — при поломанном парсинге он # «съезжает» вместе с частью пароля или пропадает совсем. assert "@postgres:5432/lux_fiscal" in url def test_database_url_roundtrips_via_sqlalchemy_make_url() -> None: """URL должен оставаться валидным для драйвера, а не только для pydantic.""" from sqlalchemy.engine import make_url settings = _settings(postgres_password="Jvth,fqkjn2020") parsed = make_url(settings.database_url) assert parsed.password == "Jvth,fqkjn2020" assert parsed.port == 5432 assert parsed.database == "lux_fiscal"