Desktop Phase 1: add 77 tests to evdevd, udev-shim, firmware-loader
Phase 1 desktop substrate test coverage for the three runtime services that must be runtime-trusted before compositor work begins: - evdevd device.rs: 44 tests (input device constructors, capability bitmaps, key/led state tracking, abs_info defaults/overrides, bitmap_from_codes edge cases) - udev-shim device_db.rs: 13 tests (DeviceInfo construction, subsystem naming, id_path formatting, input kind detection, property formatting for GPU/keyboard/mouse, device_info/uevent output, PCI fallback) - firmware-loader scheme.rs: 20 tests (openat validation, read offsets, fstat/fsize, EROFS enforcement, mmap_prep bounds, mmap/munmap/on_close deferred cleanup lifecycle) Total: 65 evdevd, 15 udev-shim, 24 firmware-loader — all passing.
This commit is contained in:
@@ -230,3 +230,458 @@ fn bitmap_from_codes(codes: &[u16]) -> Vec<u8> {
|
||||
}
|
||||
bitmap
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::types::{
|
||||
ABS_MT_POSITION_X, ABS_MT_POSITION_Y, ABS_MT_SLOT, ABS_MT_TOUCH_MAJOR, ABS_MT_TRACKING_ID,
|
||||
ABS_PRESSURE, ABS_X, ABS_Y, BTN_LEFT, BTN_TOUCH, BUS_VIRTUAL, EV_ABS, EV_KEY, EV_LED,
|
||||
EV_MSC, EV_REL, EV_REP, EV_SYN, INPUT_PROP_POINTER, KEY_A, LED_CAPSL, LED_NUML,
|
||||
LED_SCROLLL, MSC_SCAN, REL_HWHEEL, REL_WHEEL, REL_X, REL_Y,
|
||||
};
|
||||
|
||||
// Helper: check that a bitmap has the expected bit set for a given code.
|
||||
fn assert_bit_set(bitmap: &[u8], code: u16) {
|
||||
let byte = (code / 8) as usize;
|
||||
let bit = code % 8;
|
||||
assert!(
|
||||
byte < bitmap.len(),
|
||||
"code {} (byte index {}) out of bitmap range (len {})",
|
||||
code,
|
||||
byte,
|
||||
bitmap.len()
|
||||
);
|
||||
assert_eq!(
|
||||
bitmap[byte] & (1 << bit),
|
||||
1 << bit,
|
||||
"bit {} in byte {} not set for code {}",
|
||||
bit,
|
||||
byte,
|
||||
code
|
||||
);
|
||||
}
|
||||
|
||||
fn assert_bit_clear(bitmap: &[u8], code: u16) {
|
||||
let byte = (code / 8) as usize;
|
||||
let bit = code % 8;
|
||||
if byte < bitmap.len() {
|
||||
assert_eq!(
|
||||
bitmap[byte] & (1 << bit),
|
||||
0,
|
||||
"bit {} in byte {} unexpectedly set for code {}",
|
||||
bit,
|
||||
byte,
|
||||
code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 1. InputDevice::new_keyboard
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn new_keyboard_has_correct_kind() {
|
||||
let dev = InputDevice::new_keyboard(3);
|
||||
assert_eq!(dev.kind, DeviceKind::Keyboard);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_keyboard_name_format() {
|
||||
let dev = InputDevice::new_keyboard(7);
|
||||
assert_eq!(dev.name, "Redox Keyboard 7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_keyboard_input_id_bus_virtual() {
|
||||
let dev = InputDevice::new_keyboard(1);
|
||||
assert_eq!(dev.input_id.bustype, BUS_VIRTUAL);
|
||||
assert_eq!(dev.input_id.vendor, 0);
|
||||
assert_eq!(dev.input_id.product, 1);
|
||||
assert_eq!(dev.input_id.version, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_keyboard_key_and_led_state_zeroed() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
assert!(dev.key_state.iter().all(|&b| b == 0));
|
||||
assert!(dev.led_state.iter().all(|&b| b == 0));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 2. InputDevice::new_mouse
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn new_mouse_has_correct_kind() {
|
||||
let dev = InputDevice::new_mouse(2);
|
||||
assert_eq!(dev.kind, DeviceKind::Mouse);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_mouse_name_format() {
|
||||
let dev = InputDevice::new_mouse(5);
|
||||
assert_eq!(dev.name, "Redox Mouse 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_mouse_product_id_offset() {
|
||||
let dev = InputDevice::new_mouse(3);
|
||||
assert_eq!(dev.input_id.product, 3 + 0x10);
|
||||
assert_eq!(dev.input_id.bustype, BUS_VIRTUAL);
|
||||
assert_eq!(dev.input_id.version, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_mouse_key_and_led_state_zeroed() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
assert!(dev.key_state.iter().all(|&b| b == 0));
|
||||
assert!(dev.led_state.iter().all(|&b| b == 0));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 3. InputDevice::new_touchpad
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn new_touchpad_has_correct_kind() {
|
||||
let dev = InputDevice::new_touchpad(1);
|
||||
assert_eq!(dev.kind, DeviceKind::Touchpad);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_touchpad_name_format() {
|
||||
let dev = InputDevice::new_touchpad(4);
|
||||
assert_eq!(dev.name, "Redox Touchpad 4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_touchpad_product_id_offset() {
|
||||
let dev = InputDevice::new_touchpad(2);
|
||||
assert_eq!(dev.input_id.product, 2 + 0x20);
|
||||
assert_eq!(dev.input_id.bustype, BUS_VIRTUAL);
|
||||
assert_eq!(dev.input_id.version, 1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 4. supported_event_types
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn keyboard_event_types() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
let bm = dev.supported_event_types();
|
||||
assert_bit_set(&bm, EV_SYN);
|
||||
assert_bit_set(&bm, EV_KEY);
|
||||
assert_bit_set(&bm, EV_MSC);
|
||||
assert_bit_set(&bm, EV_LED);
|
||||
assert_bit_set(&bm, EV_REP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mouse_event_types() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
let bm = dev.supported_event_types();
|
||||
assert_bit_set(&bm, EV_SYN);
|
||||
assert_bit_set(&bm, EV_KEY);
|
||||
assert_bit_set(&bm, EV_REL);
|
||||
// No EV_ABS for mouse
|
||||
assert_bit_clear(&bm, EV_ABS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_event_types() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let bm = dev.supported_event_types();
|
||||
assert_bit_set(&bm, EV_SYN);
|
||||
assert_bit_set(&bm, EV_KEY);
|
||||
assert_bit_set(&bm, EV_ABS);
|
||||
// No EV_REL for touchpad
|
||||
assert_bit_clear(&bm, EV_REL);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 5. supported_keys
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn keyboard_has_key_a() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
let bm = dev.supported_keys();
|
||||
assert_bit_set(&bm, KEY_A);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mouse_has_btn_left() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
let bm = dev.supported_keys();
|
||||
assert_bit_set(&bm, BTN_LEFT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_has_btn_touch() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let bm = dev.supported_keys();
|
||||
assert_bit_set(&bm, BTN_TOUCH);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 6. supported_rel
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn mouse_rel_axes() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
let bm = dev.supported_rel();
|
||||
assert_bit_set(&bm, REL_X);
|
||||
assert_bit_set(&bm, REL_Y);
|
||||
assert_bit_set(&bm, REL_WHEEL);
|
||||
assert_bit_set(&bm, REL_HWHEEL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_rel_empty() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
assert!(dev.supported_rel().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_rel_empty() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
assert!(dev.supported_rel().is_empty());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 7. supported_abs
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn touchpad_abs_axes() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let bm = dev.supported_abs();
|
||||
assert_bit_set(&bm, ABS_X);
|
||||
assert_bit_set(&bm, ABS_Y);
|
||||
assert_bit_set(&bm, ABS_PRESSURE);
|
||||
assert_bit_set(&bm, ABS_MT_SLOT);
|
||||
assert_bit_set(&bm, ABS_MT_TOUCH_MAJOR);
|
||||
assert_bit_set(&bm, ABS_MT_POSITION_X);
|
||||
assert_bit_set(&bm, ABS_MT_POSITION_Y);
|
||||
assert_bit_set(&bm, ABS_MT_TRACKING_ID);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_abs_empty() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
assert!(dev.supported_abs().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mouse_abs_empty() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
assert!(dev.supported_abs().is_empty());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 8. supported_msc
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn keyboard_msc_has_scan() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
let bm = dev.supported_msc();
|
||||
assert_bit_set(&bm, MSC_SCAN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mouse_msc_empty() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
assert!(dev.supported_msc().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_msc_empty() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
assert!(dev.supported_msc().is_empty());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 9. supported_leds
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn keyboard_leds() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
let bm = dev.supported_leds();
|
||||
assert_bit_set(&bm, LED_NUML);
|
||||
assert_bit_set(&bm, LED_CAPSL);
|
||||
assert_bit_set(&bm, LED_SCROLLL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mouse_leds_empty() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
assert!(dev.supported_leds().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_leds_empty() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
assert!(dev.supported_leds().is_empty());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 10. supported_props
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn mouse_has_pointer_prop() {
|
||||
let dev = InputDevice::new_mouse(0);
|
||||
let bm = dev.supported_props();
|
||||
assert_bit_set(&bm, INPUT_PROP_POINTER);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_has_pointer_prop() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let bm = dev.supported_props();
|
||||
assert_bit_set(&bm, INPUT_PROP_POINTER);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyboard_props_empty() {
|
||||
let dev = InputDevice::new_keyboard(0);
|
||||
assert!(dev.supported_props().is_empty());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 11. update_key_state
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn update_key_state_press_sets_bit() {
|
||||
let mut dev = InputDevice::new_keyboard(0);
|
||||
// KEY_A = 30 → byte 3, bit 6
|
||||
dev.update_key_state(KEY_A, true);
|
||||
let byte = (KEY_A / 8) as usize;
|
||||
let bit = KEY_A % 8;
|
||||
assert_eq!(dev.key_state[byte] & (1 << bit), 1 << bit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_key_state_release_clears_bit() {
|
||||
let mut dev = InputDevice::new_keyboard(0);
|
||||
dev.update_key_state(KEY_A, true);
|
||||
assert_bit_set(&dev.key_state, KEY_A);
|
||||
dev.update_key_state(KEY_A, false);
|
||||
assert_bit_clear(&dev.key_state, KEY_A);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 12. update_led_state
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn update_led_state_set_capsl() {
|
||||
let mut dev = InputDevice::new_keyboard(0);
|
||||
// LED_CAPSL = 1 → byte 0, bit 1
|
||||
dev.update_led_state(LED_CAPSL, true);
|
||||
let byte = (LED_CAPSL / 8) as usize;
|
||||
let bit = LED_CAPSL % 8;
|
||||
assert_eq!(dev.led_state[byte] & (1 << bit), 1 << bit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_led_state_clear_capsl() {
|
||||
let mut dev = InputDevice::new_keyboard(0);
|
||||
dev.update_led_state(LED_CAPSL, true);
|
||||
assert_bit_set(&dev.led_state, LED_CAPSL);
|
||||
dev.update_led_state(LED_CAPSL, false);
|
||||
assert_bit_clear(&dev.led_state, LED_CAPSL);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 13. abs_info default touchpad
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn touchpad_abs_x_range() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let info = dev.abs_info(ABS_X);
|
||||
assert_eq!(info.minimum, 0);
|
||||
assert_eq!(info.maximum, 65_535);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_abs_pressure_max() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let info = dev.abs_info(ABS_PRESSURE);
|
||||
assert_eq!(info.maximum, 255);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn touchpad_abs_mt_slot_range() {
|
||||
let dev = InputDevice::new_touchpad(0);
|
||||
let info = dev.abs_info(ABS_MT_SLOT);
|
||||
assert_eq!(info.minimum, 0);
|
||||
assert_eq!(info.maximum, 9);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 14. set_abs_info overrides default
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn set_abs_info_override() {
|
||||
let mut dev = InputDevice::new_touchpad(0);
|
||||
let custom = AbsInfo {
|
||||
value: 42,
|
||||
minimum: -100,
|
||||
maximum: 100,
|
||||
fuzz: 1,
|
||||
flat: 2,
|
||||
resolution: 3,
|
||||
};
|
||||
dev.set_abs_info(ABS_X, custom);
|
||||
let info = dev.abs_info(ABS_X);
|
||||
assert_eq!(info.value, 42);
|
||||
assert_eq!(info.minimum, -100);
|
||||
assert_eq!(info.maximum, 100);
|
||||
assert_eq!(info.fuzz, 1);
|
||||
assert_eq!(info.flat, 2);
|
||||
assert_eq!(info.resolution, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_abs_info_does_not_affect_other_axes() {
|
||||
let mut dev = InputDevice::new_touchpad(0);
|
||||
let custom = AbsInfo {
|
||||
value: 0,
|
||||
minimum: -50,
|
||||
maximum: 50,
|
||||
..AbsInfo::default()
|
||||
};
|
||||
dev.set_abs_info(ABS_X, custom);
|
||||
// ABS_Y should still return the default touchpad range
|
||||
let info_y = dev.abs_info(ABS_Y);
|
||||
assert_eq!(info_y.minimum, 0);
|
||||
assert_eq!(info_y.maximum, 65_535);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 15. bitmap_from_codes edge cases
|
||||
// ---------------------------------------------------------------
|
||||
#[test]
|
||||
fn bitmap_from_codes_empty_input() {
|
||||
let bm = bitmap_from_codes(&[]);
|
||||
assert!(bm.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bitmap_from_codes_single_code() {
|
||||
let bm = bitmap_from_codes(&[5u16]);
|
||||
assert_eq!(bm.len(), 1); // (5/8)+1 = 1
|
||||
assert_eq!(bm[0], 1 << 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bitmap_from_codes_multiple_codes_same_byte() {
|
||||
// REL_X=0, REL_Y=1, REL_WHEEL=8, REL_HWHEEL=6
|
||||
// REL_X and REL_Y are in byte 0; REL_HWHEEL is in byte 0 too; REL_WHEEL is byte 1
|
||||
let bm = bitmap_from_codes(&[REL_X, REL_Y, REL_HWHEEL, REL_WHEEL]);
|
||||
assert_bit_set(&bm, REL_X);
|
||||
assert_bit_set(&bm, REL_Y);
|
||||
assert_bit_set(&bm, REL_WHEEL);
|
||||
assert_bit_set(&bm, REL_HWHEEL);
|
||||
// Byte 0 should have bits 0 (REL_X), 1 (REL_Y), 6 (REL_HWHEEL) set
|
||||
assert_eq!(bm[0], (1 << 0) | (1 << 1) | (1 << 6));
|
||||
// Byte 1 should have bit 0 (REL_WHEEL = 8 → byte 1, bit 0)
|
||||
assert_eq!(bm[1], 1 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user