from __future__ import annotations import json from pathlib import Path import pytest from doctor_workstation import config as config_module from doctor_workstation.config import AppConfig, normalize_api_base_url @pytest.mark.parametrize( ("raw", "expected"), [ ("https://api.example.com", "https://api.example.com/adminapi"), ("https://api.example.com/", "https://api.example.com/adminapi"), ("https://api.example.com/adminapi", "https://api.example.com/adminapi"), ("http://127.0.0.1:8080/gateway", "http://127.0.0.1:8080/gateway/adminapi"), ("", ""), ], ) def test_normalize_api_base_url(raw: str, expected: str) -> None: assert normalize_api_base_url(raw) == expected @pytest.mark.parametrize( "raw", ["api.example.com", "ftp://api.example.com", "https://u:p@example.com", "https://x.test?a=1"], ) def test_normalize_api_base_url_rejects_unsafe_values(raw: str) -> None: with pytest.raises(ValueError): normalize_api_base_url(raw) def test_config_update_validates_video_mode() -> None: with pytest.raises(ValueError): AppConfig().with_updates(video_mode="unknown") def test_config_update_normalizes_ssl_boolean_strings() -> None: assert AppConfig(debug_mode=True).with_updates(verify_ssl="false").verify_ssl is False assert ( AppConfig(debug_mode=True, verify_ssl=False) .with_updates(verify_ssl="true") .verify_ssl is True ) def test_production_config_locks_online_server_and_disables_demo( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: config_dir = tmp_path / "config" config_dir.mkdir() (config_dir / "preferences.json").write_text( json.dumps( { "api_base_url": "https://stale.example.test/adminapi", "demo_mode": True, "verify_ssl": False, } ), encoding="utf-8", ) monkeypatch.setattr(config_module, "DEBUG_MODE", False) monkeypatch.setattr( config_module, "ONLINE_API_BASE_URL", "https://prod.example.test", ) monkeypatch.setenv("DOCTOR_CONFIG_DIR", str(config_dir)) monkeypatch.setenv("DOCTOR_API_BASE_URL", "https://env.example.test") monkeypatch.setenv("DOCTOR_DEMO_MODE", "true") monkeypatch.setenv("DOCTOR_VERIFY_SSL", "false") config = AppConfig.load() assert config.debug_mode is False assert config.api_base_url == "https://prod.example.test/adminapi" assert config.demo_mode is False assert config.verify_ssl is True updated = config.with_updates( api_base_url="https://changed.example.test", demo_mode=True, verify_ssl=False, ) assert updated.api_base_url == config.api_base_url assert updated.demo_mode is False assert updated.verify_ssl is True def test_debug_config_keeps_environment_server_controls( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: monkeypatch.setattr(config_module, "DEBUG_MODE", True) monkeypatch.setenv("DOCTOR_CONFIG_DIR", str(tmp_path / "config")) monkeypatch.setenv("DOCTOR_API_BASE_URL", "http://127.0.0.1:8080") monkeypatch.setenv("DOCTOR_DEMO_MODE", "true") monkeypatch.setenv("DOCTOR_VERIFY_SSL", "false") config = AppConfig.load() assert config.debug_mode is True assert config.api_base_url == "http://127.0.0.1:8080/adminapi" assert config.demo_mode is True assert config.verify_ssl is False def test_production_config_rejects_empty_online_domain( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: monkeypatch.setattr(config_module, "DEBUG_MODE", False) monkeypatch.setattr(config_module, "ONLINE_API_BASE_URL", "") monkeypatch.setenv("DOCTOR_CONFIG_DIR", str(tmp_path / "config")) with pytest.raises(ValueError, match="ONLINE_API_BASE_URL 不能为空"): AppConfig.load() def test_runtime_directories_can_be_isolated_without_replacing_user_home( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: config_dir = tmp_path / "config" log_dir = tmp_path / "logs" monkeypatch.setenv("DOCTOR_CONFIG_DIR", str(config_dir)) monkeypatch.setenv("DOCTOR_LOG_DIR", str(log_dir)) config = AppConfig() assert config.config_dir == config_dir assert config.log_dir == log_dir