refactor: 清理未使用代码并添加未来功能标记
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

style: 统一代码格式和注释风格

docs: 更新多个功能文档的完整度和状态

feat(runtime): 添加路径验证工具支持

fix(pipeline): 改进条件判断和变量解析逻辑

test(types): 为ID类型添加全面测试用例

chore: 更新依赖项和Cargo.lock文件

perf(mcp): 优化MCP协议传输和错误处理
This commit is contained in:
iven
2026-03-25 21:55:12 +08:00
parent aa6a9cbd84
commit bf6d81f9c6
109 changed files with 12271 additions and 815 deletions

View File

@@ -62,3 +62,119 @@ pub enum ZclawError {
/// Result type alias for ZCLAW operations
pub type Result<T> = std::result::Result<T, ZclawError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_not_found_display() {
let err = ZclawError::NotFound("agent-123".to_string());
assert_eq!(err.to_string(), "Not found: agent-123");
}
#[test]
fn test_permission_denied_display() {
let err = ZclawError::PermissionDenied("unauthorized access".to_string());
assert_eq!(err.to_string(), "Permission denied: unauthorized access");
}
#[test]
fn test_llm_error_display() {
let err = ZclawError::LlmError("API rate limit".to_string());
assert_eq!(err.to_string(), "LLM error: API rate limit");
}
#[test]
fn test_tool_error_display() {
let err = ZclawError::ToolError("execution failed".to_string());
assert_eq!(err.to_string(), "Tool error: execution failed");
}
#[test]
fn test_storage_error_display() {
let err = ZclawError::StorageError("disk full".to_string());
assert_eq!(err.to_string(), "Storage error: disk full");
}
#[test]
fn test_config_error_display() {
let err = ZclawError::ConfigError("missing field".to_string());
assert_eq!(err.to_string(), "Configuration error: missing field");
}
#[test]
fn test_timeout_display() {
let err = ZclawError::Timeout("30s exceeded".to_string());
assert_eq!(err.to_string(), "Timeout: 30s exceeded");
}
#[test]
fn test_invalid_input_display() {
let err = ZclawError::InvalidInput("empty string".to_string());
assert_eq!(err.to_string(), "Invalid input: empty string");
}
#[test]
fn test_loop_detected_display() {
let err = ZclawError::LoopDetected("max iterations".to_string());
assert_eq!(err.to_string(), "Agent loop detected: max iterations");
}
#[test]
fn test_rate_limited_display() {
let err = ZclawError::RateLimited("100 req/min".to_string());
assert_eq!(err.to_string(), "Rate limited: 100 req/min");
}
#[test]
fn test_internal_error_display() {
let err = ZclawError::Internal("unexpected state".to_string());
assert_eq!(err.to_string(), "Internal error: unexpected state");
}
#[test]
fn test_export_error_display() {
let err = ZclawError::ExportError("PDF generation failed".to_string());
assert_eq!(err.to_string(), "Export error: PDF generation failed");
}
#[test]
fn test_mcp_error_display() {
let err = ZclawError::McpError("connection refused".to_string());
assert_eq!(err.to_string(), "MCP error: connection refused");
}
#[test]
fn test_security_error_display() {
let err = ZclawError::SecurityError("path traversal".to_string());
assert_eq!(err.to_string(), "Security error: path traversal");
}
#[test]
fn test_hand_error_display() {
let err = ZclawError::HandError("browser launch failed".to_string());
assert_eq!(err.to_string(), "Hand error: browser launch failed");
}
#[test]
fn test_serialization_error_from_json() {
let json_err = serde_json::from_str::<serde_json::Value>("invalid json");
let zclaw_err = ZclawError::from(json_err.unwrap_err());
assert!(matches!(zclaw_err, ZclawError::SerializationError(_)));
}
#[test]
fn test_result_type_ok() {
let result: Result<i32> = Ok(42);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 42);
}
#[test]
fn test_result_type_err() {
let result: Result<i32> = Err(ZclawError::NotFound("test".to_string()));
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), ZclawError::NotFound(_)));
}
}

