test(lesavka): cover camera and keyboard helpers
This commit is contained in:
parent
ceb20abeba
commit
8f911da06b
@ -247,4 +247,45 @@ mod tests {
|
||||
("x265enc", Some("key-int-max"))
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(coverage)]
|
||||
#[test]
|
||||
#[serial]
|
||||
/// Coverage builds can exercise H.264 encoder branches without host GPU assumptions.
|
||||
fn coverage_h264_encoder_choice_honors_stable_test_overrides() {
|
||||
let cases = [
|
||||
("nvh264enc", ("nvh264enc", None)),
|
||||
("vulkanh264enc", ("vulkanh264enc", Some("idr-period"))),
|
||||
("vaapih264enc", ("vaapih264enc", Some("keyframe-period"))),
|
||||
("v4l2h264enc", ("v4l2h264enc", Some("idrcount"))),
|
||||
("unknown", ("x264enc", Some("key-int-max"))),
|
||||
];
|
||||
|
||||
for (override_value, expected) in cases {
|
||||
temp_env::with_var("LESAVKA_CAM_TEST_ENCODER", Some(override_value), || {
|
||||
assert_eq!(CameraCapture::choose_encoder().unwrap(), expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(coverage)]
|
||||
#[test]
|
||||
/// Coverage mode keeps software video fallback enabled for deterministic tests.
|
||||
fn coverage_software_video_fallback_is_enabled() {
|
||||
assert!(CameraCapture::software_video_fallback_allowed());
|
||||
}
|
||||
|
||||
#[cfg(coverage)]
|
||||
#[test]
|
||||
/// Coverage mode replaces the FFmpeg preview reader with an inert cancellation flag.
|
||||
fn coverage_ffmpeg_preview_tap_stub_starts_stopped() {
|
||||
let running = super::spawn_ffmpeg_raw_preview_tap(
|
||||
std::io::empty(),
|
||||
std::path::PathBuf::from("/tmp/lesavka-preview-tap.coverage"),
|
||||
1,
|
||||
1,
|
||||
);
|
||||
|
||||
assert!(!running.load(std::sync::atomic::Ordering::Acquire));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
use super::{is_paste_modifier, paste_key_available_from_env, paste_rpc_enabled};
|
||||
use super::{
|
||||
build_keyboard_report, debounce_gate, is_modifier, is_paste_modifier, keycode_to_usage,
|
||||
live_modifier_delay, modifier_only_report, paste_key_available_from_env, paste_rpc_enabled,
|
||||
read_clipboard_text, should_stage_modifier_report, update_pressed_keys,
|
||||
};
|
||||
use evdev::KeyCode;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
time::Duration,
|
||||
};
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
@ -47,3 +56,99 @@ fn paste_modifier_recognizes_ctrl_alt_only() {
|
||||
assert!(!is_paste_modifier(KeyCode::KEY_V));
|
||||
assert!(!is_paste_modifier(KeyCode::KEY_LEFTSHIFT));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_report_sorts_deduplicates_and_keeps_modifiers() {
|
||||
let report = build_keyboard_report([
|
||||
KeyCode::KEY_B,
|
||||
KeyCode::KEY_LEFTSHIFT,
|
||||
KeyCode::KEY_A,
|
||||
KeyCode::KEY_A,
|
||||
KeyCode::KEY_RIGHTCTRL,
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
report[0],
|
||||
is_modifier(KeyCode::KEY_LEFTSHIFT).unwrap() | is_modifier(KeyCode::KEY_RIGHTCTRL).unwrap()
|
||||
);
|
||||
assert_eq!(report[2], keycode_to_usage(KeyCode::KEY_A).unwrap());
|
||||
assert_eq!(report[3], keycode_to_usage(KeyCode::KEY_B).unwrap());
|
||||
assert_eq!(&report[4..], &[0, 0, 0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modifier_staging_requires_modified_non_modifier_keydown() {
|
||||
let mut report = [0; 8];
|
||||
report[0] = is_modifier(KeyCode::KEY_LEFTCTRL).unwrap();
|
||||
report[2] = keycode_to_usage(KeyCode::KEY_V).unwrap();
|
||||
|
||||
assert!(should_stage_modifier_report(KeyCode::KEY_V, 1, report));
|
||||
assert!(!should_stage_modifier_report(KeyCode::KEY_V, 0, report));
|
||||
assert!(!should_stage_modifier_report(
|
||||
KeyCode::KEY_LEFTCTRL,
|
||||
1,
|
||||
report
|
||||
));
|
||||
|
||||
let mut unmodified = report;
|
||||
unmodified[0] = 0;
|
||||
assert!(!should_stage_modifier_report(KeyCode::KEY_V, 1, unmodified));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modifier_only_report_clears_non_modifier_slots() {
|
||||
assert_eq!(
|
||||
modifier_only_report(is_modifier(KeyCode::KEY_LEFTALT).unwrap()),
|
||||
[
|
||||
is_modifier(KeyCode::KEY_LEFTALT).unwrap(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn live_modifier_delay_honors_zero_override() {
|
||||
temp_env::with_var("LESAVKA_LIVE_MODIFIER_DELAY_MS", Some("0"), || {
|
||||
assert_eq!(live_modifier_delay(), Duration::ZERO);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clipboard_reader_uses_successful_command_output() {
|
||||
temp_env::with_var(
|
||||
"LESAVKA_CLIPBOARD_CMD",
|
||||
Some("printf clipboard-data"),
|
||||
|| {
|
||||
assert_eq!(read_clipboard_text().as_deref(), Some("clipboard-data"));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debounce_gate_updates_timestamp_even_when_blocked() {
|
||||
let last = AtomicU64::new(0);
|
||||
|
||||
assert!(debounce_gate(&last, 1_000, 250));
|
||||
assert_eq!(last.load(Ordering::Relaxed), 1_000);
|
||||
assert!(!debounce_gate(&last, 1_100, 250));
|
||||
assert_eq!(last.load(Ordering::Relaxed), 1_100);
|
||||
assert!(debounce_gate(&last, 1_400, 250));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pressed_key_shadow_tracks_press_release_only() {
|
||||
let mut pressed = HashSet::new();
|
||||
|
||||
update_pressed_keys(&mut pressed, KeyCode::KEY_A, 1);
|
||||
assert!(pressed.contains(&KeyCode::KEY_A));
|
||||
update_pressed_keys(&mut pressed, KeyCode::KEY_B, -1);
|
||||
assert!(!pressed.contains(&KeyCode::KEY_B));
|
||||
update_pressed_keys(&mut pressed, KeyCode::KEY_A, 0);
|
||||
assert!(!pressed.contains(&KeyCode::KEY_A));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user