Desktop Phase 1: add 42 tests to redox-drm scheme/driver and redbear-hwutils
This commit is contained in:
@@ -113,3 +113,90 @@ pub trait GpuDriver: Send + Sync {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::{discriminant, offset_of, size_of};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn redox_private_cs_submit_size() {
|
||||
// src_handle(u32) + dst_handle(u32) + src_offset(u64) + dst_offset(u64) + byte_count(u64)
|
||||
// = 4 + 4 + 8 + 8 + 8 = 32 bytes
|
||||
assert_eq!(size_of::<RedoxPrivateCsSubmit>(), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redox_private_cs_submit_result_size() {
|
||||
// seqno(u64) = 8 bytes
|
||||
assert_eq!(size_of::<RedoxPrivateCsSubmitResult>(), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redox_private_cs_wait_size() {
|
||||
// seqno(u64) + timeout_ns(u64) = 16 bytes
|
||||
assert_eq!(size_of::<RedoxPrivateCsWait>(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redox_private_cs_wait_result_size() {
|
||||
// completed(bool) + 7 padding + completed_seqno(u64) = 16 bytes
|
||||
assert_eq!(size_of::<RedoxPrivateCsWaitResult>(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn driver_event_vblank_size() {
|
||||
let event = DriverEvent::Vblank {
|
||||
crtc_id: 0xDEADBEEF,
|
||||
count: 0x1234_5678_9ABC_DEF0,
|
||||
};
|
||||
match event {
|
||||
DriverEvent::Vblank { crtc_id, count } => {
|
||||
assert_eq!(crtc_id, 0xDEADBEEF);
|
||||
assert_eq!(count, 0x1234_5678_9ABC_DEF0);
|
||||
}
|
||||
DriverEvent::Hotplug { .. } => panic!("expected Vblank, got Hotplug"),
|
||||
}
|
||||
let enum_size = size_of::<DriverEvent>();
|
||||
assert!(enum_size > 0, "DriverEvent must be non-zero-sized");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn driver_event_hotplug_size() {
|
||||
let event = DriverEvent::Hotplug {
|
||||
connector_id: 0xCAFEBABE,
|
||||
};
|
||||
match event {
|
||||
DriverEvent::Hotplug { connector_id } => {
|
||||
assert_eq!(connector_id, 0xCAFEBABE);
|
||||
}
|
||||
DriverEvent::Vblank { .. } => panic!("expected Hotplug, got Vblank"),
|
||||
}
|
||||
let vblank = DriverEvent::Vblank {
|
||||
crtc_id: 0,
|
||||
count: 0,
|
||||
};
|
||||
let hotplug = DriverEvent::Hotplug { connector_id: 0 };
|
||||
assert_ne!(
|
||||
discriminant(&vblank),
|
||||
discriminant(&hotplug),
|
||||
"Vblank and Hotplug must have distinct discriminants"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redox_private_cs_submit_is_repr_c() {
|
||||
assert_eq!(offset_of!(RedoxPrivateCsSubmit, src_handle), 0);
|
||||
assert_eq!(offset_of!(RedoxPrivateCsSubmit, dst_handle), 4);
|
||||
assert_eq!(offset_of!(RedoxPrivateCsSubmit, src_offset), 8);
|
||||
assert_eq!(offset_of!(RedoxPrivateCsSubmit, dst_offset), 16);
|
||||
assert_eq!(offset_of!(RedoxPrivateCsSubmit, byte_count), 24);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redox_private_cs_wait_is_repr_c() {
|
||||
assert_eq!(offset_of!(RedoxPrivateCsWait, seqno), 0);
|
||||
assert_eq!(offset_of!(RedoxPrivateCsWait, timeout_ns), 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2168,4 +2168,364 @@ mod tests {
|
||||
|
||||
assert_eq!(err.errno, EINVAL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_has_other_refs_returns_false_when_only_current_handle_owns_gem() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 4096,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
|
||||
let gem_handle = created.handle;
|
||||
assert!(
|
||||
!scheme.gem_has_other_refs(card, gem_handle),
|
||||
"only one handle owns the GEM, so gem_has_other_refs should be false"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_has_other_refs_returns_true_when_another_handle_owns_gem() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card_a = open_card(&mut scheme);
|
||||
let card_b = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 4096,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card_a, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card_a);
|
||||
let gem_handle = created.handle;
|
||||
|
||||
let export = DrmPrimeHandleToFdWire {
|
||||
handle: gem_handle,
|
||||
flags: 0,
|
||||
};
|
||||
write_ioctl(&mut scheme, card_a, DRM_IOCTL_PRIME_HANDLE_TO_FD, &export).unwrap();
|
||||
let exported = read_response::<DrmPrimeHandleToFdResponseWire>(&mut scheme, card_a);
|
||||
|
||||
let import = DrmPrimeFdToHandleWire {
|
||||
fd: exported.fd,
|
||||
_pad: 0,
|
||||
};
|
||||
write_ioctl(&mut scheme, card_b, DRM_IOCTL_PRIME_FD_TO_HANDLE, &import).unwrap();
|
||||
let imported = read_response::<DrmPrimeFdToHandleResponseWire>(&mut scheme, card_b);
|
||||
|
||||
assert!(
|
||||
scheme.gem_has_other_refs(card_a, imported.handle),
|
||||
"card_b owns the same GEM, so gem_has_other_refs from card_a should be true"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_is_mapped_returns_false_initially() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 4096,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
|
||||
assert!(
|
||||
!scheme.gem_is_mapped(created.handle),
|
||||
"freshly created GEM should not be mapped"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_is_mapped_returns_true_after_pin() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 4096,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
let gem_handle = created.handle;
|
||||
|
||||
scheme.pin_mapped_gem(card, gem_handle).unwrap();
|
||||
|
||||
assert!(
|
||||
scheme.gem_is_mapped(gem_handle),
|
||||
"GEM should be mapped after pin_mapped_gem"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_export_refcount_starts_at_zero() {
|
||||
let scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
|
||||
assert_eq!(
|
||||
scheme.gem_export_refcount(9999),
|
||||
0,
|
||||
"unknown GEM should have refcount 0"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bump_export_ref_increments_from_zero_to_one() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let gem_handle: GemHandle = 42;
|
||||
|
||||
scheme.bump_export_ref(gem_handle);
|
||||
|
||||
assert_eq!(
|
||||
scheme.gem_export_refcount(gem_handle),
|
||||
1,
|
||||
"bumping an unknown GEM should set its refcount to 1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bump_export_ref_saturates_on_overflow() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let gem_handle: GemHandle = 42;
|
||||
|
||||
scheme.gem_export_refs.insert(gem_handle, usize::MAX);
|
||||
|
||||
scheme.bump_export_ref(gem_handle);
|
||||
|
||||
assert_eq!(
|
||||
scheme.gem_export_refcount(gem_handle),
|
||||
usize::MAX,
|
||||
"saturating add should keep refcount at usize::MAX"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_export_ref_decrements_count() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let gem_handle: GemHandle = 42;
|
||||
|
||||
scheme.bump_export_ref(gem_handle);
|
||||
scheme.bump_export_ref(gem_handle);
|
||||
assert_eq!(scheme.gem_export_refcount(gem_handle), 2);
|
||||
|
||||
scheme.drop_export_ref(gem_handle);
|
||||
|
||||
assert_eq!(
|
||||
scheme.gem_export_refcount(gem_handle),
|
||||
1,
|
||||
"dropping once should decrement from 2 to 1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_export_ref_removes_entry_when_count_reaches_zero() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let gem_handle: GemHandle = 42;
|
||||
|
||||
scheme.bump_export_ref(gem_handle);
|
||||
assert_eq!(scheme.gem_export_refcount(gem_handle), 1);
|
||||
|
||||
scheme.drop_export_ref(gem_handle);
|
||||
|
||||
assert_eq!(
|
||||
scheme.gem_export_refcount(gem_handle),
|
||||
0,
|
||||
"dropping the last ref should remove the entry"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_export_ref_cleans_up_prime_exports() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let gem_handle: GemHandle = 77;
|
||||
let export_token: u32 = 100;
|
||||
|
||||
scheme.prime_exports.insert(export_token, gem_handle);
|
||||
scheme.bump_export_ref(gem_handle);
|
||||
assert_eq!(scheme.gem_export_refcount(gem_handle), 1);
|
||||
assert!(scheme.prime_exports.contains_key(&export_token));
|
||||
|
||||
scheme.drop_export_ref(gem_handle);
|
||||
|
||||
assert_eq!(scheme.gem_export_refcount(gem_handle), 0);
|
||||
assert!(
|
||||
!scheme.prime_exports.values().any(|&h| h == gem_handle),
|
||||
"drop_export_ref should clean up prime_exports entries for this GEM"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_can_close_returns_false_when_gem_backs_framebuffer() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 16384,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
let gem_handle = created.handle;
|
||||
|
||||
let addfb = DrmAddFbWire {
|
||||
width: 64,
|
||||
height: 64,
|
||||
pitch: 256,
|
||||
bpp: 32,
|
||||
depth: 24,
|
||||
handle: gem_handle,
|
||||
fb_id: 0,
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_MODE_ADDFB, &addfb).unwrap();
|
||||
let fb_resp = read_response::<DrmAddFbWire>(&mut scheme, card);
|
||||
|
||||
if let Some(handle) = scheme.handles.get_mut(&card) {
|
||||
handle.owned_gems.retain(|&h| h != gem_handle);
|
||||
}
|
||||
|
||||
assert!(
|
||||
!scheme.gem_can_close(gem_handle),
|
||||
"GEM backing a framebuffer should not be closeable"
|
||||
);
|
||||
assert!(scheme.fb_registry.contains_key(&fb_resp.fb_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_can_close_returns_false_when_gem_is_mapped() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 4096,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
let gem_handle = created.handle;
|
||||
|
||||
scheme.pin_mapped_gem(card, gem_handle).unwrap();
|
||||
|
||||
if let Some(handle) = scheme.handles.get_mut(&card) {
|
||||
handle.owned_gems.retain(|&h| h != gem_handle);
|
||||
}
|
||||
|
||||
assert!(
|
||||
!scheme.gem_can_close(gem_handle),
|
||||
"mapped GEM should not be closeable"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gem_can_close_returns_true_when_unreferenced() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 4096,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
let gem_handle = created.handle;
|
||||
|
||||
if let Some(handle) = scheme.handles.get_mut(&card) {
|
||||
handle.owned_gems.retain(|&h| h != gem_handle);
|
||||
}
|
||||
|
||||
assert!(
|
||||
scheme.gem_can_close(gem_handle),
|
||||
"unreferenced, unmapped GEM with no FB or export refs should be closeable"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocate_handle_returns_sequential_ids() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
|
||||
let id_a = scheme.allocate_handle(NodeKind::Card);
|
||||
let id_b = scheme.allocate_handle(NodeKind::Card);
|
||||
|
||||
assert!(
|
||||
id_b > id_a,
|
||||
"second allocated handle ID ({id_b}) should be greater than first ({id_a})"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_fb_active_returns_false_for_unknown_fb() {
|
||||
let scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
|
||||
assert!(
|
||||
!scheme.is_fb_active(12345),
|
||||
"unknown fb_id should not be active"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_fb_active_returns_true_for_active_crtc_fb() {
|
||||
let mut scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
let card = open_card(&mut scheme);
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
size: 640 * 480 * 4,
|
||||
..DrmGemCreateWire::default()
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_GEM_CREATE, &create).unwrap();
|
||||
let created = read_response::<DrmGemCreateWire>(&mut scheme, card);
|
||||
let gem_handle = created.handle;
|
||||
|
||||
let addfb = DrmAddFbWire {
|
||||
width: 640,
|
||||
height: 480,
|
||||
pitch: 2560,
|
||||
bpp: 32,
|
||||
depth: 24,
|
||||
handle: gem_handle,
|
||||
fb_id: 0,
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_MODE_ADDFB, &addfb).unwrap();
|
||||
let fb_resp = read_response::<DrmAddFbWire>(&mut scheme, card);
|
||||
let fb_id = fb_resp.fb_id;
|
||||
|
||||
let mode = DrmModeWire {
|
||||
clock: 25200,
|
||||
hdisplay: 640,
|
||||
hsync_start: 656,
|
||||
hsync_end: 752,
|
||||
htotal: 800,
|
||||
vdisplay: 480,
|
||||
vsync_start: 490,
|
||||
vsync_end: 492,
|
||||
vtotal: 525,
|
||||
vrefresh: 60,
|
||||
..DrmModeWire::default()
|
||||
};
|
||||
let setcrtc = DrmSetCrtcWire {
|
||||
crtc_id: 0,
|
||||
fb_handle: fb_id,
|
||||
connector_count: 0,
|
||||
connectors: [0; 8],
|
||||
mode,
|
||||
};
|
||||
write_ioctl(&mut scheme, card, DRM_IOCTL_MODE_SETCRTC, &setcrtc).unwrap();
|
||||
|
||||
assert!(
|
||||
scheme.is_fb_active(fb_id),
|
||||
"FB programmed on a CRTC should be active"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_gem_create_size_rejects_zero() {
|
||||
let scheme = DrmScheme::new(Arc::new(FakeDriver::new(false)));
|
||||
|
||||
let err = scheme
|
||||
.validate_gem_create_size(0, "test-zero-size")
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(err.errno, EINVAL, "zero-sized GEM creation should return EINVAL");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,120 @@ pub fn lookup_pci_device_name(vendor_id: u16, device_id: u16) -> Option<String>
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::parse_pci_id_database;
|
||||
use super::{describe_usb_device, parse_args, parse_pci_id_database, parse_pci_location};
|
||||
|
||||
// --- parse_pci_location tests ---
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_valid_input() {
|
||||
let loc = parse_pci_location("0000--00--1f.2").unwrap();
|
||||
assert_eq!(loc.segment, 0x0000);
|
||||
assert_eq!(loc.bus, 0x00);
|
||||
assert_eq!(loc.device, 0x1f);
|
||||
assert_eq!(loc.function, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_scheme_path_format() {
|
||||
let loc = parse_pci_location("0003--01--0a.3").unwrap();
|
||||
assert_eq!(loc.scheme_path(), "/scheme/pci/0003--01--0a.3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_display_format() {
|
||||
let loc = parse_pci_location("00ff--02--1c.0").unwrap();
|
||||
assert_eq!(format!("{loc}"), "00ff:02:1c.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_missing_double_dash_returns_none() {
|
||||
assert!(parse_pci_location("0000.00--1f.2").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_missing_dot_returns_none() {
|
||||
assert!(parse_pci_location("0000--00--1f-2").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_non_hex_segment_returns_none() {
|
||||
assert!(parse_pci_location("zzzz--00--1f.2").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_pci_location_empty_string_returns_none() {
|
||||
assert!(parse_pci_location("").is_none());
|
||||
}
|
||||
|
||||
// --- describe_usb_device tests ---
|
||||
|
||||
#[test]
|
||||
fn describe_usb_device_both_fields() {
|
||||
assert_eq!(
|
||||
describe_usb_device(Some("Logitech"), Some("USB Mouse")),
|
||||
"Logitech USB Mouse"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn describe_usb_device_manufacturer_only() {
|
||||
assert_eq!(describe_usb_device(Some("Logitech"), None), "Logitech");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn describe_usb_device_product_only() {
|
||||
assert_eq!(describe_usb_device(None, Some("USB Mouse")), "USB Mouse");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn describe_usb_device_both_none() {
|
||||
assert_eq!(describe_usb_device(None, None), "USB device");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn describe_usb_device_empty_manufacturer_filtered() {
|
||||
assert_eq!(describe_usb_device(Some(""), Some("USB Mouse")), "USB Mouse");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn describe_usb_device_empty_product_filtered() {
|
||||
assert_eq!(describe_usb_device(Some("Logitech"), Some("")), "Logitech");
|
||||
}
|
||||
|
||||
// --- parse_args tests ---
|
||||
|
||||
#[test]
|
||||
fn parse_args_empty_extras_returns_ok() {
|
||||
assert!(parse_args("prog", "usage", vec!["prog".to_string()]).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_args_help_flag_returns_err_empty() {
|
||||
let result = parse_args("prog", "usage text", vec!["prog".to_string(), "--help".to_string()]);
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_args_h_flag_returns_err_empty() {
|
||||
let result = parse_args("prog", "usage text", vec!["prog".to_string(), "-h".to_string()]);
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_args_unknown_argument_returns_err_with_message() {
|
||||
let result = parse_args(
|
||||
"prog",
|
||||
"usage text",
|
||||
vec!["prog".to_string(), "bogus".to_string()],
|
||||
);
|
||||
assert!(result.is_err());
|
||||
let msg = result.unwrap_err();
|
||||
assert!(msg.contains("unsupported arguments"), "expected 'unsupported arguments' in: {msg}");
|
||||
}
|
||||
|
||||
// --- original pci_id_database tests ---
|
||||
|
||||
#[test]
|
||||
fn parses_vendor_and_device_entries_from_pci_ids() {
|
||||
|
||||
Reference in New Issue
Block a user