Desktop Phase 1: add 19 tests to redox-drm KMS modules

This commit is contained in:
2026-04-25 01:16:30 +01:00
parent 3ec32b3351
commit c829dc704b
5 changed files with 290 additions and 0 deletions
@@ -44,3 +44,42 @@ pub fn synthetic_edid() -> Vec<u8> {
0x44, 0x50, 0x0a, 0x20, 0x20, 0x00, 0xa7,
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn synthetic_displayport_has_correct_fields() {
let conn = Connector::synthetic_displayport(5, 10);
assert_eq!(conn.info.id, 5);
assert_eq!(conn.info.encoder_id, 10);
assert_eq!(conn.info.connector_type, ConnectorType::DisplayPort);
assert_eq!(conn.info.connection, ConnectorStatus::Connected);
assert!(!conn.info.modes.is_empty(), "synthetic DisplayPort should have modes");
}
#[test]
fn synthetic_displayport_modes_have_valid_dimensions() {
let conn = Connector::synthetic_displayport(1, 1);
for mode in &conn.info.modes {
assert!(mode.hdisplay > 0, "mode hdisplay should be > 0");
assert!(mode.vdisplay > 0, "mode vdisplay should be > 0");
assert!(mode.vrefresh > 0, "mode vrefresh should be > 0");
assert!(mode.clock > 0, "mode clock should be > 0");
}
}
#[test]
fn synthetic_edid_returns_exactly_112_bytes() {
let edid = synthetic_edid();
assert_eq!(edid.len(), 112);
}
#[test]
fn synthetic_edid_has_valid_header() {
let edid = synthetic_edid();
let header: [u8; 8] = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00];
assert_eq!(&edid[0..8], &header, "EDID header should be valid");
}
}
@@ -41,3 +41,67 @@ impl Crtc {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_mode() -> ModeInfo {
ModeInfo::default_1080p()
}
#[test]
fn new_initializes_correctly() {
let crtc = Crtc::new(42);
assert_eq!(crtc.id, 42);
assert_eq!(crtc.current_fb, 0);
assert!(crtc.connectors.is_empty());
assert!(crtc.mode.is_none());
assert_eq!(crtc.gamma_size, 256);
}
#[test]
fn program_sets_fb_connectors_and_mode() {
let mut crtc = Crtc::new(1);
let mode = test_mode();
let result = crtc.program(99, &[10, 20], &mode);
assert!(result.is_ok());
assert_eq!(crtc.current_fb, 99);
assert_eq!(crtc.connectors, vec![10, 20]);
assert!(crtc.mode.is_some());
let programmed_mode = crtc.mode.unwrap();
assert_eq!(programmed_mode.hdisplay, 1920);
assert_eq!(programmed_mode.vdisplay, 1080);
}
#[test]
fn program_empty_connectors_returns_invalid_argument() {
let mut crtc = Crtc::new(1);
let mode = test_mode();
let result = crtc.program(99, &[], &mode);
assert!(result.is_err());
match result.unwrap_err() {
DriverError::InvalidArgument(msg) => {
assert!(msg.contains("connector"));
}
other => panic!("expected InvalidArgument, got {:?}", other),
}
// State should be unchanged
assert_eq!(crtc.current_fb, 0);
assert!(crtc.connectors.is_empty());
assert!(crtc.mode.is_none());
}
#[test]
fn program_multiple_connectors_accepted() {
let mut crtc = Crtc::new(1);
let mode = test_mode();
let result = crtc.program(50, &[1, 2, 3, 4, 5], &mode);
assert!(result.is_ok());
assert_eq!(crtc.connectors.len(), 5);
assert_eq!(crtc.connectors, vec![1, 2, 3, 4, 5]);
}
}
@@ -180,3 +180,91 @@ pub struct EncoderInfo {
#[allow(dead_code)]
pub possible_clones: u32,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_1080p_has_correct_values() {
let mode = ModeInfo::default_1080p();
assert_eq!(mode.hdisplay, 1920);
assert_eq!(mode.vdisplay, 1080);
assert_eq!(mode.vrefresh, 60);
assert_eq!(mode.clock, 148_500);
assert_eq!(mode.name, "1920x1080@60");
assert_eq!(mode.htotal, 2200);
assert_eq!(mode.vtotal, 1125);
}
#[test]
fn from_edid_synthetic_edid_too_short_returns_empty() {
let edid = super::connector::synthetic_edid();
assert!(edid.len() < 128, "synthetic EDID is shorter than 128 bytes");
let modes = ModeInfo::from_edid(&edid);
assert!(modes.is_empty(), "EDID shorter than 128 bytes should produce no modes");
}
#[test]
fn from_edid_empty_input_returns_empty() {
let modes = ModeInfo::from_edid(&[]);
assert!(modes.is_empty());
}
#[test]
fn from_edid_short_input_returns_empty() {
let modes = ModeInfo::from_edid(&[0u8; 64]);
assert!(modes.is_empty());
}
#[test]
fn from_edid_invalid_header_returns_empty() {
let mut data = vec![0u8; 128];
data[0] = 0x01;
let modes = ModeInfo::from_edid(&data);
assert!(modes.is_empty());
}
#[test]
fn from_edid_parsed_modes_have_nonzero_dimensions() {
let edid = super::connector::synthetic_edid();
let modes = ModeInfo::from_edid(&edid);
for mode in &modes {
assert_ne!(mode.hdisplay, 0, "hdisplay should not be zero");
assert_ne!(mode.vdisplay, 0, "vdisplay should not be zero");
}
}
#[test]
fn from_edid_parsed_modes_have_correct_name_format() {
let edid = super::connector::synthetic_edid();
let modes = ModeInfo::from_edid(&edid);
for mode in &modes {
let parts: Vec<&str> = mode.name.split('@').collect();
assert_eq!(parts.len(), 2, "name should contain exactly one '@': {}", mode.name);
let dims: Vec<&str> = parts[0].split('x').collect();
assert_eq!(dims.len(), 2, "name prefix should be WxH: {}", mode.name);
let w: u16 = dims[0].parse().expect("width should be numeric");
let h: u16 = dims[1].parse().expect("height should be numeric");
assert_eq!(w, mode.hdisplay);
assert_eq!(h, mode.vdisplay);
let refresh: u32 = parts[1].parse().expect("refresh should be numeric");
assert_eq!(refresh, mode.vrefresh);
}
}
#[test]
fn from_edid_with_valid_header_but_zero_pixel_clock_skips_descriptor() {
let mut data = vec![0u8; 128];
data[0] = 0x00;
data[1] = 0xFF;
data[2] = 0xFF;
data[3] = 0xFF;
data[4] = 0xFF;
data[5] = 0xFF;
data[6] = 0xFF;
data[7] = 0x00;
let modes = ModeInfo::from_edid(&data);
assert!(modes.is_empty());
}
}
@@ -40,3 +40,52 @@ impl Plane {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_primary_initializes_correctly() {
let plane = Plane::new(7, PlaneKind::Primary);
assert_eq!(plane.id, 7);
assert_eq!(plane.kind, PlaneKind::Primary);
assert_eq!(plane.fb_handle, None);
assert_eq!(plane.crtc_id, None);
}
#[test]
fn new_cursor_initializes_correctly() {
let plane = Plane::new(3, PlaneKind::Cursor);
assert_eq!(plane.id, 3);
assert_eq!(plane.kind, PlaneKind::Cursor);
assert!(plane.fb_handle.is_none());
assert!(plane.crtc_id.is_none());
}
#[test]
fn attach_sets_crtc_id_and_fb_handle() {
let mut plane = Plane::new(1, PlaneKind::Primary);
let result = plane.attach(10, 20);
assert!(result.is_ok());
assert_eq!(plane.crtc_id, Some(10));
assert_eq!(plane.fb_handle, Some(20));
}
#[test]
fn attach_zero_fb_handle_returns_invalid_argument() {
let mut plane = Plane::new(1, PlaneKind::Primary);
let result = plane.attach(10, 0);
assert!(result.is_err());
match result.unwrap_err() {
DriverError::InvalidArgument(msg) => {
assert!(msg.contains("framebuffer"));
}
other => panic!("expected InvalidArgument, got {:?}", other),
}
assert_eq!(plane.crtc_id, None);
assert_eq!(plane.fb_handle, None);
}
}
@@ -579,4 +579,54 @@ mod tests {
assert!(!expectation.required);
assert!(expectation.keys.is_empty());
}
#[test]
fn mode_info_default_1080p_clock_matches_standard_cvt() {
use crate::kms::ModeInfo;
let mode = ModeInfo::default_1080p();
// Standard 1080p60 timing: 148.5 MHz pixel clock
assert_eq!(mode.clock, 148_500);
// Total pixels per frame = htotal * vtotal = 2200 * 1125 = 2_475_000
// Refresh = clock*1000 / total = 148_500_000 / 2_475_000 = 60
assert_eq!(mode.htotal as u32 * mode.vtotal as u32, 2_475_000_u32);
}
#[test]
fn mode_info_from_edid_rejects_short_edid() {
use crate::kms::connector::synthetic_edid;
use crate::kms::ModeInfo;
let edid = synthetic_edid();
assert!(edid.len() < 128);
let modes = ModeInfo::from_edid(&edid);
assert!(modes.is_empty());
}
#[test]
fn mode_info_from_edid_parses_valid_128byte_edid() {
use crate::kms::ModeInfo;
let mut edid = vec![0u8; 128];
edid[0] = 0x00;
edid[1] = 0xFF;
edid[2] = 0xFF;
edid[3] = 0xFF;
edid[4] = 0xFF;
edid[5] = 0xFF;
edid[6] = 0xFF;
edid[7] = 0x00;
let modes = ModeInfo::from_edid(&edid);
assert!(modes.is_empty(), "all-zero descriptors should produce no modes");
}
#[test]
fn mode_info_from_edid_name_format_is_width_x_height_at_refresh() {
use crate::kms::connector::synthetic_edid;
use crate::kms::ModeInfo;
let edid = synthetic_edid();
let modes = ModeInfo::from_edid(&edid);
for mode in &modes {
// Verify the canonical format: "WxH@refresh"
let expected = format!("{}x{}@{}", mode.hdisplay, mode.vdisplay, mode.vrefresh);
assert_eq!(mode.name, expected);
}
}
}