95 lines
2.5 KiB
Rust
95 lines
2.5 KiB
Rust
use cassady::access::AccessMode;
|
|
use cassady::tools::{self, ToolContext};
|
|
use serde_json::json;
|
|
use tempfile::tempdir;
|
|
|
|
fn ctx(root: &std::path::Path, mode: AccessMode) -> ToolContext {
|
|
ToolContext {
|
|
mode,
|
|
cwd: root.to_path_buf(),
|
|
read_only_root: root.to_path_buf(),
|
|
model_result_limit: 100_000,
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn read_only_rejects_write_and_path_escape() {
|
|
let dir = tempdir().unwrap();
|
|
let outside = tempdir().unwrap();
|
|
std::fs::write(outside.path().join("x.txt"), "secret").unwrap();
|
|
|
|
let out = tools::execute(
|
|
"write",
|
|
json!({"path":"x.txt", "content":"hi"}),
|
|
&ctx(dir.path(), AccessMode::ReadOnly),
|
|
)
|
|
.await;
|
|
assert!(!out.ok);
|
|
|
|
let out = tools::execute(
|
|
"read",
|
|
json!({"files":[{"path": outside.path().join("x.txt").display().to_string()}]}),
|
|
&ctx(dir.path(), AccessMode::ReadOnly),
|
|
)
|
|
.await;
|
|
assert!(!out.ok);
|
|
assert!(out.content.contains("escapes read-only root"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn read_and_grep_work() {
|
|
let dir = tempdir().unwrap();
|
|
std::fs::write(dir.path().join("a.txt"), "one\ntwo needle\nthree\n").unwrap();
|
|
let context = ctx(dir.path(), AccessMode::ReadOnly);
|
|
|
|
let read = tools::execute(
|
|
"read",
|
|
json!({"files":[{"path":"a.txt", "lines":"2-3"}]}),
|
|
&context,
|
|
)
|
|
.await;
|
|
assert!(read.ok);
|
|
assert!(read.content.contains("two needle"));
|
|
assert!(!read.content.contains("one"));
|
|
|
|
let grep = tools::execute(
|
|
"grep",
|
|
json!({"query":"needle", "paths":["."], "case_sensitive": true}),
|
|
&context,
|
|
)
|
|
.await;
|
|
assert!(grep.ok);
|
|
assert!(grep.content.contains("a.txt:2"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn edit_is_exact_and_atomic_on_validation_failure() {
|
|
let dir = tempdir().unwrap();
|
|
std::fs::write(dir.path().join("a.txt"), "alpha\nbeta\ngamma\n").unwrap();
|
|
let context = ctx(dir.path(), AccessMode::FullAccess);
|
|
|
|
let ok = tools::execute(
|
|
"edit",
|
|
json!({"path":"a.txt", "edits":[{"old_text":"beta", "new_text":"BETA"}]}),
|
|
&context,
|
|
)
|
|
.await;
|
|
assert!(ok.ok);
|
|
assert_eq!(
|
|
std::fs::read_to_string(dir.path().join("a.txt")).unwrap(),
|
|
"alpha\nBETA\ngamma\n"
|
|
);
|
|
|
|
let bad = tools::execute(
|
|
"edit",
|
|
json!({"path":"a.txt", "edits":[{"old_text":"missing", "new_text":"NOPE"}]}),
|
|
&context,
|
|
)
|
|
.await;
|
|
assert!(!bad.ok);
|
|
assert_eq!(
|
|
std::fs::read_to_string(dir.path().join("a.txt")).unwrap(),
|
|
"alpha\nBETA\ngamma\n"
|
|
);
|
|
}
|