View File

@@ -145,3 +145,114 @@ impl std::fmt::Display for RunId {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_agent_id_new_creates_unique_ids() {
let id1 = AgentId::new();
let id2 = AgentId::new();
assert_ne!(id1, id2);
}
#[test]
fn test_agent_id_default() {
let id = AgentId::default();
assert!(!id.0.is_nil());
}
#[test]
fn test_agent_id_display() {
let id = AgentId::new();
let display = format!("{}", id);
assert_eq!(display.len(), 36); // UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
assert!(display.contains('-'));
}
#[test]
fn test_agent_id_from_str_valid() {
let id = AgentId::new();
let id_str = id.to_string();
let parsed: AgentId = id_str.parse().unwrap();
assert_eq!(id, parsed);
}
#[test]
fn test_agent_id_from_str_invalid() {
let result: Result<AgentId, _> = "invalid-uuid".parse();
assert!(result.is_err());
}
#[test]
fn test_agent_id_serialization() {
let id = AgentId::new();
let json = serde_json::to_string(&id).unwrap();
let deserialized: AgentId = serde_json::from_str(&json).unwrap();
assert_eq!(id, deserialized);
}
#[test]
fn test_session_id_new_creates_unique_ids() {
let id1 = SessionId::new();
let id2 = SessionId::new();
assert_ne!(id1, id2);
}
#[test]
fn test_session_id_default() {
let id = SessionId::default();
assert!(!id.0.is_nil());
}
#[test]
fn test_tool_id_new() {
let id = ToolId::new("test_tool");
assert_eq!(id.as_str(), "test_tool");
}
#[test]
fn test_tool_id_from_str() {
let id: ToolId = "browser".into();
assert_eq!(id.as_str(), "browser");
}
#[test]
fn test_tool_id_from_string() {
let id: ToolId = String::from("shell").into();
assert_eq!(id.as_str(), "shell");
}
#[test]
fn test_tool_id_display() {
let id = ToolId::new("test");
assert_eq!(format!("{}", id), "test");
}
#[test]
fn test_skill_id_new() {
let id = SkillId::new("coding");
assert_eq!(id.as_str(), "coding");
}
#[test]
fn test_run_id_new_creates_unique_ids() {
let id1 = RunId::new();
let id2 = RunId::new();
assert_ne!(id1, id2);
}
#[test]
fn test_run_id_default() {
let id = RunId::default();
assert!(!id.0.is_nil());
}
#[test]
fn test_run_id_display() {
let id = RunId::new();
let display = format!("{}", id);
assert_eq!(display.len(), 36);
}
}

View File

