mod common;
#[test]
fn replace_modifies_file_atomically() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "rep.txt", "old_api(x)\nold_api(y)\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"replace",
"old_api",
"new_api",
])
.arg(dir.path())
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
let replaced: Vec<_> = events.iter().filter(|e| e["type"] == "replaced").collect();
assert!(!replaced.is_empty());
assert_eq!(replaced[0]["replacements"], 2);
assert!(replaced[0]["checksum_before"].is_string());
assert!(replaced[0]["checksum_after"].is_string());
let content = std::fs::read_to_string(dir.path().join("rep.txt")).expect("read");
assert!(content.contains("new_api"));
assert!(!content.contains("old_api"));
}
#[test]
fn replace_dry_run_does_not_modify() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "dry.txt", "original_text\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"replace",
"--dry-run",
"original_text",
"new_text",
])
.arg(dir.path())
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(dir.path().join("dry.txt")).expect("read");
assert_eq!(content, "original_text\n", "file should not be modified");
let events = common::parse_ndjson(&output.stdout);
let plans: Vec<_> = events.iter().filter(|e| e["type"] == "plan").collect();
assert!(!plans.is_empty());
}
#[test]
fn replace_literal_escapes_regex_chars() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "regex.txt", "fn foo() -> Result<(), Error>\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"replace",
"--literal",
"Result<(), Error>",
"anyhow::Result<()>",
])
.arg(dir.path())
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(dir.path().join("regex.txt")).expect("read");
assert!(content.contains("anyhow::Result<()>"));
}
#[test]
fn replace_preview_shows_diff_without_writing() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "prev.txt", "hello world\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"replace",
"--preview",
"hello",
"goodbye",
])
.arg(dir.path())
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(dir.path().join("prev.txt")).expect("read");
assert_eq!(content, "hello world\n", "file should not be modified");
let events = common::parse_ndjson(&output.stdout);
let previews: Vec<_> = events.iter().filter(|e| e["type"] == "preview").collect();
assert!(!previews.is_empty());
assert!(previews[0]["diff"].is_string());
}
#[test]
fn replace_max_replacements_limits_count() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "max.txt", "aaa\naaa\naaa\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"replace",
"--max-replacements",
"1",
"aaa",
"bbb",
])
.arg(dir.path())
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(dir.path().join("max.txt")).expect("read");
let bbb_count = content.matches("bbb").count();
let aaa_count = content.matches("aaa").count();
assert_eq!(bbb_count, 1);
assert_eq!(aaa_count, 2);
}
#[test]
fn replace_summary_has_correct_counts() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "a.txt", "target\n");
common::create_test_file(dir.path(), "b.txt", "no match\n");
common::create_test_file(dir.path(), "c.txt", "target target\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"replace",
"target",
"replaced",
])
.arg(dir.path())
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
let summary = events
.iter()
.find(|e| e["type"] == "summary")
.expect("summary");
assert!(summary["files_visited"].as_u64().unwrap() >= 3);
assert!(summary["total_replacements"].as_u64().unwrap() >= 3);
}