use crate::brain::tools::r#trait::{Tool, ToolCapability, ToolExecutionContext};
use crate::brain::tools::web_scrape::WebScrapeTool;
use serde_json::json;
use uuid::Uuid;
fn ctx() -> ToolExecutionContext {
ToolExecutionContext::new(Uuid::new_v4())
}
#[test]
fn advertises_stable_contract() {
let tool = WebScrapeTool::default();
assert_eq!(tool.name(), "web_scrape");
assert_eq!(tool.capabilities(), vec![ToolCapability::Network]);
assert!(!tool.requires_approval());
}
#[test]
fn schema_requires_url_and_offers_modes() {
let schema = WebScrapeTool::default().input_schema();
assert_eq!(schema["required"][0], "url");
let modes = &schema["properties"]["mode"]["enum"];
assert!(modes.as_array().unwrap().iter().any(|m| m == "readable"));
assert!(modes.as_array().unwrap().iter().any(|m| m == "sitemap"));
}
#[tokio::test]
async fn missing_url_is_invalid_input() {
let err = WebScrapeTool::default()
.execute(json!({}), &ctx())
.await
.expect_err("missing url must error");
assert!(err.to_string().to_lowercase().contains("url"));
}
#[tokio::test]
async fn blank_url_is_invalid_input() {
let err = WebScrapeTool::default()
.execute(json!({ "url": " " }), &ctx())
.await
.expect_err("blank url must error");
assert!(err.to_string().to_lowercase().contains("url"));
}
#[tokio::test]
async fn ssrf_blocked_url_fails_without_fetch() {
let result = WebScrapeTool::default()
.execute(json!({ "url": "file:///etc/passwd" }), &ctx())
.await
.expect("execute should return a result, not an error");
assert!(!result.success);
assert!(result.error.unwrap_or(result.output).contains("web_scrape"));
}
#[tokio::test]
async fn localhost_url_is_blocked() {
let result = WebScrapeTool::default()
.execute(json!({ "url": "http://localhost:8080/admin" }), &ctx())
.await
.expect("execute should return a result");
assert!(!result.success);
}