@@ -161,3 +161,189 @@ impl ImageSource {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_user_creation() {
let msg = Message::user("Hello, world!");
assert!(msg.is_user());
assert_eq!(msg.role(), "user");
assert!(!msg.is_assistant());
assert!(!msg.is_tool_use());
}
#[test]
fn test_message_assistant_creation() {
let msg = Message::assistant("Hello!");
assert!(msg.is_assistant());
assert_eq!(msg.role(), "assistant");
}
#[test]
fn test_message_assistant_with_thinking() {
let msg = Message::assistant_with_thinking("Response", "My reasoning...");
assert!(msg.is_assistant());
if let Message::Assistant { content, thinking } = msg {
assert_eq!(content, "Response");
assert_eq!(thinking, Some("My reasoning...".to_string()));
} else {
panic!("Expected Assistant message");
}
}
#[test]
fn test_message_tool_use_creation() {
let input = serde_json::json!({"query": "test"});
let msg = Message::tool_use("call-123", ToolId::new("search"), input.clone());
assert!(msg.is_tool_use());
assert_eq!(msg.role(), "tool_use");
if let Message::ToolUse { id, tool, input: i } = msg {
assert_eq!(id, "call-123");
assert_eq!(tool.as_str(), "search");
assert_eq!(i, input);
} else {
panic!("Expected ToolUse message");
}
}
#[test]
fn test_message_tool_result_creation() {
let output = serde_json::json!({"result": "success"});
let msg = Message::tool_result("call-123", ToolId::new("search"), output.clone(), false);
assert!(msg.is_tool_result());
assert_eq!(msg.role(), "tool_result");
if let Message::ToolResult { tool_call_id, tool, output: o, is_error } = msg {
assert_eq!(tool_call_id, "call-123");
assert_eq!(tool.as_str(), "search");
assert_eq!(o, output);
assert!(!is_error);
} else {
panic!("Expected ToolResult message");
}
}
#[test]
fn test_message_tool_result_error() {
let output = serde_json::json!({"error": "failed"});
let msg = Message::tool_result("call-456", ToolId::new("exec"), output, true);
if let Message::ToolResult { is_error, .. } = msg {
assert!(is_error);
} else {
panic!("Expected ToolResult message");
}
}
#[test]
fn test_message_system_creation() {
let msg = Message::system("You are a helpful assistant.");
assert_eq!(msg.role(), "system");
assert!(!msg.is_user());
assert!(!msg.is_assistant());
}
#[test]
fn test_message_serialization_user() {
let msg = Message::user("Test message");
let json = serde_json::to_string(&msg).unwrap();
assert!(json.contains("\"role\":\"user\""));
assert!(json.contains("\"content\":\"Test message\""));
}
#[test]
fn test_message_serialization_assistant() {
let msg = Message::assistant("Response");
let json = serde_json::to_string(&msg).unwrap();
assert!(json.contains("\"role\":\"assistant\""));
}
#[test]
fn test_message_deserialization_user() {
let json = r#"{"role":"user","content":"Hello"}"#;
let msg: Message = serde_json::from_str(json).unwrap();
assert!(msg.is_user());
if let Message::User { content } = msg {
assert_eq!(content, "Hello");
} else {
panic!("Expected User message");
}
}
#[test]
fn test_content_block_text() {
let block = ContentBlock::Text { text: "Hello".to_string() };
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains("\"type\":\"text\""));
assert!(json.contains("\"text\":\"Hello\""));
}
#[test]
fn test_content_block_thinking() {
let block = ContentBlock::Thinking { thinking: "Reasoning...".to_string() };
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains("\"type\":\"thinking\""));
}
#[test]
fn test_content_block_tool_use() {
let block = ContentBlock::ToolUse {
id: "tool-1".to_string(),
name: "search".to_string(),
input: serde_json::json!({"q": "test"}),
};
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains("\"type\":\"tool_use\""));
assert!(json.contains("\"name\":\"search\""));
}
#[test]
fn test_content_block_tool_result() {
let block = ContentBlock::ToolResult {
tool_use_id: "tool-1".to_string(),
content: "Success".to_string(),
is_error: false,
};
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains("\"type\":\"tool_result\""));
assert!(json.contains("\"is_error\":false"));
}
#[test]
fn test_content_block_image() {
let source = ImageSource::base64("image/png", "base64data");
let block = ContentBlock::Image { source };
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains("\"type\":\"image\""));
}
#[test]
fn test_image_source_base64() {
let source = ImageSource::base64("image/png", "abc123");
assert_eq!(source.source_type, "base64");
assert_eq!(source.media_type, "image/png");
assert_eq!(source.data, "abc123");
}
#[test]
fn test_image_source_url() {
let source = ImageSource::url("https://example.com/image.png");
assert_eq!(source.source_type, "url");
assert_eq!(source.media_type, "image/*");
assert_eq!(source.data, "https://example.com/image.png");
}
#[test]
fn test_image_source_serialization() {
let source = ImageSource::base64("image/jpeg", "data123");
let json = serde_json::to_string(&source).unwrap();
assert!(json.contains("\"type\":\"base64\""));
assert!(json.contains("\"media_type\":\"image/jpeg\""));
}
}