"""Launch-time CLI override tests — v4.10.0 regression guard. The GUI entry (``launch_gui``) runs BEFORE the async environment probe (500ms QTimer), so ``window.env`` is ``None`` at launch time. Writing CLI overrides straight onto ``env.av1an_flags`` crashed with ``AttributeError: 'NoneType' object has no attribute 'av1an_flags'`` on every GUI launch through ``main()`` — both entries (``python open-transcode.py`` and ``python -m opentranscode``). The fix: overrides land in the window's pending store (``_set_cli_flag`` / ``_clear_cli_flag``) and ``_probe_and_init`` flushes them into the live ``av1an_flags`` the moment the probe finishes. These tests pin the pending/flush semantics hermetically (no QApplication, no probe): the window is built via ``__new__`` and the env is a stub. """ from __future__ import annotations class _StubEnv: def __init__(self, flags: dict | None = None): self.av1an_flags = dict(flags or {}) def _bare_master(module): master = module.OpenCodecMaster.__new__(module.OpenCodecMaster) master._pending_av1an_flags = {} return master class TestPendingFlagStore: def test_launch_before_probe_does_not_crash(self, opentranscode_module): # The original failure mode: writing a flag with env unset. # The pending store accepts it with env=None in sight. master = _bare_master(opentranscode_module) master.env = None master._set_cli_flag("engine", "cpu") # raised before the fix assert master._pending_av1an_flags["engine"] == "cpu" def test_flush_applies_pending_into_live_flags(self, opentranscode_module): master = _bare_master(opentranscode_module) master.env = _StubEnv({"concat_method": "ffmpeg"}) master._set_cli_flag("engine", "cpu") master._set_cli_flag("max_workers", 3) master._set_cli_flag("use_av1an", False) master._flush_cli_flags() assert master.env.av1an_flags["engine"] == "cpu" assert master.env.av1an_flags["max_workers"] == 3 assert master.env.av1an_flags["use_av1an"] is False def test_falsy_values_survive_the_flush(self, opentranscode_module): # The delete sentinel is an identity check — False, 0 and "" # are legitimate flag values and must never be swallowed. master = _bare_master(opentranscode_module) master.env = _StubEnv() master._set_cli_flag("use_av1an", False) master._set_cli_flag("max_workers", 0) master._set_cli_flag("some_str", "") master._flush_cli_flags() flags = master.env.av1an_flags assert flags["use_av1an"] is False assert flags["max_workers"] == 0 assert flags["some_str"] == "" def test_clear_removes_probe_set_flag(self, opentranscode_module): # --chunk-method auto must delete the probe's chunk_method_override # (set when no VapourSynth source plugins are installed). master = _bare_master(opentranscode_module) master.env = _StubEnv({"chunk_method_override": "select", "concat_method": "ffmpeg"}) master._clear_cli_flag("chunk_method_override") master._flush_cli_flags() assert "chunk_method_override" not in master.env.av1an_flags assert master.env.av1an_flags["concat_method"] == "ffmpeg" def test_clear_is_a_noop_when_key_absent(self, opentranscode_module): master = _bare_master(opentranscode_module) master.env = _StubEnv() master._clear_cli_flag("chunk_method_override") master._flush_cli_flags() assert master.env.av1an_flags == {} def test_last_write_wins_and_flush_drains(self, opentranscode_module): master = _bare_master(opentranscode_module) master.env = _StubEnv() master._set_cli_flag("engine", "cpu") master._set_cli_flag("engine", "hybrid") master._flush_cli_flags() assert master.env.av1an_flags["engine"] == "hybrid" assert master._pending_av1an_flags == {} # A second flush with no new pending writes changes nothing. master._flush_cli_flags() assert master.env.av1an_flags["engine"] == "hybrid"