"""The app's state machine: actions fold correctly, and nothing else moves. `apply_action` is the only way state changes, so these tests are the contract for every control on the page. They run against the real module with the store pointed at a temp directory, so no network and no credentials are involved. """ from __future__ import annotations import importlib import os import pytest @pytest.fixture(scope="module") def app(tmp_path_factory): """The app module, booted against an empty local store.""" os.environ["ARENA_OFFLINE"] = "1" os.environ["ARENA_LOCAL_STORE"] = str(tmp_path_factory.mktemp("store")) os.environ["ARENA_LOCAL_NAV"] = "" import app as app_module app_module = importlib.reload(app_module) # Enroll the dependency-free baselines so the selection tests exercise real # registry entries rather than skipping. They need no weights or network. from src import runtime as rt for model_id in ("baseline/random-walk", "baseline/drift", "baseline/bootstrap"): rt.enroll(app_module.STORE, "baseline", model_id, enrolled_by="tests", registry=app_module.BOOT["registry"]) app_module.BOOT["registry"] = app_module.STORE.get_registry() return app_module def _state(app, **over): state = app.default_state() state.update(over) return state # -------------------------------------------------------------------------- # Action folding # -------------------------------------------------------------------------- def test_an_unknown_action_changes_nothing(app): before = _state(app) after = app.apply_action(before, "not-an-action:whatever|n1") assert after == before def test_a_malformed_payload_changes_nothing(app): before = _state(app) for raw in ("", "no-colon", "|", None): assert app.apply_action(before, raw) == before def test_asset_and_timeframe_are_validated(app): state = _state(app) assert app.apply_action(state, "asset:BTC-USD|n1")["asset"] == "BTC-USD" # Off the known list: ignored, not stored. assert app.apply_action(state, "asset:DOGE-USD|n2")["asset"] == state["asset"] assert app.apply_action(state, "tf:1d|n3")["tf"] == "1d" assert app.apply_action(state, "tf:7y|n4")["tf"] == state["tf"] def test_changing_the_timeframe_resets_the_horizon_to_its_default(app): state = app.apply_action(_state(app), "hz:96|n1") assert state["horizon"] == 96 state = app.apply_action(state, "tf:1d|n2") assert state["horizon"] == app.config.DEFAULT_HORIZON["1d"] def test_an_out_of_range_horizon_is_rejected(app): state = _state(app, tf="1d") assert app.apply_action(state, "hz:100000|n1")["horizon"] == state["horizon"] assert app.apply_action(state, "hz:-4|n2")["horizon"] == state["horizon"] assert app.apply_action(state, "hz:notanumber|n3")["horizon"] == state["horizon"] def test_the_same_nonce_twice_folds_once(app): """Two delivery paths mean one click can arrive twice.""" state = _state(app, gear=False) once = app.apply_action(state, "gear:toggle|abc") twice = app.apply_action(once, "gear:toggle|abc") assert once["gear"] is True assert twice["gear"] is True, "the duplicate delivery toggled it back" def test_playground_holds_one_model_and_matchup_holds_up_to_three(app): slugs = sorted(app.BOOT["registry"].get("models", {})) if len(slugs) < 2: pytest.skip("needs at least two enrolled models") state = _state(app, mode="matchup", selected=[slugs[0]]) for slug in slugs[1:5]: state = app.apply_action(state, f"pick:{slug}|n{slug}") assert len(state["selected"]) <= app.view.MAX_MATCHUP state = app.apply_action(state, "mode:playground|nz") assert len(state["selected"]) == 1 def test_deselecting_the_last_model_is_refused(app): slugs = sorted(app.BOOT["registry"].get("models", {})) if not slugs: pytest.skip("needs an enrolled model") state = _state(app, mode="matchup", selected=[slugs[0]]) state = app.apply_action(state, f"pick:{slugs[0]}|n1") assert state["selected"] == [slugs[0]], "left the UI with no model selected" def test_picking_an_unenrolled_model_is_ignored(app): state = _state(app) after = app.apply_action(state, "pick:some-model-nobody-enrolled|n1") assert after["selected"] == state["selected"] def test_standings_class_filter_is_validated(app): state = _state(app) assert app.apply_action(state, "cls:Crypto|n1")["cls"] == "Crypto" assert app.apply_action(state, "cls:Nonsense|n2")["cls"] == state["cls"] def test_the_enrollment_box_is_length_capped(app): state = app.apply_action(_state(app), "hfid:" + "x" * 5000 + "|n1") assert len(state["hfid"]) <= 120 # -------------------------------------------------------------------------- # Rendering # -------------------------------------------------------------------------- def test_the_page_renders_for_every_mode(app): for mode in ("playground", "matchup"): html = app.render(_state(app, mode=mode)) assert "Forecast Arena" in html assert len(html) > 5000 def test_the_page_renders_with_no_models_enrolled(app, monkeypatch): """An empty registry is the first-boot state, not an error.""" monkeypatch.setitem(app.BOOT, "registry", {"models": {}}) html = app.render(_state(app, selected=[])) assert "Forecast Arena" in html def test_the_disclaimer_is_always_on_the_page(app): """A forecast must never be presented as advice, on any state of the page.""" html = app.render(_state(app)).lower() assert "nothing here is financial advice" in html # Twice: once beside the method note, once in the footer. assert html.count("financial advice") >= 2 def test_the_methodology_promises_are_on_the_page(app): html = app.render(_state(app)) for promise in ("frozen at issue", "backfilled entries", "resolved forecasts only"): assert promise in html.lower() def test_on_action_returns_html_and_state(app): html, state = app.on_action("cls:Crypto|n1", app.default_state()) assert isinstance(html, str) and len(html) > 1000 assert state["cls"] == "Crypto" # -------------------------------------------------------------------------- # Deep links # -------------------------------------------------------------------------- def test_a_model_deep_link_preselects_and_badges(app): slugs = sorted(app.BOOT["registry"].get("models", {})) if not slugs: pytest.skip("needs an enrolled model") state = app.apply_action(_state(app), f"deeplink:{slugs[0]}|d1") assert state["selected"] == [slugs[0]] assert state["deep_linked"] is True assert state["mode"] == "playground" assert "DEEP LINK" in app.render(state) def test_a_stale_deep_link_opens_the_arena_rather_than_failing(app): before = _state(app) after = app.apply_action(before, "deeplink:a-model-that-was-retired|d2") assert after["selected"] == before["selected"] assert not after.get("deep_linked") assert "Forecast Arena" in app.render(after) def test_a_deep_link_cannot_smuggle_a_path(app): for hostile in ("../../etc/passwd", "a|b", "