| """Unit tests for dukaan.audio_cache — the per-message TTS cache. |
| |
| session.speak is monkeypatched so these run CPU-only with no model. |
| """ |
| import os |
|
|
| import numpy as np |
| import soundfile as sf |
|
|
| from dukaan import audio_cache |
|
|
|
|
| def _fake_speak(text): |
| |
| return (24000, np.full(1200, 0.01, dtype=np.float32)) |
|
|
|
|
| def test_ensure_ready_writes_a_playable_wav(monkeypatch): |
| monkeypatch.setattr(audio_cache.session, "speak", _fake_speak) |
| path = audio_cache.ensure_ready("mid-A", "Namaste bhai", timeout=5) |
| assert path and os.path.exists(path) |
| wav, sr = sf.read(path, dtype="float32") |
| assert sr == 24000 and wav.size > 1 |
| assert audio_cache.get("mid-A")["status"] == "ready" |
|
|
|
|
| def test_ensure_ready_is_idempotent_same_path(monkeypatch): |
| monkeypatch.setattr(audio_cache.session, "speak", _fake_speak) |
| p1 = audio_cache.ensure_ready("mid-B", "x", timeout=5) |
| p2 = audio_cache.ensure_ready("mid-B", "x", timeout=5) |
| assert p1 == p2 |
|
|
|
|
| def test_failure_returns_silence_path_not_none(monkeypatch): |
| monkeypatch.setattr(audio_cache.session, "speak", lambda t: None) |
| path = audio_cache.ensure_ready("mid-C", "x", timeout=5) |
| assert path and os.path.exists(path) |
|
|
|
|
| def test_prepare_async_then_ready(monkeypatch): |
| monkeypatch.setattr(audio_cache.session, "speak", _fake_speak) |
| audio_cache.prepare_async("mid-D", "x") |
| path = audio_cache.ensure_ready("mid-D", "x", timeout=5) |
| assert path and os.path.exists(path) |
|
|
|
|
| def test_eviction_caps_entries(monkeypatch): |
| monkeypatch.setattr(audio_cache.session, "speak", _fake_speak) |
| monkeypatch.setattr(audio_cache, "_MAX", 3) |
| for i in range(6): |
| audio_cache.ensure_ready(f"e{i}", "x", timeout=5) |
| assert len(audio_cache._CACHE) <= 3 |
|
|