Files
unshackle/tests/core/test_dovi_info_frame.py
T

91 lines
2.9 KiB
Python

"""Unit tests for dovi.info_frame, which parses one frame of RPU metadata out of
`dovi_tool info` output. The tests never run dovi_tool; they mock subprocess.run."""
from __future__ import annotations
import subprocess
from pathlib import Path
from typing import Any
import pytest
from unshackle.core.utils import dovi
pytestmark = pytest.mark.unit
RPU_JSON = (
"Parsing RPU file...\n"
'{"vdr_dm_data": {"cmv29_metadata": {"ext_metadata_blocks": '
'[{"Level6": {"max_content_light_level": 588}}]}}}'
)
class FakeCompleted:
def __init__(self, returncode: int, stdout: str = "", stderr: str = "") -> None:
self.returncode = returncode
self.stdout = stdout
self.stderr = stderr
@pytest.fixture(autouse=True)
def fake_tool(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(dovi.binaries, "DoviTool", Path("dovi_tool"))
monkeypatch.setattr(dovi, "log_tool_run", lambda *a, **k: None)
def patch_run(monkeypatch: pytest.MonkeyPatch, result: FakeCompleted) -> list[list[str]]:
calls: list[list[str]] = []
def fake_run(args: list[str], **kwargs: Any) -> FakeCompleted:
calls.append(args)
return result
monkeypatch.setattr(subprocess, "run", fake_run)
return calls
def test_parses_json_after_a_preamble(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
calls = patch_run(monkeypatch, FakeCompleted(0, RPU_JSON))
info = dovi.info_frame(tmp_path / "RPU.bin")
blocks = info["vdr_dm_data"]["cmv29_metadata"]["ext_metadata_blocks"]
assert blocks[0]["Level6"]["max_content_light_level"] == 588
assert calls[0][1:] == ["info", "-i", str(tmp_path / "RPU.bin"), "-f", "0"]
def test_frame_number_is_passed_through(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
calls = patch_run(monkeypatch, FakeCompleted(0, RPU_JSON))
dovi.info_frame(tmp_path / "RPU.bin", frame=12)
assert calls[0][-2:] == ["-f", "12"]
def test_non_zero_return_code_raises(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
patch_run(monkeypatch, FakeCompleted(1, "", "boom"))
with pytest.raises(RuntimeError, match="dovi_tool info failed"):
dovi.info_frame(tmp_path / "RPU.bin")
def test_stdout_without_json_raises(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
patch_run(monkeypatch, FakeCompleted(0, "Parsing RPU file...\nno json here\n"))
with pytest.raises(RuntimeError, match="no JSON"):
dovi.info_frame(tmp_path / "RPU.bin")
def test_broken_json_raises(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
patch_run(monkeypatch, FakeCompleted(0, "Parsing RPU file...\n{not: valid}"))
with pytest.raises(RuntimeError, match="invalid JSON"):
dovi.info_frame(tmp_path / "RPU.bin")
def test_missing_binary_raises(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
monkeypatch.setattr(dovi.binaries, "DoviTool", None)
with pytest.raises(EnvironmentError):
dovi.info_frame(tmp_path / "RPU.bin")