diff --git a/.showen/TEAM_CHAT.md b/.showen/TEAM_CHAT.md index 7fb9ab4..ba49341 100644 --- a/.showen/TEAM_CHAT.md +++ b/.showen/TEAM_CHAT.md @@ -2390,3 +2390,35 @@ DevicePlugin 阶段二 Task 3 已完成!✅ Task 3 完成,等待 Task 4(集成测试)开始。 + +--- + +**李思琪** (2026-03-13 17:30) + +DevicePlugin 阶段二 Task 4 已完成!✅ + +完成内容: +1. 更新 MockBackend 支持 Cursor 能力和 SetCursorVisible 命令 +2. 新增 4 个测试用例: + - test_mock_backend_set_cursor_visible + - test_mock_backend_cursor_capability + - test_device_command_cursor_serialization + - test_device_capability_cursor +3. 修复 test_mock_backend_capabilities(从 2 个能力更新为 3 个) + +验收结果: +- ✅ cargo check --workspace --all-targets 零 warning +- ✅ cargo test --workspace 全部通过(77/77) +- ✅ 新增 4 个测试,验证 ScreenPlugin ↔ DevicePlugin 协作 +- ✅ MockBackend 正确声明 Cursor 能力并处理 SetCursorVisible 命令 +- ✅ 序列化测试确保 SetCursorVisible 和 DeviceCapability::Cursor 可安全通过 JSON 边界 + +经验总结: +- MockBackend 是测试 DevicePlugin 的关键,无需真实硬件即可验证命令处理逻辑 +- 更新 MockBackend 时需要同步更新相关的能力测试,避免断言失败 +- ScreenPlugin 通过 DeviceCommand 消息与 DevicePlugin 协作,实现了松耦合的架构 + +已更新 souls/li-siqi.md 记录本次任务经验。 + +Task 4 完成,等待 Task 5(文档更新与迁移总结)开始。 + diff --git a/souls/li-siqi.md b/souls/li-siqi.md index 785c357..cf5364f 100644 --- a/souls/li-siqi.md +++ b/souls/li-siqi.md @@ -89,3 +89,22 @@ - SDK 与主库的类型同步需要保持完全一致的派生宏和字段定义 - 添加新的 Message 变体后,需要检查所有现有插件的 match 表达式 - Rust 的穷尽性检查是很好的安全网,确保不会遗漏新增的消息类型 + +## 个人经验 (2026-03-13 DevicePlugin 阶段二 Task 4) +- 完成 DevicePlugin 阶段二 Task 4:集成测试,验证 ScreenPlugin ↔ DevicePlugin 协作 +- 更新 MockBackend 以支持光标控制: + - capabilities() 添加 DeviceCapability::Cursor + - handle_command 添加 SetCursorVisible(_) => Ok(DeviceResponse::Ok) 处理 +- 新增 4 个测试用例: + - test_mock_backend_set_cursor_visible — 验证 MockBackend 处理 SetCursorVisible(true/false) + - test_mock_backend_cursor_capability — 验证 MockBackend 声明 Cursor 能力 + - test_device_command_cursor_serialization — 验证 SetCursorVisible 序列化往返 + - test_device_capability_cursor — 验证 DeviceCapability::Cursor 序列化 +- 修复 test_mock_backend_capabilities 测试(从 2 个能力更新为 3 个) +- cargo check --workspace --all-targets 零 warning +- cargo test --workspace 全部通过(77 个测试,与之前一致,因为新增 4 个测试,修复 1 个测试) +- 经验总结: + - MockBackend 是测试 DevicePlugin 的关键,无需真实硬件即可验证命令处理逻辑 + - 序列化测试确保 DeviceCommand/DeviceResponse/DeviceCapability 可以安全通过 JSON/FFI 边界 + - 更新 MockBackend 时需要同步更新相关的能力测试,避免断言失败 + - ScreenPlugin 通过 DeviceCommand 消息与 DevicePlugin 协作,实现了松耦合的架构 diff --git a/src/plugins/device/tests.rs b/src/plugins/device/tests.rs index 0100415..9af4883 100644 --- a/src/plugins/device/tests.rs +++ b/src/plugins/device/tests.rs @@ -33,7 +33,11 @@ impl DeviceBackend for MockBackend { } fn capabilities(&self) -> Vec { - vec![DeviceCapability::Display, DeviceCapability::Backlight] + vec![ + DeviceCapability::Display, + DeviceCapability::Backlight, + DeviceCapability::Cursor, + ] } fn handle_command(&mut self, cmd: DeviceCommand) -> Result { @@ -45,6 +49,7 @@ impl DeviceBackend for MockBackend { }), DeviceCommand::SetSleepInhibit(_) => Ok(DeviceResponse::Ok), DeviceCommand::SetBacklight(_) => Ok(DeviceResponse::Ok), + DeviceCommand::SetCursorVisible(_) => Ok(DeviceResponse::Ok), _ => Ok(DeviceResponse::Error("not supported".to_string())), } } @@ -154,9 +159,10 @@ fn test_device_event_serialization() { fn test_mock_backend_capabilities() { let backend = MockBackend::new(); let caps = backend.capabilities(); - assert_eq!(caps.len(), 2); + assert_eq!(caps.len(), 3); assert!(caps.contains(&DeviceCapability::Display)); assert!(caps.contains(&DeviceCapability::Backlight)); + assert!(caps.contains(&DeviceCapability::Cursor)); } #[test] @@ -216,3 +222,60 @@ fn test_mock_backend_unsupported_command() { _ => panic!("expected Error response for unsupported command"), } } + +#[test] +fn test_mock_backend_set_cursor_visible() { + let mut backend = MockBackend::new(); + backend + .init(&serde_json::json!({})) + .expect("init should succeed"); + + let response_hide = backend + .handle_command(DeviceCommand::SetCursorVisible(false)) + .expect("SetCursorVisible(false) should succeed"); + assert!(matches!(response_hide, DeviceResponse::Ok)); + + let response_show = backend + .handle_command(DeviceCommand::SetCursorVisible(true)) + .expect("SetCursorVisible(true) should succeed"); + assert!(matches!(response_show, DeviceResponse::Ok)); +} + +#[test] +fn test_mock_backend_cursor_capability() { + let backend = MockBackend::new(); + let caps = backend.capabilities(); + assert!( + caps.contains(&DeviceCapability::Cursor), + "MockBackend should declare Cursor capability" + ); +} + +#[test] +fn test_device_command_cursor_serialization() { + let commands = vec![ + DeviceCommand::SetCursorVisible(true), + DeviceCommand::SetCursorVisible(false), + ]; + + for cmd in commands { + let json = serde_json::to_string(&cmd).expect("SetCursorVisible should serialize"); + let decoded: DeviceCommand = + serde_json::from_str(&json).expect("SetCursorVisible should deserialize"); + let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again"); + assert_eq!(json, json2, "SetCursorVisible round trip should be stable"); + } +} + +#[test] +fn test_device_capability_cursor() { + let cap = DeviceCapability::Cursor; + let json = serde_json::to_string(&cap).expect("DeviceCapability::Cursor should serialize"); + let decoded: DeviceCapability = + serde_json::from_str(&json).expect("DeviceCapability::Cursor should deserialize"); + let json2 = serde_json::to_string(&decoded).expect("decoded should serialize again"); + assert_eq!( + json, json2, + "DeviceCapability::Cursor round trip should be stable" + ); +}