Desktop Phase 1: add 19 tests to redox-drm KMS modules
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user