//! Include-based coverage for microphone source-name routing. //! //! Scope: include `client/src/input/microphone.rs` and cover selected-source //! routing heuristics for launcher catalog names. //! Targets: `client/src/input/microphone.rs`. //! Why: launcher-selected Pulse source names must not regress to PipeWire //! negotiation when the catalog already provides a concrete Pulse device name. #[allow(warnings)] mod microphone_source_contract { include!(env!("LESAVKA_CLIENT_MICROPHONE_SRC")); use serial_test::serial; use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::Path; use temp_env::with_var; use tempfile::tempdir; fn write_executable(dir: &Path, name: &str, body: &str) { let path = dir.join(name); fs::write(&path, body).expect("write script"); let mut perms = fs::metadata(&path).expect("metadata").permissions(); perms.set_mode(0o755); fs::set_permissions(path, perms).expect("chmod"); } fn with_fake_command(name: &str, script_body: &str, f: impl FnOnce()) { let dir = tempdir().expect("tempdir"); write_executable(dir.path(), name, script_body); let prior = std::env::var("PATH").unwrap_or_default(); let merged = if prior.is_empty() { dir.path().display().to_string() } else { format!("{}:{prior}", dir.path().display()) }; with_var("PATH", Some(merged), f); } fn with_fake_pactl(script_body: &str, f: impl FnOnce()) { with_fake_command("pactl", script_body, f); } fn with_fake_pw_dump(script_body: &str, f: impl FnOnce()) { with_fake_command("pw-dump", script_body, f); } #[test] fn pulse_source_name_heuristic_matches_launcher_catalog_names() { assert!(looks_like_pulse_source_name( "alsa_input.usb-Neat_Microphones_Bumblebee_II_USB_Microphone-00.mono-fallback" )); assert!(looks_like_pulse_source_name("bluez_input.headset")); assert!(!looks_like_pulse_source_name("PipeWire Nick Mic")); } #[test] #[serial] fn resolve_source_desc_prefers_pulse_for_pulse_catalog_names() { let pactl_script = r#"#!/usr/bin/env sh if [ "$1" = "list" ] && [ "$2" = "short" ] && [ "$3" = "sources" ]; then echo "1 alsa_input.usb-Bumblebee_II-00.mono-fallback module-alsa-card.c s16le 1ch 48000Hz RUNNING" exit 0 fi exit 0 "#; let pw_script = r#"#!/usr/bin/env sh cat <<'JSON' [ {"info":{"props":{"media.class":"Audio/Source","node.name":"alsa_input.usb-Bumblebee_II-00.mono-fallback"}}} ] JSON "#; with_fake_pactl(pactl_script, || { with_fake_pw_dump(pw_script, || { let desc = MicrophoneCapture::resolve_source_desc("alsa_input.usb-Bumblebee_II") .expect("pulse source"); assert!( desc.contains("pulsesrc device=alsa_input.usb-Bumblebee_II-00.mono-fallback"), "Pulse catalog source names should route through pulsesrc: {desc}" ); }); }); } #[test] #[cfg(coverage)] #[serial] fn default_source_desc_can_fall_back_to_pulse_when_pipewire_is_disabled() { with_var("LESAVKA_MIC_TEST_SOURCE_DESC", None::<&str>, || { with_var("LESAVKA_MIC_DISABLE_PIPEWIRE", Some("1"), || { assert_eq!( MicrophoneCapture::default_source_desc(), "pulsesrc do-timestamp=true" ); }); }); } }