use crate::brain::tools::edit::EditTool;
use crate::brain::tools::write::WriteTool;
use crate::brain::tools::{Tool, ToolExecutionContext};
use serde_json::json;
use tempfile::TempDir;
use uuid::Uuid;
#[tokio::test]
async fn write_file_rejects_protected_brain_file() {
let temp = TempDir::new().unwrap();
let brain_path = temp.path().join("MEMORY.md");
std::fs::write(&brain_path, "original brain content").unwrap();
let tool = WriteTool;
let context =
ToolExecutionContext::new(Uuid::new_v4()).with_working_directory(temp.path().to_path_buf());
let result = tool
.execute(
json!({
"path": brain_path.to_str().unwrap(),
"content": ""
}),
&context,
)
.await
.unwrap();
assert!(
!result.success,
"write_file must refuse protected brain file"
);
let err = result.error.unwrap_or_default();
assert!(
err.contains("write_opencrabs_file"),
"error must route caller to write_opencrabs_file, got: {err}"
);
let still_there = std::fs::read_to_string(&brain_path).unwrap();
assert_eq!(
still_there, "original brain content",
"brain file content must be untouched after rejection"
);
}
#[tokio::test]
async fn edit_file_rejects_protected_brain_file() {
let temp = TempDir::new().unwrap();
let brain_path = temp.path().join("SOUL.md");
std::fs::write(&brain_path, "original soul content\nline two").unwrap();
let tool = EditTool;
let context =
ToolExecutionContext::new(Uuid::new_v4()).with_working_directory(temp.path().to_path_buf());
let result = tool
.execute(
json!({
"path": brain_path.to_str().unwrap(),
"operation": "replace",
"old_text": "original soul content",
"new_text": ""
}),
&context,
)
.await
.unwrap();
assert!(
!result.success,
"edit_file must refuse protected brain file"
);
let err = result.error.unwrap_or_default();
assert!(
err.contains("write_opencrabs_file"),
"error must route caller to write_opencrabs_file, got: {err}"
);
let still_there = std::fs::read_to_string(&brain_path).unwrap();
assert_eq!(
still_there, "original soul content\nline two",
"brain file content must be untouched after rejection"
);
}
#[tokio::test]
async fn write_file_allows_non_brain_files_in_same_dir() {
let temp = TempDir::new().unwrap();
let non_brain_path = temp.path().join("notes.md");
let tool = WriteTool;
let context =
ToolExecutionContext::new(Uuid::new_v4()).with_working_directory(temp.path().to_path_buf());
let result = tool
.execute(
json!({
"path": non_brain_path.to_str().unwrap(),
"content": "scratch notes"
}),
&context,
)
.await
.unwrap();
assert!(result.success, "non-brain files must still write normally");
let written = std::fs::read_to_string(&non_brain_path).unwrap();
assert_eq!(written, "scratch notes");
}
#[tokio::test]
async fn write_file_rejects_every_protected_brain_file() {
let names = [
"SOUL.md",
"USER.md",
"AGENTS.md",
"TOOLS.md",
"CODE.md",
"SECURITY.md",
"MEMORY.md",
"BOOT.md",
];
for name in names {
let temp = TempDir::new().unwrap();
let path = temp.path().join(name);
std::fs::write(&path, "x").unwrap();
let tool = WriteTool;
let context = ToolExecutionContext::new(Uuid::new_v4())
.with_working_directory(temp.path().to_path_buf());
let result = tool
.execute(
json!({ "path": path.to_str().unwrap(), "content": "y" }),
&context,
)
.await
.unwrap();
assert!(!result.success, "write_file must refuse {name}");
assert_eq!(
std::fs::read_to_string(&path).unwrap(),
"x",
"{name} content must survive rejection"
);
}
}