"""voice.py must be import-safe even without kokoro (the 3.13 test venv has none): the DSP is pure numpy and testable; speak() degrades to None.""" import numpy as np import voice def test_dsp_functions_are_pure_numpy(): x = np.sin(np.linspace(0, 20, 24000)).astype(np.float32) up = voice._pitch_up(x, 1.16) assert up.dtype == np.float32 and len(up) < len(x) # pitch-up shortens fogged = voice._fog(x, intensity=0.28) assert np.max(np.abs(fogged)) <= 0.86 # normalized headroom def test_speak_returns_none_when_pipeline_unavailable(): # the 3.13 test venv has no kokoro -> _PIPELINE is None -> silent if voice._PIPELINE is None: assert voice.speak("the sea. i grew up near the sea.") is None def test_speak_is_guarded_against_errors(monkeypatch): # even if a pipeline exists, a synth error must degrade to None, never raise monkeypatch.setattr(voice, "_PIPELINE", object()) # a bogus pipeline assert voice.speak("anything") is None def test_clean_for_tts_strips_dashes(): assert "—" not in voice._clean_for_tts("i don't— i don't remember") assert "-" not in voice._clean_for_tts("a well-kept secret") # collapses to single spaces, trims assert voice._clean_for_tts("a — b") == "a , b"