"""Shared fixtures and the deployed-Space plumbing for the whole Phase 1 suite.""" from __future__ import annotations import json import wave from pathlib import Path import pytest FIXTURES = Path(__file__).parent / "fixtures" def pytest_addoption(parser): parser.addoption( "--space-url", action="store", default=None, help="Base URL of the deployed Space, e.g. https://wolfdavid-japanese-learning-avatar.hf.space", ) def pytest_collection_modifyitems(config, items): if config.getoption("--space-url"): return skip = pytest.mark.skip(reason="needs --space-url (deployed Space)") for item in items: if "deployed" in item.keywords: item.add_marker(skip) @pytest.fixture(scope="session") def space_url(request) -> str: url = request.config.getoption("--space-url") if not url: pytest.skip("needs --space-url") return url.rstrip("/") @pytest.fixture(scope="session") def fixtures_dir() -> Path: return FIXTURES @pytest.fixture(scope="session") def silence_wav() -> Path: return FIXTURES / "silence_30s.wav" @pytest.fixture(scope="session") def cafe_noise_wav() -> Path: return FIXTURES / "cafe_noise_30s.wav" @pytest.fixture(scope="session") def speech_wav() -> Path: """Japanese speech fixture. Produced by plan 01-04 from real VOICEVOX synthesis.""" p = FIXTURES / "speech_ja.wav" if not p.exists(): pytest.skip("speech_ja.wav not generated yet (plan 01-04)") return p @pytest.fixture(scope="session") def synth_meta() -> dict: """Recorded synthesis metadata written by plan 01-04. Shape: {"cases": {"": {"query": ".json", "wav": ".wav", "text": "...", "speed_scale": 1.0, "duration_seconds": , "mora_count": , "vowel_symbols": [...]}}} """ p = FIXTURES / "synth_meta.json" if not p.exists(): pytest.skip("synth_meta.json not generated yet (plan 01-04)") return json.loads(p.read_text(encoding="utf-8")) def wav_duration_seconds(path: Path) -> float: with wave.open(str(path), "rb") as w: return w.getnframes() / float(w.getframerate())