483 lines
13 KiB
Rust
483 lines
13 KiB
Rust
//! 设备模拟集成测试
|
|
|
|
#[cfg(test)]
|
|
mod virtio_block_device {
|
|
/// VirtIO块设备操作
|
|
enum BlockOp {
|
|
Read { sector: u64, count: u32 },
|
|
Write { sector: u64, count: u32 },
|
|
}
|
|
|
|
/// VirtIO块设备模拟器
|
|
struct VirtioBlockDevice {
|
|
sector_size: u32,
|
|
total_sectors: u64,
|
|
data_buffer: Vec<u8>,
|
|
}
|
|
|
|
impl VirtioBlockDevice {
|
|
fn new(total_sectors: u64, sector_size: u32) -> Self {
|
|
Self {
|
|
sector_size,
|
|
total_sectors,
|
|
data_buffer: vec![0; (total_sectors as usize) * (sector_size as usize)],
|
|
}
|
|
}
|
|
|
|
fn read(&self, sector: u64, count: u32) -> Option<Vec<u8>> {
|
|
if sector + count as u64 > self.total_sectors {
|
|
return None;
|
|
}
|
|
|
|
let start = (sector as usize) * (self.sector_size as usize);
|
|
let end = start + (count as usize) * (self.sector_size as usize);
|
|
|
|
Some(self.data_buffer[start..end].to_vec())
|
|
}
|
|
|
|
fn write(&mut self, sector: u64, data: &[u8]) -> bool {
|
|
let count = data.len() / (self.sector_size as usize);
|
|
if sector + count as u64 > self.total_sectors {
|
|
return false;
|
|
}
|
|
|
|
let start = (sector as usize) * (self.sector_size as usize);
|
|
let end = start + data.len();
|
|
|
|
self.data_buffer[start..end].copy_from_slice(data);
|
|
true
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_block_device_creation() {
|
|
let device = VirtioBlockDevice::new(1000, 512);
|
|
assert_eq!(device.total_sectors, 1000);
|
|
assert_eq!(device.sector_size, 512);
|
|
}
|
|
|
|
#[test]
|
|
fn test_block_read_operation() {
|
|
let device = VirtioBlockDevice::new(100, 512);
|
|
let data = device.read(0, 1);
|
|
assert!(data.is_some());
|
|
assert_eq!(data.unwrap().len(), 512);
|
|
}
|
|
|
|
#[test]
|
|
fn test_block_write_operation() {
|
|
let mut device = VirtioBlockDevice::new(100, 512);
|
|
let write_data = vec![0xAB; 512];
|
|
assert!(device.write(0, &write_data));
|
|
}
|
|
|
|
#[test]
|
|
fn test_block_boundary_check() {
|
|
let device = VirtioBlockDevice::new(10, 512);
|
|
// 超过容量的读取应该失败
|
|
assert!(device.read(0, 20).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_block_read_write_consistency() {
|
|
let mut device = VirtioBlockDevice::new(100, 512);
|
|
let write_data = vec![0xDEADBEEF as u8; 512];
|
|
|
|
device.write(5, &write_data);
|
|
let read_data = device.read(5, 1).unwrap();
|
|
|
|
assert_eq!(write_data, read_data);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod virtio_network_device {
|
|
/// VirtIO网络数据包
|
|
struct NetworkPacket {
|
|
data: Vec<u8>,
|
|
size: usize,
|
|
}
|
|
|
|
impl NetworkPacket {
|
|
fn new(data: Vec<u8>) -> Self {
|
|
let size = data.len();
|
|
Self { data, size }
|
|
}
|
|
}
|
|
|
|
/// VirtIO网络设备模拟器
|
|
struct VirtioNetDevice {
|
|
rx_queue: Vec<NetworkPacket>,
|
|
tx_queue: Vec<NetworkPacket>,
|
|
max_queue_size: usize,
|
|
}
|
|
|
|
impl VirtioNetDevice {
|
|
fn new(max_queue_size: usize) -> Self {
|
|
Self {
|
|
rx_queue: Vec::new(),
|
|
tx_queue: Vec::new(),
|
|
max_queue_size,
|
|
}
|
|
}
|
|
|
|
fn send(&mut self, packet: NetworkPacket) -> bool {
|
|
if self.tx_queue.len() < self.max_queue_size {
|
|
self.tx_queue.push(packet);
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
fn receive(&mut self, packet: NetworkPacket) -> bool {
|
|
if self.rx_queue.len() < self.max_queue_size {
|
|
self.rx_queue.push(packet);
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
fn get_rx_packet(&mut self) -> Option<NetworkPacket> {
|
|
if self.rx_queue.is_empty() {
|
|
None
|
|
} else {
|
|
Some(self.rx_queue.remove(0))
|
|
}
|
|
}
|
|
|
|
fn get_tx_packet(&mut self) -> Option<NetworkPacket> {
|
|
if self.tx_queue.is_empty() {
|
|
None
|
|
} else {
|
|
Some(self.tx_queue.remove(0))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_net_device_creation() {
|
|
let device = VirtioNetDevice::new(256);
|
|
assert_eq!(device.rx_queue.len(), 0);
|
|
assert_eq!(device.tx_queue.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_net_send_packet() {
|
|
let mut device = VirtioNetDevice::new(256);
|
|
let packet = NetworkPacket::new(vec![1, 2, 3, 4]);
|
|
assert!(device.send(packet));
|
|
assert_eq!(device.tx_queue.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_net_receive_packet() {
|
|
let mut device = VirtioNetDevice::new(256);
|
|
let packet = NetworkPacket::new(vec![5, 6, 7, 8]);
|
|
assert!(device.receive(packet));
|
|
assert_eq!(device.rx_queue.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_net_queue_overflow() {
|
|
let mut device = VirtioNetDevice::new(2);
|
|
|
|
// 填满队列
|
|
assert!(device.send(NetworkPacket::new(vec![1])));
|
|
assert!(device.send(NetworkPacket::new(vec![2])));
|
|
|
|
// 第三个应该失败
|
|
assert!(!device.send(NetworkPacket::new(vec![3])));
|
|
}
|
|
|
|
#[test]
|
|
fn test_net_packet_retrieval() {
|
|
let mut device = VirtioNetDevice::new(256);
|
|
let data = vec![0xAA, 0xBB, 0xCC];
|
|
device.send(NetworkPacket::new(data.clone()));
|
|
|
|
let packet = device.get_tx_packet().unwrap();
|
|
assert_eq!(packet.data, data);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod mmio_device_tests {
|
|
/// MMIO寄存器映射设备
|
|
struct MmioDevice {
|
|
registers: Vec<u32>,
|
|
register_count: usize,
|
|
}
|
|
|
|
impl MmioDevice {
|
|
fn new(register_count: usize) -> Self {
|
|
Self {
|
|
registers: vec![0; register_count],
|
|
register_count,
|
|
}
|
|
}
|
|
|
|
fn read_register(&self, offset: usize) -> Option<u32> {
|
|
if offset < self.register_count {
|
|
Some(self.registers[offset])
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn write_register(&mut self, offset: usize, value: u32) -> bool {
|
|
if offset < self.register_count {
|
|
self.registers[offset] = value;
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
fn read_register_field(&self, offset: usize, bit_offset: u32, mask: u32) -> Option<u32> {
|
|
self.read_register(offset).map(|val| (val >> bit_offset) & mask)
|
|
}
|
|
|
|
fn write_register_field(&mut self, offset: usize, bit_offset: u32, mask: u32, value: u32) -> bool {
|
|
if let Some(current) = self.read_register(offset) {
|
|
let masked = current & !(mask << bit_offset);
|
|
let new_val = masked | ((value & mask) << bit_offset);
|
|
self.write_register(offset, new_val)
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_mmio_device_creation() {
|
|
let device = MmioDevice::new(16);
|
|
assert_eq!(device.register_count, 16);
|
|
}
|
|
|
|
#[test]
|
|
fn test_mmio_read_write() {
|
|
let mut device = MmioDevice::new(8);
|
|
assert!(device.write_register(0, 0xDEADBEEF));
|
|
assert_eq!(device.read_register(0), Some(0xDEADBEEF));
|
|
}
|
|
|
|
#[test]
|
|
fn test_mmio_boundary_check() {
|
|
let mut device = MmioDevice::new(4);
|
|
assert!(!device.write_register(10, 0x123));
|
|
assert!(device.read_register(10).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_mmio_field_operations() {
|
|
let mut device = MmioDevice::new(4);
|
|
|
|
// 写4位字段 (位3-7)
|
|
device.write_register_field(0, 3, 0x0F, 0x0A);
|
|
|
|
// 读回字段
|
|
let value = device.read_register_field(0, 3, 0x0F);
|
|
assert_eq!(value, Some(0x0A));
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod interrupt_handling {
|
|
/// 中断处理模拟
|
|
struct InterruptController {
|
|
pending_interrupts: u64,
|
|
enabled_interrupts: u64,
|
|
}
|
|
|
|
impl InterruptController {
|
|
fn new() -> Self {
|
|
Self {
|
|
pending_interrupts: 0,
|
|
enabled_interrupts: 0,
|
|
}
|
|
}
|
|
|
|
fn trigger(&mut self, irq: u32) {
|
|
if irq < 64 {
|
|
self.pending_interrupts |= 1u64 << irq;
|
|
}
|
|
}
|
|
|
|
fn enable(&mut self, irq: u32) {
|
|
if irq < 64 {
|
|
self.enabled_interrupts |= 1u64 << irq;
|
|
}
|
|
}
|
|
|
|
fn get_pending(&self) -> Option<u32> {
|
|
if self.pending_interrupts == 0 {
|
|
return None;
|
|
}
|
|
|
|
for i in 0..64 {
|
|
if (self.pending_interrupts & (1u64 << i)) != 0 &&
|
|
(self.enabled_interrupts & (1u64 << i)) != 0 {
|
|
return Some(i as u32);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn acknowledge(&mut self, irq: u32) {
|
|
if irq < 64 {
|
|
self.pending_interrupts &= !(1u64 << irq);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_interrupt_trigger() {
|
|
let mut ic = InterruptController::new();
|
|
ic.trigger(5);
|
|
assert_eq!(ic.pending_interrupts, 1u64 << 5);
|
|
}
|
|
|
|
#[test]
|
|
fn test_interrupt_enable_disable() {
|
|
let mut ic = InterruptController::new();
|
|
ic.trigger(3);
|
|
ic.enable(3);
|
|
|
|
assert_eq!(ic.get_pending(), Some(3));
|
|
}
|
|
|
|
#[test]
|
|
fn test_interrupt_acknowledge() {
|
|
let mut ic = InterruptController::new();
|
|
ic.trigger(7);
|
|
ic.enable(7);
|
|
ic.acknowledge(7);
|
|
|
|
assert!(ic.get_pending().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_interrupts() {
|
|
let mut ic = InterruptController::new();
|
|
ic.trigger(1);
|
|
ic.trigger(2);
|
|
ic.trigger(3);
|
|
|
|
ic.enable(1);
|
|
ic.enable(2);
|
|
ic.enable(3);
|
|
|
|
// 应该返回最低的待处理中断
|
|
assert!(ic.get_pending().is_some());
|
|
}
|
|
}
|
|
#[cfg(test)]
|
|
mod virtio_gpu_device {
|
|
/// VirtIO GPU设备模拟器
|
|
struct VirtioGpuDevice {
|
|
resolution: (u32, u32),
|
|
framebuffer: Vec<u32>,
|
|
device_status: u32,
|
|
capabilities: u32,
|
|
}
|
|
|
|
impl VirtioGpuDevice {
|
|
fn new(width: u32, height: u32) -> Self {
|
|
Self {
|
|
resolution: (width, height),
|
|
framebuffer: vec![0; (width * height) as usize],
|
|
device_status: 0,
|
|
capabilities: 0x00000001, // 支持基本绘图命令
|
|
}
|
|
}
|
|
|
|
fn set_resolution(&mut self, width: u32, height: u32) -> bool {
|
|
self.resolution = (width, height);
|
|
self.framebuffer = vec![0; (width * height) as usize];
|
|
true
|
|
}
|
|
|
|
fn draw_pixel(&mut self, x: u32, y: u32, color: u32) -> bool {
|
|
if x < self.resolution.0 && y < self.resolution.1 {
|
|
let index = (y * self.resolution.0 + x) as usize;
|
|
self.framebuffer[index] = color;
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
fn draw_rectangle(&mut self, x: u32, y: u32, width: u32, height: u32, color: u32) -> bool {
|
|
if x + width > self.resolution.0 || y + height > self.resolution.1 {
|
|
return false;
|
|
}
|
|
|
|
for row in y..y + height {
|
|
for col in x..x + width {
|
|
let index = (row * self.resolution.0 + col) as usize;
|
|
self.framebuffer[index] = color;
|
|
}
|
|
}
|
|
true
|
|
}
|
|
|
|
fn get_pixel(&self, x: u32, y: u32) -> Option<u32> {
|
|
if x < self.resolution.0 && y < self.resolution.1 {
|
|
let index = (y * self.resolution.0 + x) as usize;
|
|
Some(self.framebuffer[index])
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn get_framebuffer(&self) -> &[u32] {
|
|
&self.framebuffer
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_gpu_device_creation() {
|
|
let device = VirtioGpuDevice::new(1024, 768);
|
|
assert_eq!(device.resolution, (1024, 768));
|
|
assert_eq!(device.framebuffer.len(), (1024 * 768) as usize);
|
|
}
|
|
|
|
#[test]
|
|
fn test_gpu_draw_pixel() {
|
|
let mut device = VirtioGpuDevice::new(800, 600);
|
|
assert!(device.draw_pixel(100, 200, 0x00FF00));
|
|
assert_eq!(device.get_pixel(100, 200), Some(0x00FF00));
|
|
}
|
|
|
|
#[test]
|
|
fn test_gpu_draw_rectangle() {
|
|
let mut device = VirtioGpuDevice::new(800, 600);
|
|
assert!(device.draw_rectangle(10, 20, 50, 30, 0xFF0000));
|
|
|
|
// 检查矩形内的像素
|
|
assert_eq!(device.get_pixel(10, 20), Some(0xFF0000));
|
|
assert_eq!(device.get_pixel(59, 49), Some(0xFF0000));
|
|
|
|
// 检查矩形外的像素
|
|
assert_eq!(device.get_pixel(9, 19), Some(0x000000));
|
|
}
|
|
|
|
#[test]
|
|
fn test_gpu_resolution_change() {
|
|
let mut device = VirtioGpuDevice::new(800, 600);
|
|
assert!(device.set_resolution(1920, 1080));
|
|
assert_eq!(device.resolution, (1920, 1080));
|
|
assert_eq!(device.framebuffer.len(), (1920 * 1080) as usize);
|
|
}
|
|
|
|
#[test]
|
|
fn test_gpu_boundary_check() {
|
|
let mut device = VirtioGpuDevice::new(100, 100);
|
|
// 超出边界的绘制应该失败
|
|
assert!(!device.draw_pixel(150, 200, 0x0000FF));
|
|
assert!(!device.draw_rectangle(50, 50, 100, 100, 0xFFFFFF));
|
|
}
|
|
}
|