"""Windows VC++ runtime detection for the native voice wheels.""" import subprocess import pytest import tools.transcription_tools as tt import tools.wake_word as ww from tools import windows_native_runtime as wnr _NATIVE_LOAD_ERROR = wnr.native_load_error @pytest.fixture(autouse=True) def _clear_probe_cache(): _NATIVE_LOAD_ERROR.cache_clear() yield _NATIVE_LOAD_ERROR.cache_clear() def _fake_run(returncode, stderr, calls=None): def run(cmd, **kwargs): if calls is not None: calls.append((cmd, kwargs)) return subprocess.CompletedProcess(cmd, returncode, stdout="", stderr=stderr) return run def test_non_windows_never_probes(monkeypatch): monkeypatch.setattr(wnr.sys, "platform", "linux") monkeypatch.setattr(wnr.subprocess, "run", pytest.fail) assert _NATIVE_LOAD_ERROR("onnxruntime") is None @pytest.mark.parametrize( "stderr", [ "ImportError: DLL load failed while importing onnxruntime_pybind11_state: The specified module could not be found.", "ImportError: DLL load failed while importing onnxruntime_pybind11_state: Belirtilen modül bulunamadı.", "FileNotFoundError: Could not find module 'C:\\venv\\ctranslate2\\ctranslate2.dll' (or one of its dependencies).", ], ) def test_dll_load_failure_is_reported(monkeypatch, stderr): calls = [] monkeypatch.setattr(wnr.sys, "platform", "win32") monkeypatch.setattr(wnr.subprocess, "run", _fake_run(1, "Traceback (most recent call last):\n" + stderr, calls)) assert _NATIVE_LOAD_ERROR("onnxruntime") == stderr assert calls[0][0][1:] == ["-c", "import onnxruntime"] assert calls[0][1]["timeout"] > 0 def test_missing_package_is_not_a_runtime_failure(monkeypatch): monkeypatch.setattr(wnr.sys, "platform", "win32") monkeypatch.setattr( wnr.subprocess, "run", _fake_run(1, "ModuleNotFoundError: No module named 'onnxruntime'") ) assert _NATIVE_LOAD_ERROR("onnxruntime") is None def test_probe_result_is_cached_per_process(monkeypatch): calls = [] monkeypatch.setattr(wnr.sys, "platform", "win32") monkeypatch.setattr(wnr.subprocess, "run", _fake_run(0, "", calls)) assert _NATIVE_LOAD_ERROR("ctranslate2") is None assert _NATIVE_LOAD_ERROR("ctranslate2") is None assert len(calls) == 1 def test_inconclusive_probe_does_not_block(monkeypatch): def timeout(cmd, **kwargs): raise subprocess.TimeoutExpired(cmd, kwargs["timeout"]) monkeypatch.setattr(wnr.sys, "platform", "win32") monkeypatch.setattr(wnr.subprocess, "run", timeout) assert _NATIVE_LOAD_ERROR("onnxruntime") is None def test_module_name_is_validated(monkeypatch): monkeypatch.setattr(wnr.sys, "platform", "win32") with pytest.raises(ValueError): _NATIVE_LOAD_ERROR("os; import shutil") def test_wake_requirements_report_missing_vc_runtime(monkeypatch): monkeypatch.setattr(ww, "_stt_ready", lambda: True) monkeypatch.setattr(ww, "_tts_ready", lambda: True) monkeypatch.setattr(ww, "_audio_available", lambda: True) monkeypatch.setattr(ww, "_local_input_device_ready", lambda: True) monkeypatch.setattr("tools.lazy_deps.is_available", lambda f: True) monkeypatch.setattr("tools.lazy_deps._allow_lazy_installs", lambda: True) monkeypatch.setattr(ww, "_native_runtime_error", lambda module: "ImportError: DLL load failed") reqs = ww.check_wake_word_requirements({"provider": "openwakeword", "capture": "local"}) assert reqs["available"] is False assert reqs["native_runtime_error"] == "ImportError: DLL load failed" assert "msvcp140.dll" in reqs["hint"] def test_wake_requirements_unaffected_when_runtime_loads(monkeypatch): monkeypatch.setattr(ww, "_stt_ready", lambda: True) monkeypatch.setattr(ww, "_tts_ready", lambda: True) monkeypatch.setattr(ww, "_audio_available", lambda: True) monkeypatch.setattr(ww, "_local_input_device_ready", lambda: True) monkeypatch.setattr("tools.lazy_deps.is_available", lambda f: True) monkeypatch.setattr(ww, "_native_runtime_error", lambda module: None) reqs = ww.check_wake_word_requirements({"provider": "openwakeword", "capture": "local"}) assert reqs["available"] is True assert reqs["native_runtime_error"] is None def test_local_transcription_reports_missing_vc_runtime(monkeypatch, tmp_path): monkeypatch.setattr(tt, "_HAS_FASTER_WHISPER", True) monkeypatch.setattr(wnr, "native_load_error", lambda module: "ImportError: DLL load failed") monkeypatch.setattr(tt, "_load_stt_config", pytest.fail) result = tt._transcribe_local(str(tmp_path / "a.wav"), "base") assert result["success"] is False assert "msvcp140.dll" in result["error"]