from __future__ import annotations import json from web_core.auth import profile_store as store def test_save_and_load_settings_are_isolated_by_profile(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) store.save_web_settings({"symbol": "AAPL", "period": "1mo"}, profile_id="alice") store.save_web_settings({"symbol": "MSFT", "period": "3mo"}, profile_id="bob") alice = store.load_web_settings(profile_id="alice") bob = store.load_web_settings(profile_id="bob") unknown = store.load_web_settings(profile_id="carol") assert alice["symbol"] == "AAPL" assert alice["period"] == "1mo" assert bob["symbol"] == "MSFT" assert bob["period"] == "3mo" assert unknown["symbol"] == "AAPL" # fallback default def test_load_settings_migrates_legacy_flat_payload_to_default_profile(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) legacy_payload = {"symbol": "TSLA", "interval": "1h", "max_bars": 9999} legacy_path.write_text(json.dumps(legacy_payload), encoding="utf-8") loaded = store.load_web_settings(profile_id="default") assert loaded["symbol"] == "TSLA" assert loaded["interval"] == "1h" assert loaded["max_bars"] == 5000 # normalized max cap store.save_web_settings({"symbol": "TSLA"}, profile_id="default") stored = json.loads(settings_path.read_text(encoding="utf-8")) assert "profiles" in stored assert "default" in stored["profiles"] assert "settings" in stored["profiles"]["default"] assert "audit" in stored["profiles"]["default"] def test_list_web_profiles_includes_saved_profiles(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) store.save_web_settings({"symbol": "AAPL"}, profile_id="zoe") store.save_web_settings({"symbol": "AAPL"}, profile_id="alice") profile_ids = store.list_web_profiles() assert "default" in profile_ids assert "alice" in profile_ids assert "zoe" in profile_ids def test_resolve_login_profile_prefers_session_then_query() -> None: assert store.resolve_login_profile("alice", "bob") == "alice" assert store.resolve_login_profile("", "bob") == "bob" assert store.resolve_login_profile(None, None) is None def test_profile_exists_normalizes_input() -> None: profiles = {"default", "alice"} assert store.profile_exists("alice", profiles) is True assert store.profile_exists(" ", profiles) is True # normalizes to default assert store.profile_exists("bob", profiles) is False def test_profile_exists_is_case_insensitive() -> None: profiles = {"default", "Alice"} assert store.profile_exists("alice", profiles) is True assert store.find_existing_profile_id("ALICE", profiles) == "Alice" def test_is_profile_session_expired_after_timeout() -> None: now_epoch = 2000.0 assert store.is_profile_session_expired(1000.0, now_epoch, timeout_sec=900) is True assert store.is_profile_session_expired(1500.0, now_epoch, timeout_sec=900) is False assert store.is_profile_session_expired(None, now_epoch, timeout_sec=900) is False def test_is_truthy_flag_parses_common_values() -> None: assert store.is_truthy_flag("1") is True assert store.is_truthy_flag("true") is True assert store.is_truthy_flag("yes") is True assert store.is_truthy_flag("0") is False assert store.is_truthy_flag(None) is False def test_create_profile_with_pin_requires_pin_for_verification(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) store.create_profile("alice", pin="1234", now_epoch=1700000000) assert store.profile_requires_pin("alice") is True assert store.verify_profile_pin("alice", "1234") is True assert store.verify_profile_pin("alice", "9999") is False def test_audit_stamps_update_on_save_and_login(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) store.create_profile("alice", now_epoch=1700000000) store.save_web_settings({"symbol": "MSFT"}, profile_id="alice") store.mark_profile_login("alice", now_epoch=1700000010) audit = store.get_profile_audit("alice") assert audit["created_at"] == 1700000000 assert audit["last_login_at"] == 1700000010 assert audit["last_symbol"] == "MSFT" def test_load_settings_migrates_old_profiles_map_structure(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) old_payload = { "last_profile": "alice", "profiles": { "alice": {"symbol": "TSLA", "interval": "1d"}, "bob": {"symbol": "MSFT", "interval": "1h"}, }, } settings_path.write_text(json.dumps(old_payload), encoding="utf-8") alice_settings = store.load_web_settings("alice") bob_settings = store.load_web_settings("bob") assert alice_settings["symbol"] == "TSLA" assert bob_settings["symbol"] == "MSFT" store.save_web_settings({"symbol": "AAPL"}, profile_id="alice") stored = json.loads(settings_path.read_text(encoding="utf-8")) assert isinstance(stored["profiles"]["alice"], dict) assert "settings" in stored["profiles"]["alice"] def test_watchlist_round_trip_keeps_multiple_symbols(tmp_path, monkeypatch) -> None: settings_path = tmp_path / "settings.json" legacy_path = tmp_path / "legacy.json" monkeypatch.setattr(store, "SETTINGS_PATH", settings_path) monkeypatch.setattr(store, "LEGACY_SETTINGS_PATH", legacy_path) store.save_web_settings({"symbol": "AMD", "watchlist": ["AMD", "TSLA"]}, profile_id="matt") loaded = store.load_web_settings(profile_id="matt") assert loaded["watchlist"] == ["AMD", "TSLA"]