use crate::snip::snippet::{Boundary, BoundaryMode, Snippet, SnippetError};
use crate::snip::Target;
use crate::Rope;
#[test]
fn test_replace_insert_at_position_exclude() {
let rope = Rope::from_str("hello world");
let target = Target::Char(4); let boundary = Boundary::new(target, BoundaryMode::Exclude); let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, ", beautiful").unwrap();
assert_eq!(result.to_string(), "hello, beautiful world");
}
#[test]
fn test_replace_insert_at_position_include() {
let rope = Rope::from_str("hello world");
let target = Target::Char(5); let boundary = Boundary::new(target, BoundaryMode::Include); let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, ", beautiful ").unwrap();
assert_eq!(result.to_string(), "hello, beautiful world");
}
#[test]
fn test_replace_delete_range() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let target = Target::Line(1); let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "").unwrap();
assert_eq!(result.to_string(), "line1\nline3\n");
}
#[test]
fn test_replace_edit_existing_text() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let target = Target::Line(1);
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "MODIFIED\n").unwrap();
assert_eq!(result.to_string(), "line1\nMODIFIED\nline3\n");
}
#[test]
fn test_replace_between_boundaries() {
let rope = Rope::from_str("<!-- start -->old content<!-- end -->");
let start_target = Target::Literal("<!-- start -->".to_string());
let end_target = Target::Literal("<!-- end -->".to_string());
let start_boundary = Boundary::new(start_target, BoundaryMode::Exclude);
let end_boundary = Boundary::new(end_target, BoundaryMode::Exclude);
let snippet = Snippet::Between {
start: start_boundary,
end: end_boundary,
};
let result = snippet.replace(&rope, "new content").unwrap();
assert_eq!(result.to_string(), "<!-- start -->new content<!-- end -->");
}
#[test]
fn test_replace_from_boundary_to_eof_exclude() {
let rope = Rope::from_str("keep this\nreplace from here\nand this too\n");
let target = Target::Literal("\nreplace from here".to_string());
let boundary = Boundary::new(target, BoundaryMode::Exclude);
let snippet = Snippet::From(boundary);
let result = snippet.replace(&rope, "\nnew ending").unwrap();
assert_eq!(
result.to_string(),
"keep this\nreplace from here\nnew ending"
);
}
#[test]
fn test_replace_from_boundary_to_eof_include() {
let rope = Rope::from_str("keep this\nreplace from here\nand this too\n");
let target = Target::Literal("replace from here".to_string());
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::From(boundary);
let result = snippet.replace(&rope, "\nnew ending").unwrap();
assert_eq!(
result.to_string(),
"keep this\nreplace from here\nnew ending"
);
}
#[test]
fn test_replace_to_boundary_from_bof() {
let rope = Rope::from_str("replace this\nand this\nkeep from here");
let target = Target::Literal("keep from here".to_string());
let boundary = Boundary::new(target, BoundaryMode::Exclude);
let snippet = Snippet::To(boundary);
let result = snippet.replace(&rope, "new beginning\n").unwrap();
assert_eq!(result.to_string(), "new beginning\nkeep from here");
}
#[test]
fn test_replace_entire_rope() {
let rope = Rope::from_str("old content\nline 2\nline 3");
let snippet = Snippet::All;
let result = snippet.replace(&rope, "completely new").unwrap();
assert_eq!(result.to_string(), "completely new");
}
#[test]
fn test_replace_multiline_content() {
let rope =
Rope::from_str("header\n<!-- start -->\nold line 1\nold line 2\n<!-- end -->\nfooter");
let start_target = Target::Literal("<!-- start -->".to_string());
let end_target = Target::Literal("<!-- end -->".to_string());
let start_boundary = Boundary::new(start_target, BoundaryMode::Exclude);
let end_boundary = Boundary::new(end_target, BoundaryMode::Exclude);
let snippet = Snippet::Between {
start: start_boundary,
end: end_boundary,
};
let replacement = "\nnew line 1\nnew line 2\n";
let result = snippet.replace(&rope, replacement).unwrap();
assert_eq!(
result.to_string(),
"header\n<!-- start -->\nnew line 1\nnew line 2\n<!-- end -->\nfooter"
);
}
#[test]
fn test_replace_with_unicode() {
let rope = Rope::from_str("hello world");
let target = Target::Literal("world".to_string());
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "🌍 café").unwrap();
assert_eq!(result.to_string(), "hello 🌍 café");
let expected_chars = "hello 🌍 café".chars().count();
assert_eq!(result.len_chars(), expected_chars);
}
#[test]
fn test_replace_null_byte_rejection() {
let rope = Rope::from_str("hello world");
let target = Target::Literal("world".to_string());
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "bad\0string");
assert!(matches!(result, Err(SnippetError::InvalidUtf8(_))));
}
#[test]
fn test_replace_empty_rope() {
let rope = Rope::from_str("");
let snippet = Snippet::All;
let result = snippet.replace(&rope, "new content").unwrap();
assert_eq!(result.to_string(), "new content");
}
#[test]
fn test_replace_preserves_surrounding_text() {
let rope = Rope::from_str("prefix [REPLACE ME] suffix");
let target = Target::Literal("[REPLACE ME]".to_string());
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "[DONE]").unwrap();
assert_eq!(result.to_string(), "prefix [DONE] suffix");
let prefix = result.slice(0..7).to_string();
assert_eq!(prefix, "prefix ");
let suffix_start = result.len_chars() - 7;
let suffix = result.slice(suffix_start..result.len_chars()).to_string();
assert_eq!(suffix, " suffix");
}
#[cfg(feature = "regex")]
#[test]
fn test_replace_regex_pattern() {
let rope = Rope::from_str("version 1.2.3 is old");
let target = Target::pattern(r"\d+\.\d+\.\d+").unwrap();
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "2.0.0").unwrap();
assert_eq!(result.to_string(), "version 2.0.0 is old");
}