use selfware::tools::{
file::{DirectoryTree, FileEdit, FileRead, FileWrite},
shell::ShellExec,
Tool, ToolRegistry,
};
use serde_json::json;
#[tokio::test]
async fn test_file_read_success() {
let tool = FileRead::new();
let args = json!({"path": "Cargo.toml"});
let result = tool.execute(args).await.unwrap();
assert!(result.get("content").is_some());
assert_eq!(result.get("encoding").unwrap(), "utf-8");
}
#[tokio::test]
async fn test_file_read_not_found() {
let tool = FileRead::new();
let args = json!({"path": "/nonexistent/file.txt"});
let result = tool.execute(args).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_shell_exec_echo() {
let tool = ShellExec;
let args = json!({"command": "echo 'hello'", "timeout_secs": 5});
let result = tool.execute(args).await.unwrap();
assert_eq!(result.get("exit_code").unwrap(), 0);
assert!(result
.get("stdout")
.unwrap()
.as_str()
.unwrap()
.contains("hello"));
}
#[tokio::test]
async fn test_tool_registry() {
let registry = ToolRegistry::new();
assert!(registry.get("file_read").is_some());
assert!(registry.get("shell_exec").is_some());
assert!(registry.get("nonexistent").is_none());
}
#[tokio::test]
async fn test_file_read_nonexistent_path_returns_error() {
let tool = FileRead::new();
let args = json!({"path": "__selfware_test_nonexistent_12345.txt"});
let result = tool.execute(args).await;
assert!(
result.is_err(),
"Expected Err for non-existent path, got Ok"
);
let err_msg = result.unwrap_err().to_string();
assert!(
err_msg.contains("Failed to read file") || err_msg.contains("No such file"),
"Unexpected error message: {}",
err_msg
);
}
#[tokio::test]
async fn test_file_write_restricted_directory_returns_error() {
use selfware::config::SafetyConfig;
let safety = SafetyConfig {
allowed_paths: vec!["./**".to_string()],
denied_paths: vec!["/etc/**".to_string()],
protected_branches: vec![],
require_confirmation: vec![],
strict_permissions: false,
permissions: vec![],
};
let tool = FileWrite::with_safety_config(safety);
let args = json!({
"path": "/etc/selfware_test_restricted.txt",
"content": "should not be written"
});
let result = tool.execute(args).await;
assert!(
result.is_err(),
"Expected Err when writing to a denied path, got Ok"
);
}
#[tokio::test]
async fn test_file_edit_empty_old_string_returns_error() {
let temp_dir = tempfile::TempDir::new().unwrap();
let file_path = temp_dir.path().join("edit_test.txt");
std::fs::write(&file_path, "Hello, world!").unwrap();
let tool = FileEdit::new();
let args = json!({
"path": file_path.to_str().unwrap(),
"old_str": "",
"new_str": "replacement"
});
let result = tool.execute(args).await;
assert!(result.is_err(), "Expected Err for empty old_str, got Ok");
}
#[tokio::test]
async fn test_directory_tree_nonexistent_directory_returns_error() {
let tool = DirectoryTree::new();
let args = json!({"path": "__selfware_test_nonexistent_dir_98765"});
let result = tool.execute(args).await;
match result {
Err(_) => { }
Ok(val) => {
let entries = val["entries"].as_array();
assert!(
entries.is_none_or(|e| e.is_empty()),
"Expected empty entries for non-existent directory, got: {:?}",
val
);
}
}
}
#[tokio::test]
async fn test_shell_exec_empty_command_returns_error_or_nonzero() {
let tool = ShellExec;
let args = json!({"command": "", "timeout_secs": 5});
let result = tool.execute(args).await;
match result {
Err(_) => { }
Ok(val) => {
assert!(
val.get("exit_code").is_some(),
"Expected exit_code in response, got: {:?}",
val
);
}
}
}
#[tokio::test]
async fn test_file_read_directory_path_returns_error() {
let tool = FileRead::new();
let args = json!({"path": "src"});
let result = tool.execute(args).await;
assert!(
result.is_err(),
"Expected Err when reading a directory path, got Ok"
);
}
#[tokio::test]
async fn test_file_write_oversized_content_returns_error() {
let content = "x".repeat(10 * 1024 * 1024 + 1);
let tool = FileWrite::new();
let args = json!({
"path": "__selfware_test_big_file.txt",
"content": content
});
let result = tool.execute(args).await;
assert!(
result.is_err(),
"Expected Err for oversized content, got Ok"
);
let err_msg = result.unwrap_err().to_string();
assert!(
err_msg.contains("too large"),
"Unexpected error message: {}",
err_msg
);
let _ = std::fs::remove_file("__selfware_test_big_file.txt");
}