#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::panic
)]
use std::path::PathBuf;
use dci_tool::sandbox::CorpusRoot;
use dci_tool::tools::{FindArgs, ReadArgs, SearchArgs};
use dci_tool::{FindTool, ReadTool, SearchTool};
use rig_core::tool::Tool;
fn corpus() -> CorpusRoot {
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures");
CorpusRoot::new(dir).expect("fixture corpus")
}
#[tokio::test]
async fn search_tool_returns_hits() {
let tool = SearchTool::new(corpus());
let out = tool
.call(SearchArgs {
pattern: "Failed password".to_string(),
path_glob: Some("**/*.log".to_string()),
case_insensitive: None,
context_lines: None,
max_results: None,
})
.await
.expect("search call");
assert!(out.hits.len() >= 3);
assert!(out.hits.iter().all(|h| h.path.ends_with("auth.log")));
}
#[tokio::test]
async fn find_tool_locates_files() {
let tool = FindTool::new(corpus());
let out = tool
.call(FindArgs {
glob: "**/*.md".to_string(),
max_results: None,
})
.await
.expect("find call");
assert!(out.paths.iter().any(|p| p.ends_with("notes.md")));
}
#[tokio::test]
async fn read_tool_rejects_escape() {
let tool = ReadTool::new(corpus());
let err = tool
.call(ReadArgs {
path: "../../Cargo.toml".to_string(),
start_line: None,
line_count: None,
})
.await
.unwrap_err();
assert!(matches!(
err,
dci_tool::DciError::PathEscape { .. } | dci_tool::DciError::NotFound { .. }
));
}