lesavka/tests/unit/common/hid/common_hid_edge_cases_unit.rs

67 lines
2.2 KiB
Rust

// Extra pure HID encoder edge coverage.
//
// Scope: verify balanced modifier/key release sequences without touching
// evdev, uinput, or gadget device nodes.
// Targets: `common/src/hid.rs`.
// Why: a leaked shift/modifier or missing release is exactly how a safe
// synthetic input path turns into foreground typing like `aAaasa`.
use lesavka_common::hid::{KeyboardHidReport, append_char_reports, char_to_usage};
fn reports_for(text: &str) -> Vec<KeyboardHidReport> {
let mut reports = Vec::new();
for ch in text.chars() {
assert!(append_char_reports(&mut reports, ch), "unsupported {ch:?}");
}
reports
}
#[test]
fn shifted_character_releases_modifier_before_following_unshifted_character() {
let reports = reports_for("Aa");
assert_eq!(reports.len(), 6);
assert_eq!(reports[0], [0x02, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(reports[1], [0x02, 0, 0x04, 0, 0, 0, 0, 0]);
assert_eq!(reports[2], [0x02, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(reports[3], [0; 8]);
assert_eq!(reports[4], [0, 0, 0x04, 0, 0, 0, 0, 0]);
assert_eq!(reports[5], [0; 8]);
}
#[test]
fn whitespace_characters_emit_press_release_pairs_without_sticky_keys() {
let reports = reports_for("\n\r\t ");
let expected_usages = [0x28, 0x28, 0x2B, 0x2C];
assert_eq!(reports.len(), expected_usages.len() * 2);
for (chunk, usage) in reports.chunks_exact(2).zip(expected_usages) {
assert_eq!(chunk[0], [0, 0, usage, 0, 0, 0, 0, 0]);
assert_eq!(chunk[1], [0; 8]);
}
}
#[test]
fn shifted_symbols_are_balanced_modifier_key_release_sequences() {
for ch in [
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '{', '}', '|', ':', '"', '~',
'<', '>', '?',
] {
let mut reports = Vec::new();
let (usage, modifiers) = char_to_usage(ch).expect("supported shifted symbol");
assert_eq!(modifiers, 0x02, "{ch:?} should require shift");
assert!(append_char_reports(&mut reports, ch));
assert_eq!(
reports,
vec![
[0x02, 0, 0, 0, 0, 0, 0, 0],
[0x02, 0, usage, 0, 0, 0, 0, 0],
[0x02, 0, 0, 0, 0, 0, 0, 0],
[0; 8],
]
);
}
}