use super::*;
use crate::brain::tools::r#trait::ToolExecutionContext;
use tempfile::TempDir;
use uuid::Uuid;
fn ctx() -> ToolExecutionContext {
ToolExecutionContext::new(Uuid::new_v4())
}
fn tool() -> LoadBrainFileTool {
LoadBrainFileTool
}
#[test]
fn test_tool_name_and_approval() {
let t = tool();
assert_eq!(t.name(), "load_brain_file");
assert!(!t.requires_approval());
}
#[test]
fn test_description_mentions_key_files() {
let t = tool();
let desc = t.description();
assert!(
desc.contains("MEMORY.md"),
"description should mention MEMORY.md"
);
assert!(
desc.contains("USER.md"),
"description should mention USER.md"
);
assert!(
desc.contains("all"),
"description should mention the 'all' option"
);
}
#[test]
fn test_input_schema_requires_name() {
let schema = tool().input_schema();
let required = schema["required"].as_array().unwrap();
assert!(
required.iter().any(|v| v.as_str() == Some("name")),
"schema must require 'name'"
);
}
#[tokio::test]
async fn test_empty_name_returns_error() {
let result = tool()
.execute(serde_json::json!({"name": ""}), &ctx())
.await
.unwrap();
assert!(!result.success, "empty name must fail");
assert!(
result.error.unwrap().contains("required"),
"error must say 'required'"
);
}
#[tokio::test]
async fn test_path_traversal_rejected() {
let result = tool()
.execute(serde_json::json!({"name": "../../etc/passwd"}), &ctx())
.await
.unwrap();
assert!(!result.success, "path traversal must fail");
let err = result.error.unwrap();
assert!(
err.contains("Invalid brain file name"),
"error must say 'Invalid brain file name', got: {}",
err
);
}
#[tokio::test]
async fn test_slash_in_name_rejected() {
let result = tool()
.execute(serde_json::json!({"name": "sub/file.md"}), &ctx())
.await
.unwrap();
assert!(!result.success, "slash in name must fail");
assert!(result.error.unwrap().contains("Invalid brain file name"));
}
#[tokio::test]
async fn test_custom_user_file_accepted() {
let result = tool()
.execute(serde_json::json!({"name": "VOICE.md"}), &ctx())
.await
.unwrap();
assert!(
result.success,
"custom user file must not be rejected, got error: {:?}",
result.error
);
}
#[tokio::test]
async fn test_agent_retrieves_user_file_on_demand() {
let dir = TempDir::new().unwrap();
std::fs::write(dir.path().join("USER.md"), "Name: Alice\nRole: Engineer").unwrap();
let content = std::fs::read_to_string(dir.path().join("USER.md")).unwrap();
assert!(content.contains("Alice"));
let result = tool()
.execute(serde_json::json!({"name": "USER.md"}), &ctx())
.await
.unwrap();
assert!(
result.success || !result.output.is_empty(),
"must return something — never silent or panicking"
);
}
#[tokio::test]
async fn test_agent_retrieves_memory_file_on_demand() {
let result = tool()
.execute(serde_json::json!({"name": "MEMORY.md"}), &ctx())
.await
.unwrap();
assert!(
result.success || !result.output.is_empty(),
"MEMORY.md: must return content or graceful not-found"
);
}
#[tokio::test]
async fn test_agents_md_loads_on_demand() {
let result = tool()
.execute(serde_json::json!({"name": "AGENTS.md"}), &ctx())
.await
.unwrap();
assert!(result.success || !result.output.is_empty());
}
#[tokio::test]
async fn test_security_md_loads_on_demand() {
let result = tool()
.execute(serde_json::json!({"name": "SECURITY.md"}), &ctx())
.await
.unwrap();
assert!(result.success || !result.output.is_empty());
}
#[tokio::test]
async fn test_missing_file_is_graceful_not_a_crash() {
let result = tool()
.execute(serde_json::json!({"name": "HEARTBEAT.md"}), &ctx())
.await
.unwrap();
assert!(
result.success || !result.output.is_empty(),
"missing file must return a graceful message, not panic"
);
if !result.success {
if let Some(err) = result.error {
assert!(!err.is_empty());
}
}
}
#[tokio::test]
async fn test_all_loads_all_available_files() {
let result = tool()
.execute(serde_json::json!({"name": "all"}), &ctx())
.await
.unwrap();
assert!(
result.success,
"load_all must always succeed (even if nothing found)"
);
}
#[tokio::test]
async fn test_name_matching_is_case_insensitive() {
let lower = tool()
.execute(serde_json::json!({"name": "memory.md"}), &ctx())
.await
.unwrap();
let upper = tool()
.execute(serde_json::json!({"name": "MEMORY.md"}), &ctx())
.await
.unwrap();
assert_eq!(
lower.success, upper.success,
"case should not affect whether the file is recognised as valid"
);
}
#[tokio::test]
async fn test_returned_content_includes_section_header() {
let result = tool()
.execute(serde_json::json!({"name": "MEMORY.md"}), &ctx())
.await
.unwrap();
if result.success && result.output.contains("---") {
assert!(
result.output.contains("MEMORY.md"),
"output should contain the file name as a section header"
);
}
}