156 lines
6.0 KiB
Rust
156 lines
6.0 KiB
Rust
use super::*;
|
|
|
|
#[test]
|
|
fn parses_media_control_state_from_launcher_file() {
|
|
assert_eq!(
|
|
parse_media_control_state("camera=1 microphone=0 audio=true 123"),
|
|
Some(MediaControlState::new(true, false, true))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
/// Keeps `parses_media_control_state_with_live_device_choices` explicit because it sits on this module contract, where hidden behavior would make regressions difficult to diagnose.
|
|
/// Inputs are the typed parameters; output is the return value or side effect.
|
|
fn parses_media_control_state_with_live_device_choices() {
|
|
let state = MediaControlState::with_devices(
|
|
true,
|
|
true,
|
|
true,
|
|
Some("Logitech BRIO".to_string()),
|
|
Some("1280x720@30".to_string()),
|
|
Some("alsa_input.usb-Neat Microphones".to_string()),
|
|
None,
|
|
);
|
|
let dir = tempfile::tempdir().expect("tempdir");
|
|
let path = dir.path().join("media.control");
|
|
write_media_control_request(&path, state.clone()).expect("write controls");
|
|
let raw = fs::read_to_string(path).expect("read controls");
|
|
assert_eq!(parse_media_control_state(&raw), Some(state));
|
|
}
|
|
|
|
#[test]
|
|
fn device_choices_resolve_inherit_auto_and_selected() {
|
|
assert_eq!(
|
|
MediaDeviceChoice::Inherit.resolve(Some("env-device")),
|
|
Some("env-device".to_string())
|
|
);
|
|
assert_eq!(MediaDeviceChoice::Auto.resolve(Some("env-device")), None);
|
|
assert_eq!(
|
|
MediaDeviceChoice::Selected("chosen".to_string()).resolve(Some("env-device")),
|
|
Some("chosen".to_string())
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn codec_and_noise_choices_resolve_inherit_and_selected_values() {
|
|
assert_eq!(
|
|
MediaCameraCodecChoice::selected(Some(" HeVc ".to_string())).resolve(Some("mjpeg")),
|
|
Some("hevc".to_string())
|
|
);
|
|
assert_eq!(
|
|
MediaCameraCodecChoice::selected(Some(" ".to_string())).resolve(Some("mjpeg")),
|
|
Some("mjpeg".to_string())
|
|
);
|
|
assert_eq!(
|
|
MediaAudioCodecChoice::Inherit.resolve(UpstreamAudioCodec::PcmS16le),
|
|
UpstreamAudioCodec::PcmS16le
|
|
);
|
|
assert_eq!(
|
|
MediaAudioCodecChoice::selected(UpstreamAudioCodec::Opus)
|
|
.resolve(UpstreamAudioCodec::PcmS16le),
|
|
UpstreamAudioCodec::Opus
|
|
);
|
|
assert!(MediaNoiseSuppressionChoice::Enabled.resolve(false));
|
|
assert!(!MediaNoiseSuppressionChoice::Disabled.resolve(true));
|
|
assert!(MediaNoiseSuppressionChoice::Inherit.resolve(true));
|
|
}
|
|
|
|
#[test]
|
|
/// Keeps `live_media_controls_refresh_after_file_changes` explicit because it sits on this module contract, where hidden behavior would make regressions difficult to diagnose.
|
|
/// Inputs are the typed parameters; output is the return value or side effect.
|
|
fn live_media_controls_refresh_after_file_changes() {
|
|
let dir = tempfile::tempdir().expect("tempdir");
|
|
let path = dir.path().join("media.control");
|
|
write_media_control_request(&path, MediaControlState::new(true, true, false))
|
|
.expect("write initial controls");
|
|
let controls = LiveMediaControls {
|
|
path: path.clone(),
|
|
inner: Arc::new(Mutex::new(LiveMediaControlsInner {
|
|
state: MediaControlState::new(false, false, false),
|
|
})),
|
|
};
|
|
assert_eq!(
|
|
controls.refresh(),
|
|
MediaControlState::new(true, true, false)
|
|
);
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(5));
|
|
write_media_control_request(&path, MediaControlState::new(false, true, true))
|
|
.expect("write updated controls");
|
|
assert_eq!(
|
|
controls.refresh(),
|
|
MediaControlState::new(false, true, true)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn from_env_default_path_fallback_is_safe() {
|
|
let controls = LiveMediaControls::from_env(MediaControlState::new(true, false, true));
|
|
let _ = controls.refresh();
|
|
}
|
|
|
|
#[test]
|
|
fn parser_tolerates_unknown_tokens_and_rejects_invalid_flags() {
|
|
assert_eq!(
|
|
parse_media_control_state("camera=on extra=ignored microphone=no audio=off"),
|
|
Some(MediaControlState::new(true, false, false))
|
|
);
|
|
assert_eq!(
|
|
parse_media_control_state("camera=maybe microphone=1 audio=1"),
|
|
None
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn parser_round_trips_codec_aliases_noise_and_encoded_choices() {
|
|
let raw = "camera=1 mic=1 speaker=0 camera_source_b64=b64:TG9naXRlY2ggQlJJTw== camera_quality=720p mic_source=auto speaker_sink=inherit webcam_transport=h265 uplink_audio_codec=pcm mic_noise_suppression=yes";
|
|
let state = parse_media_control_state(raw).expect("state");
|
|
|
|
assert_eq!(
|
|
state.camera_source.resolve(None).as_deref(),
|
|
Some("Logitech BRIO")
|
|
);
|
|
assert_eq!(state.camera_profile.resolve(None).as_deref(), Some("720p"));
|
|
assert_eq!(state.microphone_source, MediaDeviceChoice::Auto);
|
|
assert_eq!(state.audio_sink, MediaDeviceChoice::Inherit);
|
|
assert_eq!(state.camera_codec.resolve(None).as_deref(), Some("hevc"));
|
|
assert_eq!(
|
|
state.audio_codec.resolve(UpstreamAudioCodec::Opus),
|
|
UpstreamAudioCodec::PcmS16le
|
|
);
|
|
assert!(state.noise_suppression.resolve(false));
|
|
|
|
assert_eq!(parse_choice("b64:not-base64"), None);
|
|
assert_eq!(parse_camera_codec_choice("vp9"), None);
|
|
assert_eq!(parse_audio_codec_choice("flac"), None);
|
|
assert_eq!(parse_noise_suppression_choice("maybe"), None);
|
|
}
|
|
|
|
#[test]
|
|
/// Keeps `refresh_falls_back_to_all_enabled_if_lock_is_poisoned` explicit because it sits on this module contract, where hidden behavior would make regressions difficult to diagnose.
|
|
/// Inputs are the typed parameters; output is the return value or side effect.
|
|
fn refresh_falls_back_to_all_enabled_if_lock_is_poisoned() {
|
|
let controls = LiveMediaControls {
|
|
path: PathBuf::from("/definitely/not/a/real/lesavka-media.control"),
|
|
inner: Arc::new(Mutex::new(LiveMediaControlsInner {
|
|
state: MediaControlState::new(false, false, false),
|
|
})),
|
|
};
|
|
let inner = Arc::clone(&controls.inner);
|
|
let _ = std::panic::catch_unwind(move || {
|
|
let _guard = inner.lock().expect("lock");
|
|
panic!("poison media controls lock");
|
|
});
|
|
assert_eq!(controls.refresh(), MediaControlState::new(true, true, true));
|
|
}
|