diff --git a/src/ed_diff.rs b/src/ed_diff.rs index 81ddfb4..f1ac5cd 100644 --- a/src/ed_diff.rs +++ b/src/ed_diff.rs @@ -126,6 +126,7 @@ pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Result, match (expected_count, actual_count) { (0, 0) => unreachable!(), (0, _) => writeln!(&mut output, "{}a", line_number_expected - 1).unwrap(), + (1, 0) => writeln!(&mut output, "{line_number_expected}d").unwrap(), (_, 0) => writeln!( &mut output, "{},{}d", @@ -180,6 +181,12 @@ mod tests { assert_eq!(diff, expected.as_bytes()); } + #[test] + fn test_single_line_deleted() { + let diff = diff(b"a\nb\n", b"a\n", &Params::default()).unwrap(); + assert_eq!(diff, b"2d\n"); + } + #[test] fn test_permutations() { let target = "target/ed-diff/"; diff --git a/src/normal_diff.rs b/src/normal_diff.rs index 652dc84..c930b95 100644 --- a/src/normal_diff.rs +++ b/src/normal_diff.rs @@ -133,6 +133,13 @@ pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec { let actual_count = result.actual.len(); match (expected_count, actual_count) { (0, 0) => unreachable!(), + (0, 1) => writeln!( + // exactly one line added + &mut output, + "{}a{line_number_actual}", + line_number_expected - 1 + ) + .unwrap(), (0, _) => writeln!( // 'a' stands for "Add lines" &mut output, @@ -142,6 +149,13 @@ pub fn diff(expected: &[u8], actual: &[u8], params: &Params) -> Vec { line_number_actual + actual_count - 1 ) .unwrap(), + (1, 0) => writeln!( + // exactly one line deleted + &mut output, + "{line_number_expected}d{}", + line_number_actual - 1 + ) + .unwrap(), (_, 0) => writeln!( // 'd' stands for "Delete lines" &mut output, @@ -228,6 +242,15 @@ mod tests { assert_eq!(diff, expected); } + #[test] + fn test_single_line_added_or_deleted() { + // A one-line range is written as a single number, as for c. + let added = diff(b"a\n", b"a\nb\n", &Params::default()); + assert_eq!(added, b"1a2\n> b\n".to_vec()); + let deleted = diff(b"a\nb\n", b"a\n", &Params::default()); + assert_eq!(deleted, b"2d1\n< b\n".to_vec()); + } + #[test] fn test_permutations() { let target = "target/normal-diff/"; diff --git a/tests/by-util/test_diff.rs b/tests/by-util/test_diff.rs index fbdd494..bd408c9 100644 --- a/tests/by-util/test_diff.rs +++ b/tests/by-util/test_diff.rs @@ -288,3 +288,51 @@ fn sdiff_gutter_marker_column() -> Result<(), Box> { Ok(()) } + +#[test] +fn normal_format_single_line_ranges() -> Result<(), Box> { + let tmp_dir = tempdir()?; + let old = tmp_dir.path().join("old"); + let new = tmp_dir.path().join("new"); + std::fs::write(&old, "north\neast\nsouth\nwest\n")?; + std::fs::write(&new, "north\nsouth\nwest\nup\ndown\n")?; + + let mut cmd = cargo_bin_cmd!("diffutils"); + cmd.arg("diff").arg(&old).arg(&new); + cmd.assert() + .code(predicate::eq(1)) + .stdout("2d1\n< east\n4a4,5\n> up\n> down\n"); + + let mut cmd = cargo_bin_cmd!("diffutils"); + cmd.arg("diff").arg("/dev/null").arg(&old); + if cfg!(unix) { + cmd.assert() + .code(predicate::eq(1)) + .stdout("0a1,4\n> north\n> east\n> south\n> west\n"); + } + + std::fs::write(&new, "north\neast\nsouth\nwest\nup\n")?; + let mut cmd = cargo_bin_cmd!("diffutils"); + cmd.arg("diff").arg(&old).arg(&new); + cmd.assert().code(predicate::eq(1)).stdout("4a5\n> up\n"); + Ok(()) +} + +#[test] +fn ed_format_single_line_deletions() -> Result<(), Box> { + let tmp_dir = tempdir()?; + let old = tmp_dir.path().join("old"); + let new = tmp_dir.path().join("new"); + std::fs::write(&old, "red\norange\nyellow\ngreen\nblue\n")?; + std::fs::write(&new, "red\norange\nyellow\nblue\n")?; + + let mut cmd = cargo_bin_cmd!("diffutils"); + cmd.arg("diff").arg("-e").arg(&old).arg(&new); + cmd.assert().code(predicate::eq(1)).stdout("4d\n"); + + std::fs::write(&new, "red\nblue\n")?; + let mut cmd = cargo_bin_cmd!("diffutils"); + cmd.arg("diff").arg("-e").arg(&old).arg(&new); + cmd.assert().code(predicate::eq(1)).stdout("2,4d\n"); + Ok(()) +}