mod common;
#[test]
fn edit_old_new_replaces_exact_match() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "edit.txt", "fn old_name() {}\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"old_name",
"--new",
"new_name",
])
.arg(&path)
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["type"], "edit");
assert_eq!(events[0]["mode"], "exact");
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("new_name"));
assert!(!content.contains("old_name"));
}
#[test]
fn edit_old_not_found_exits_65() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "nofind.txt", "hello world\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"NONEXISTENT",
"--new",
"replacement",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(output.status.code(), Some(65));
}
#[test]
fn edit_after_line_inserts_content() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "lines.txt", "line1\nline2\nline3\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--after-line",
"2",
])
.arg(&path)
.write_stdin("inserted\n")
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(&path).expect("read");
let lines: Vec<&str> = content.lines().collect();
assert_eq!(lines[0], "line1");
assert_eq!(lines[1], "line2");
assert_eq!(lines[2], "inserted");
assert_eq!(lines[3], "line3");
}
#[test]
fn edit_delete_range_removes_lines() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "del.txt", "a\nb\nc\nd\ne\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--delete-range",
"2:4",
])
.arg(&path)
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(&path).expect("read");
let lines: Vec<&str> = content.lines().collect();
assert_eq!(lines, vec!["a", "e"]);
}
#[test]
fn edit_after_match_inserts_after_marker() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(
dir.path(),
"marker.txt",
"use std::io;\nuse std::fs;\n\nfn main() {}\n",
);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--after-match",
"use std::fs;",
])
.arg(&path)
.write_stdin("use std::path::Path;")
.output()
.expect("run");
assert!(output.status.success());
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("use std::fs;\nuse std::path::Path;\n"));
}
#[test]
fn edit_multiple_pairs_without_multi() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "multi_pair.txt", "alpha bravo charlie\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"charlie",
"--new",
"CHARLIE",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("ALPHA"), "first pair should be applied");
assert!(content.contains("CHARLIE"), "second pair should be applied");
assert!(!content.contains("alpha"));
assert!(!content.contains("charlie"));
}
#[test]
fn edit_old_new_mismatch_count() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "mismatch.txt", "content\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"A",
"--new",
"B",
"--old",
"C",
])
.arg(&path)
.output()
.expect("run");
assert!(
!output.status.success(),
"mismatched --old/--new counts should fail"
);
}
#[test]
fn edit_multi_ndjson_stdin() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(
dir.path(),
"multi_stdin.txt",
"line_one\nline_two\nline_three\n",
);
let ndjson = r#"{"op":"exact","old":"line_one","new":"LINE_ONE"}
{"op":"exact","old":"line_three","new":"LINE_THREE"}"#;
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--multi",
])
.arg(&path)
.write_stdin(ndjson)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("LINE_ONE"));
assert!(content.contains("LINE_THREE"));
assert!(content.contains("line_two"));
}
#[test]
fn edit_fuzzy_punctuation_spaces() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(
dir.path(),
"fuzzy_punct.rs",
"fn calculate( items: Vec<i32> ) -> i32 {\n items.iter().sum()\n}\n",
);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"fn calculate(items: Vec<i32>) -> i32 {",
"--new",
"fn calc(items: Vec<i32>) -> i32 {",
"--fuzzy",
"aggressive",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"fuzzy should match despite punctuation whitespace, stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert!(
content.contains("fn calc("),
"replacement should be applied"
);
}
#[test]
fn edit_fuzzy_single_line_block_anchor() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "anchor.rs", "let result = calculate(x, y);\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"let result = calculate( x, y );",
"--new",
"let result = compute(x, y);",
"--fuzzy",
"aggressive",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"fuzzy should match single-line pattern with punctuation spaces, stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("compute"), "replacement should be applied");
assert!(
!content.contains("calculate"),
"original should be replaced"
);
}
#[test]
fn edit_fuzzy_multiline_first_line_variation() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(
dir.path(),
"multi.rs",
"fn process( items: Vec<i32> ) {\n for item in items {\n println!(\"{}\", item);\n }\n}\n",
);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"fn process(items: Vec<i32>) {\n for item in items {\n println!(\"{}\", item);\n }\n}",
"--new",
"fn handle(items: Vec<i32>) {\n for item in items {\n println!(\"{}\", item);\n }\n}",
"--fuzzy",
"aggressive",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"fuzzy should match multiline with first-line whitespace variation, stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert!(
content.contains("fn handle("),
"replacement should be applied"
);
assert!(
!content.contains("fn process("),
"original should be replaced"
);
}
#[test]
fn edit_expect_checksum_rejects_drift() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "edit_drift.txt", "hello world\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"hello",
"--new",
"goodbye",
"--expect-checksum",
"wrong_checksum_value",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(
output.status.code(),
Some(82),
"edit with wrong checksum should exit 82"
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["code"], "STATE_DRIFT");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "hello world\n", "file should not be modified");
}
#[test]
fn edit_expect_checksum_accepts_correct() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "edit_locked.txt", "old_value = 42;\n");
let hash_out = common::atomwrite()
.args(["--workspace", dir.path().to_str().unwrap(), "hash"])
.arg(&path)
.output()
.expect("hash");
let checksum = common::parse_ndjson(&hash_out.stdout)[0]["checksum"]
.as_str()
.expect("checksum")
.to_string();
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"old_value",
"--new",
"new_value",
"--expect-checksum",
&checksum,
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"edit with correct checksum should succeed: {:?}",
output.status
);
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("new_value"));
}
#[test]
fn edit_multi_fuzzy_pair_succeeds() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "g117a.rs", "fn alpha() {}\n let x = 1;\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"let x = 1;",
"--new",
"let y = 2;",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["type"], "edit");
assert_eq!(events[0]["edits"], 2);
assert_eq!(events[0]["mode"], "fuzzy-multi(2)");
assert_eq!(events[0]["fuzzy"], true);
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("ALPHA"));
assert!(content.contains("let y = 2;"));
}
#[test]
fn edit_multi_all_exact_keeps_mode_exact_multi() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "g117b.txt", "alpha\nbeta\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"beta",
"--new",
"BETA",
])
.arg(&path)
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["mode"], "exact-multi(2)");
assert_eq!(events[0]["fuzzy"], false);
}
#[test]
fn edit_multi_success_includes_pair_results() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "g117c.txt", "alpha\nbeta\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"beta",
"--new",
"BETA",
])
.arg(&path)
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["pairs_total"], 2);
let pairs = events[0]["pair_results"]
.as_array()
.expect("pair_results array");
assert_eq!(pairs.len(), 2);
assert_eq!(pairs[0]["index"], 1);
assert_eq!(pairs[0]["matched"], true);
assert_eq!(pairs[0]["strategy"], "exact");
assert_eq!(pairs[1]["index"], 2);
assert_eq!(pairs[1]["matched"], true);
}
#[test]
fn edit_multi_error_reports_failed_pair_index() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "alpha\nbeta\ngamma\n";
let path = common::create_test_file(dir.path(), "g117d.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"NAOEXISTE",
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(output.status.code(), Some(65));
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["error"], true);
assert_eq!(events[0]["code"], "INVALID_INPUT");
assert_eq!(events[0]["failed_pair_index"], 2);
assert_eq!(events[0]["pairs_total"], 2);
let pairs = events[0]["pair_results"]
.as_array()
.expect("pair_results array");
assert_eq!(pairs.len(), 2);
assert_eq!(pairs[0]["matched"], true);
assert_eq!(pairs[1]["matched"], false);
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, before);
}
#[test]
fn edit_multi_fuzzy_off_preserves_exact_behavior() {
let dir = tempfile::tempdir().expect("tempdir");
let before = " let x = 1;\n";
let path = common::create_test_file(dir.path(), "g117e.rs", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--fuzzy",
"off",
"--old",
"let x = 1;",
"--new",
"let y = 2;",
"--old",
"let x",
"--new",
"let z",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(output.status.code(), Some(65));
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, before);
}
#[test]
fn edit_partial_applies_valid_pairs() {
let dir = tempfile::tempdir().expect("tempdir");
let path = common::create_test_file(dir.path(), "g117f.txt", "alpha\nbeta\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--partial",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"NAOEXISTE",
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["edits"], 1);
assert_eq!(events[0]["pairs_total"], 2);
let pairs = events[0]["pair_results"]
.as_array()
.expect("pair_results array");
assert_eq!(pairs.len(), 2);
assert_eq!(pairs[0]["matched"], true);
assert_eq!(pairs[1]["matched"], false);
let content = std::fs::read_to_string(&path).expect("read");
assert!(content.contains("ALPHA"));
}
#[test]
fn edit_partial_zero_matches_exits_1() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "alpha\n";
let path = common::create_test_file(dir.path(), "g117g.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--partial",
"--old",
"NAOEXISTE1",
"--new",
"X",
"--old",
"NAOEXISTE2",
"--new",
"Y",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(output.status.code(), Some(1));
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["code"], "NO_MATCHES");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, before);
}
#[test]
fn edit_partial_dry_run_no_write() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "alpha\nbeta\n";
let path = common::create_test_file(dir.path(), "g117h.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--partial",
"--dry-run",
"--old",
"alpha",
"--new",
"ALPHA",
"--old",
"NAOEXISTE",
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["type"], "plan");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, before);
}
#[test]
fn edit_unicode_old_new_exact_match() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "alpha ção beta ção\n";
let path = common::create_test_file(dir.path(), "g117_unicode.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"ção",
"--new",
"AÇÃO",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "alpha AÇÃO beta ção\n");
}
#[test]
fn edit_crlf_line_endings_preserve_eol_after_replace() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "alpha\r\nbeta\r\ngamma\r\n";
let path = common::create_test_file(dir.path(), "g117_crlf.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"beta",
"--new",
"BETA",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "alpha\r\nBETA\r\ngamma\r\n");
}
#[test]
fn edit_multi_pair_same_old_appears_twice_applies_both() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "foo bar foo\n";
let path = common::create_test_file(dir.path(), "g117_repeat.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"foo",
"--new",
"FOO_A",
"--old",
"foo",
"--new",
"FOO_B",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "FOO_A bar FOO_B\n");
}
#[test]
fn edit_nfc_vs_nfd_does_not_match() {
let dir = tempfile::tempdir().expect("tempdir");
let nfd_a = "a\u{0303}";
assert_eq!(nfd_a.len(), 3, "NFD 'ã' must be 3 bytes");
let before = format!("José{nfd_a} Silva\n");
let path = common::create_test_file(dir.path(), "g117_nfd.txt", &before);
let nfc_a = "ã";
assert_eq!(nfc_a.len(), 2, "NFC 'ã' must be 2 bytes");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
nfc_a,
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(output.status.code(), Some(65));
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["error"], true);
assert_eq!(events[0]["code"], "INVALID_INPUT");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, before);
}
#[test]
fn edit_old_only_whitespace_matches_first_run_exact() {
let dir = tempfile::tempdir().expect("tempdir");
let before = " hello world \n";
let path = common::create_test_file(dir.path(), "g117_ws.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
" ",
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["fuzzy"], false);
assert_eq!(events[0]["strategy"], "exact");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "Xhello world \n");
}
#[test]
fn edit_new_empty_string_deletion_removes_only_match() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "keep this, remove this, keep this too\n";
let path = common::create_test_file(dir.path(), "g117_del.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"remove this, ",
"--new",
"",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "keep this, keep this too\n");
assert!(!content.contains("remove"));
assert!(!content.contains(", ,"));
}
#[test]
fn edit_utf8_bom_is_stripped_before_match() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "\u{FEFF}hello\n";
let path = common::create_test_file(dir.path(), "g117_bom.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"hello",
"--new",
"world",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["bytes_before"], 6);
assert_eq!(events[0]["strategy"], "exact");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "world\n");
assert!(!content.starts_with('\u{FEFF}'));
}
#[test]
fn edit_partial_zero_applicable_pairs_exits_no_matches() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "foo bar\n";
let path = common::create_test_file(dir.path(), "g117_pz.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--partial",
"--old",
"NAOEXISTE_ZZ",
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert_eq!(output.status.code(), Some(1));
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["code"], "NO_MATCHES");
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, before);
}
#[test]
fn edit_one_token_drift_in_block_matches_via_context_aware_fallback() {
let dir = tempfile::tempdir().expect("tempdir");
let before = "alpha bravo charlie delta\n";
let path = common::create_test_file(dir.path(), "g117_thr.txt", before);
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"alpha bravo echo delta",
"--new",
"X",
])
.arg(&path)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["fuzzy"], true);
let strategy = events[0]["strategy"].as_str().expect("strategy");
assert!(
strategy == "block_anchor" || strategy == "context_aware" || strategy == "context_aware_jw",
"expected block_anchor, context_aware, or context_aware_jw, got {strategy}"
);
if let Some(sim) = events[0]["similarity"].as_f64() {
assert!(
(0.70..=0.95).contains(&sim),
"similarity {sim} outside expected band [0.70, 0.95]"
);
}
let content = std::fs::read_to_string(&path).expect("read");
assert_eq!(content, "X\n");
}
#[test]
fn v0_1_20_edit_partial_single_pair_unmatched_returns_no_matches() {
let dir = tempfile::tempdir().expect("tempdir");
common::create_test_file(dir.path(), "foo.txt", "hello world\n");
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"edit",
"--old",
"NONEXISTENT_TEXT",
"--new",
"X",
"--partial",
])
.arg(dir.path().join("foo.txt"))
.output()
.expect("run");
assert_eq!(
output.status.code(),
Some(1),
"single-pair --partial + no match must be NoMatches (exit 1)"
);
let events = common::parse_ndjson(&output.stdout);
assert_eq!(events[0]["code"], "NO_MATCHES");
let content = std::fs::read_to_string(dir.path().join("foo.txt")).unwrap();
assert_eq!(content, "hello world\n", "no write on NoMatches");
}
#[test]
fn v0_1_20_diff_algorithm_myers_runs() {
let dir = tempfile::tempdir().expect("tempdir");
let a = dir.path().join("a.txt");
let b = dir.path().join("b.txt");
std::fs::write(&a, "the quick brown fox\n").unwrap();
std::fs::write(&b, "the quick red fox\n").unwrap();
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"diff",
"--algorithm",
"myers",
])
.arg(&a)
.arg(&b)
.output()
.expect("run");
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn v0_1_20_diff_algorithm_lcs_on_identical_files() {
let dir = tempfile::tempdir().expect("tempdir");
let a = dir.path().join("a.txt");
let b = dir.path().join("b.txt");
std::fs::write(&a, "abc\n").unwrap();
std::fs::write(&b, "abc\n").unwrap();
let output = common::atomwrite()
.args([
"--workspace",
dir.path().to_str().unwrap(),
"diff",
"--algorithm",
"lcs",
"--stat",
])
.arg(&a)
.arg(&b)
.output()
.expect("run");
assert!(output.status.success());
let events = common::parse_ndjson(&output.stdout);
assert!(events[0]["identical"].as_bool().unwrap());
}