trait IpmiTransport { fn send_command(&self, cmd: u8, data: &[u8]) -> Result<Vec<u8>, String>; }
struct RealIpmi { } impl IpmiTransport for RealIpmi { fn send_command(&self, cmd: u8, data: &[u8]) -> Result<Vec<u8>, String> { todo!("Real IPMI call") } }
struct MockIpmi { responses: std::collections::HashMap<u8, Vec<u8>>, } impl IpmiTransport for MockIpmi { fn send_command(&self, cmd: u8, _data: &[u8]) -> Result<Vec<u8>, String> { self.responses.get(&cmd) .cloned() .ok_or_else(|| format!("No mock response for cmd 0x{cmd:02x}")) } }
fn read_sensor_temperature(transport: &dyn IpmiTransport) -> Result<f64, String> { let response = transport.send_command(0x2D, &[])?; if response.len() < 2 { return Err("Response too short".into()); } Ok(response[0] as f64 + (response[1] as f64 / 256.0)) }
#[cfg(test)] mod tests { use super::*;
#[test] fn test_temperature_reading() { let mut mock = MockIpmi { responses: std::collections::HashMap::new() }; mock.responses.insert(0x2D, vec![72, 128]);
let temp = read_sensor_temperature(&mock).unwrap(); assert!((temp - 72.5).abs() < 0.01); }
#[test] fn test_short_response() { let mock = MockIpmi { responses: std::collections::HashMap::new() }; assert!(read_sensor_temperature(&mock).is_err()); } }
|