OpenTranscode/tests/test_launch_env_pending.py

95 lines
4.1 KiB
Python

"""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"