"""Shared pytest fixtures for backend tests. All external LLM/ASR calls must be mocked. Use tmp_path for ChromaDB instances. """ import pytest from unittest.mock import AsyncMock, MagicMock @pytest.fixture def mock_llm_client(monkeypatch): """Mock LLM client to avoid hitting live APIs.""" class _Mock: async def complete(self, prompt: str, temperature: float = 0.7) -> str: # type: ignore return "{\"choices\": [{\"message\": {\"content\": \"mock response\"}}]}" return _Mock() @pytest.fixture def mock_asr_client(monkeypatch): """Mock ASR client to avoid hitting live APIs.""" class _Mock: async def transcribe(self, audio_bytes): # type: ignore return "" return _Mock() @pytest.fixture def chroma_test_dir(tmp_path): """Provide a temporary directory for isolated ChromaDB instances.""" return tmp_path / "chroma_test" @pytest.fixture def mock_prompt_service(): """Mock PromptService for tests that don't need real DB.""" class _MockPromptService: def __init__(self): self._template = "Test template: {question}" def get_active_profile_name(self) -> str: return "A" def get_prompt_template(self, step: str) -> str: return self._template def list_profiles(self) -> list[dict]: return [ {"name": "A", "is_active": True}, {"name": "B", "is_active": False}, {"name": "C", "is_active": False}, ] def activate_profile(self, name: str) -> None: pass def get_profile_prompts(self, name: str) -> dict: return {"decompose": self._template, "filter": self._template, "generate": self._template} def update_prompt(self, name: str, step: str, template: str) -> None: pass def update_all_prompts(self, name: str, prompts: dict[str, str]) -> None: pass def reset_to_defaults(self, name: str, step: str | None = None) -> None: pass return _MockPromptService()