feat: DevicePlugin Task4 — 7个集成测试(MockBackend+序列化) 总计73测试通过
This commit is contained in:
@@ -151,3 +151,6 @@ impl Plugin for DevicePlugin {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
218
src/plugins/device/tests.rs
Normal file
218
src/plugins/device/tests.rs
Normal file
@@ -0,0 +1,218 @@
|
||||
//! DevicePlugin 集成测试
|
||||
//!
|
||||
//! 测试 DeviceCommand/DeviceResponse/DeviceEvent 的序列化以及 MockBackend 的行为。
|
||||
|
||||
use crate::core::message::{
|
||||
DeviceCapability, DeviceCommand, DeviceEvent, DeviceResponse, PixelFormat, SensorType,
|
||||
TouchAction,
|
||||
};
|
||||
use crate::plugins::device::backend::DeviceBackend;
|
||||
use anyhow::Result;
|
||||
|
||||
/// MockBackend — 用于测试的模拟设备后端
|
||||
///
|
||||
/// 不依赖真实硬件,返回预定义的响应数据。
|
||||
struct MockBackend {
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl MockBackend {
|
||||
fn new() -> Self {
|
||||
Self { initialized: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceBackend for MockBackend {
|
||||
fn name(&self) -> &str {
|
||||
"mock"
|
||||
}
|
||||
|
||||
fn init(&mut self, _config: &serde_json::Value) -> Result<()> {
|
||||
self.initialized = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn capabilities(&self) -> Vec<DeviceCapability> {
|
||||
vec![DeviceCapability::Display, DeviceCapability::Backlight]
|
||||
}
|
||||
|
||||
fn handle_command(&mut self, cmd: DeviceCommand) -> Result<DeviceResponse> {
|
||||
match cmd {
|
||||
DeviceCommand::GetDisplayInfo => Ok(DeviceResponse::DisplayInfo {
|
||||
width: 1280,
|
||||
height: 800,
|
||||
format: PixelFormat::RGB888,
|
||||
}),
|
||||
DeviceCommand::SetSleepInhibit(_) => Ok(DeviceResponse::Ok),
|
||||
DeviceCommand::SetBacklight(_) => Ok(DeviceResponse::Ok),
|
||||
_ => Ok(DeviceResponse::Error("not supported".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) -> Result<()> {
|
||||
self.initialized = false;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ── 序列化测试 ──
|
||||
|
||||
#[test]
|
||||
fn test_device_command_serialization() {
|
||||
let commands = vec![
|
||||
DeviceCommand::GetDisplayInfo,
|
||||
DeviceCommand::SetBrightness(75),
|
||||
DeviceCommand::SetBacklight(true),
|
||||
DeviceCommand::WriteFramebuffer {
|
||||
data: vec![0xFF, 0x00, 0xFF],
|
||||
format: PixelFormat::RGB888,
|
||||
},
|
||||
DeviceCommand::SetSleepInhibit(true),
|
||||
DeviceCommand::GetBatteryLevel,
|
||||
DeviceCommand::SetVolume(50),
|
||||
DeviceCommand::PlayAudio {
|
||||
path: "/audio/test.wav".to_string(),
|
||||
},
|
||||
DeviceCommand::GetTouchEvents,
|
||||
DeviceCommand::GetButtonState,
|
||||
DeviceCommand::GetSensorData(SensorType::Temperature),
|
||||
DeviceCommand::CustomCommand {
|
||||
subsystem: "gpio".to_string(),
|
||||
payload: serde_json::json!({"pin": 17, "value": 1}),
|
||||
},
|
||||
];
|
||||
|
||||
for cmd in commands {
|
||||
let json = serde_json::to_string(&cmd).expect("DeviceCommand should serialize");
|
||||
let decoded: DeviceCommand =
|
||||
serde_json::from_str(&json).expect("DeviceCommand should deserialize");
|
||||
let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
|
||||
assert_eq!(json, json2, "DeviceCommand round trip should be stable");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_device_response_serialization() {
|
||||
let responses = vec![
|
||||
DeviceResponse::DisplayInfo {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
format: PixelFormat::RGBA8888,
|
||||
},
|
||||
DeviceResponse::SensorData {
|
||||
sensor: SensorType::Temperature,
|
||||
value: 23.5,
|
||||
},
|
||||
DeviceResponse::BatteryLevel(85),
|
||||
DeviceResponse::Ok,
|
||||
DeviceResponse::Error("device not found".to_string()),
|
||||
DeviceResponse::Custom(serde_json::json!({"status": "ready"})),
|
||||
];
|
||||
|
||||
for resp in responses {
|
||||
let json = serde_json::to_string(&resp).expect("DeviceResponse should serialize");
|
||||
let decoded: DeviceResponse =
|
||||
serde_json::from_str(&json).expect("DeviceResponse should deserialize");
|
||||
let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
|
||||
assert_eq!(json, json2, "DeviceResponse round trip should be stable");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_device_event_serialization() {
|
||||
let events = vec![
|
||||
DeviceEvent::TouchEvent {
|
||||
x: 100,
|
||||
y: 200,
|
||||
action: TouchAction::Down,
|
||||
},
|
||||
DeviceEvent::ButtonEvent {
|
||||
button: 1,
|
||||
pressed: true,
|
||||
},
|
||||
DeviceEvent::BatteryLow(15),
|
||||
DeviceEvent::DisplayConnected,
|
||||
DeviceEvent::DisplayDisconnected,
|
||||
DeviceEvent::SensorAlert {
|
||||
sensor: SensorType::Temperature,
|
||||
value: 85.0,
|
||||
},
|
||||
];
|
||||
|
||||
for event in events {
|
||||
let json = serde_json::to_string(&event).expect("DeviceEvent should serialize");
|
||||
let decoded: DeviceEvent =
|
||||
serde_json::from_str(&json).expect("DeviceEvent should deserialize");
|
||||
let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again");
|
||||
assert_eq!(json, json2, "DeviceEvent round trip should be stable");
|
||||
}
|
||||
}
|
||||
|
||||
// ── MockBackend 行为测试 ──
|
||||
|
||||
#[test]
|
||||
fn test_mock_backend_capabilities() {
|
||||
let backend = MockBackend::new();
|
||||
let caps = backend.capabilities();
|
||||
assert_eq!(caps.len(), 2);
|
||||
assert!(caps.contains(&DeviceCapability::Display));
|
||||
assert!(caps.contains(&DeviceCapability::Backlight));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mock_backend_get_display_info() {
|
||||
let mut backend = MockBackend::new();
|
||||
backend
|
||||
.init(&serde_json::json!({}))
|
||||
.expect("init should succeed");
|
||||
|
||||
let response = backend
|
||||
.handle_command(DeviceCommand::GetDisplayInfo)
|
||||
.expect("GetDisplayInfo should succeed");
|
||||
|
||||
match response {
|
||||
DeviceResponse::DisplayInfo {
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
} => {
|
||||
assert_eq!(width, 1280);
|
||||
assert_eq!(height, 800);
|
||||
assert!(matches!(format, PixelFormat::RGB888));
|
||||
}
|
||||
_ => panic!("expected DisplayInfo response"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mock_backend_set_sleep_inhibit() {
|
||||
let mut backend = MockBackend::new();
|
||||
backend
|
||||
.init(&serde_json::json!({}))
|
||||
.expect("init should succeed");
|
||||
|
||||
let response = backend
|
||||
.handle_command(DeviceCommand::SetSleepInhibit(true))
|
||||
.expect("SetSleepInhibit should succeed");
|
||||
|
||||
assert!(matches!(response, DeviceResponse::Ok));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mock_backend_unsupported_command() {
|
||||
let mut backend = MockBackend::new();
|
||||
backend
|
||||
.init(&serde_json::json!({}))
|
||||
.expect("init should succeed");
|
||||
|
||||
let response = backend
|
||||
.handle_command(DeviceCommand::GetBatteryLevel)
|
||||
.expect("unsupported command should return Error response");
|
||||
|
||||
match response {
|
||||
DeviceResponse::Error(msg) => {
|
||||
assert_eq!(msg, "not supported");
|
||||
}
|
||||
_ => panic!("expected Error response for unsupported command"),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user