From c341092207207e1a4b823c286632b079fc533fe2 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Sun, 12 Apr 2026 21:18:17 -0300 Subject: [PATCH] testing: broaden input aggregator state and classifier contracts --- testing/tests/client_inputs_contract.rs | 104 ++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/testing/tests/client_inputs_contract.rs b/testing/tests/client_inputs_contract.rs index 0ef939f..0ecb51b 100644 --- a/testing/tests/client_inputs_contract.rs +++ b/testing/tests/client_inputs_contract.rs @@ -78,6 +78,64 @@ mod inputs_contract { open_virtual_device(&mut vdev) } + fn build_touch_mouse() -> Option { + let mut keys = AttributeSet::::new(); + keys.insert(evdev::KeyCode::BTN_TOUCH); + let abs = evdev::AbsInfo::new(0, 0, 1024, 0, 0, 0); + + let mut vdev = VirtualDevice::builder() + .ok()? + .name("lesavka-input-classify-touch") + .with_keys(&keys) + .ok()? + .with_absolute_axis(&evdev::UinputAbsSetup::new( + evdev::AbsoluteAxisCode::ABS_MT_POSITION_X, + abs, + )) + .ok()? + .with_absolute_axis(&evdev::UinputAbsSetup::new( + evdev::AbsoluteAxisCode::ABS_MT_POSITION_Y, + abs, + )) + .ok()? + .build() + .ok()?; + + open_virtual_device(&mut vdev) + } + + fn build_misc_key_device() -> Option { + let mut keys = AttributeSet::::new(); + keys.insert(evdev::KeyCode::KEY_VOLUMEUP); + + let mut vdev = VirtualDevice::builder() + .ok()? + .name("lesavka-input-classify-other") + .with_keys(&keys) + .ok()? + .build() + .ok()?; + + open_virtual_device(&mut vdev) + } + + fn build_keyboard_pair(name: &str) -> Option<(VirtualDevice, evdev::Device)> { + let mut keys = AttributeSet::::new(); + keys.insert(evdev::KeyCode::KEY_A); + keys.insert(evdev::KeyCode::KEY_ENTER); + + let mut vdev = VirtualDevice::builder() + .ok()? + .name(name) + .with_keys(&keys) + .ok()? + .build() + .ok()?; + + let dev = open_virtual_device(&mut vdev)?; + Some((vdev, dev)) + } + fn new_aggregator() -> InputAggregator { let (kbd_tx, _) = tokio::sync::broadcast::channel(32); let (mou_tx, _) = tokio::sync::broadcast::channel(32); @@ -94,6 +152,14 @@ mod inputs_contract { if let Some(mouse) = build_mouse() { assert!(matches!(classify_device(&mouse), DeviceKind::Mouse)); } + + if let Some(touch) = build_touch_mouse() { + assert!(matches!(classify_device(&touch), DeviceKind::Mouse)); + } + + if let Some(other) = build_misc_key_device() { + assert!(matches!(classify_device(&other), DeviceKind::Other)); + } } #[test] @@ -123,6 +189,44 @@ mod inputs_contract { assert!(!agg.released); } + #[test] + fn toggle_grab_ignores_requests_while_kill_release_is_pending() { + let mut agg = new_aggregator(); + agg.pending_kill = true; + agg.toggle_grab(); + assert!(agg.pending_kill); + assert!(!agg.pending_release); + assert!(!agg.released); + } + + #[test] + #[serial] + fn capture_pending_keys_collects_current_keyboard_state() { + let Some((mut vdev, dev)) = build_keyboard_pair("lesavka-input-pending-keys") else { + return; + }; + + let (kbd_tx, _) = tokio::sync::broadcast::channel(16); + let (agg_kbd_tx, _) = tokio::sync::broadcast::channel(16); + let (agg_mou_tx, _) = tokio::sync::broadcast::channel(16); + let mut keyboard = KeyboardAggregator::new(dev, false, kbd_tx, None); + + vdev.emit(&[evdev::InputEvent::new( + evdev::EventType::KEY.0, + evdev::KeyCode::KEY_A.0, + 1, + )]) + .expect("emit key press"); + thread::sleep(std::time::Duration::from_millis(20)); + keyboard.process_events(); + + let mut agg = InputAggregator::new(false, agg_kbd_tx, agg_mou_tx, None); + agg.keyboards.push(keyboard); + agg.capture_pending_keys(); + + assert!(agg.pending_keys.contains(&evdev::KeyCode::KEY_A)); + } + #[tokio::test(flavor = "current_thread")] async fn run_returns_once_pending_kill_chord_is_released() { let mut agg = new_aggregator();