use crate::snip::snippet::{Boundary, BoundaryMode, Extent, Snippet};
use crate::snip::Target;
use textum::Rope;
#[test]
fn test_workflow_comment_block_replacement() {
let rope = Rope::from_str(
"<!DOCTYPE html>\n<!-- content -->\n<p>Old paragraph</p>\n<!-- /content -->\n</html>"
);
let start_target = Target::Literal("<!-- content -->".to_string());
let end_target = Target::Literal("<!-- /content -->".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 new_content = "\n<p>New paragraph</p>\n<p>Second paragraph</p>\n";
let result = snippet.replace(&rope, new_content).unwrap();
assert_eq!(
result.to_string(),
"<!DOCTYPE html>\n<!-- content -->\n<p>New paragraph</p>\n<p>Second paragraph</p>\n<!-- /content -->\n</html>"
);
}
#[test]
fn test_workflow_line_range_deletion() {
let rope = Rope::from_str("line 1\nline 2\nline 3\nline 4\nline 5\n");
let start_target = Target::Line(1);
let end_target = Target::Line(3);
let start_boundary = Boundary::new(start_target, BoundaryMode::Include);
let end_boundary = Boundary::new(end_target, BoundaryMode::Exclude);
let snippet = Snippet::Between {
start: start_boundary,
end: end_boundary,
};
let result = snippet.replace(&rope, "").unwrap();
assert_eq!(result.to_string(), "line 1\nline 4\nline 5\n");
}
#[test]
fn test_workflow_insert_at_end_of_line() {
let rope = Rope::from_str("def function():\n pass\n");
let target = Target::Line(0);
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "def function():\n \"\"\"Docstring here.\"\"\"\n").unwrap();
assert_eq!(result.to_string(), "def function():\n \"\"\"Docstring here.\"\"\"\n pass\n");
}
#[test]
fn test_workflow_multiple_replacements() {
let rope1 = Rope::from_str("Step 1: TODO\nStep 2: TODO\nStep 3: TODO\n");
let target1 = Target::Literal("Step 1: TODO".to_string());
let boundary1 = Boundary::new(target1, BoundaryMode::Include);
let snippet1 = Snippet::At(boundary1);
let rope2 = snippet1.replace(&rope1, "Step 1: Complete").unwrap();
assert_eq!(rope2.to_string(), "Step 1: Complete\nStep 2: TODO\nStep 3: TODO\n");
let target2 = Target::Literal("Step 2: TODO".to_string());
let boundary2 = Boundary::new(target2, BoundaryMode::Include);
let snippet2 = Snippet::At(boundary2);
let rope3 = snippet2.replace(&rope2, "Step 2: In Progress").unwrap();
assert_eq!(rope3.to_string(), "Step 1: Complete\nStep 2: In Progress\nStep 3: TODO\n");
let target3 = Target::Literal("Step 3: TODO".to_string());
let boundary3 = Boundary::new(target3, BoundaryMode::Include);
let snippet3 = Snippet::At(boundary3);
let rope4 = snippet3.replace(&rope3, "Step 3: Complete").unwrap();
assert_eq!(rope4.to_string(), "Step 1: Complete\nStep 2: In Progress\nStep 3: Complete\n");
}
#[test]
fn test_workflow_nested_boundaries() {
let rope = Rope::from_str(
"<div>\n <section>\n <p>inner content</p>\n </section>\n</div>"
);
let outer_start = Target::Literal("<section>".to_string());
let outer_end = Target::Literal("</section>".to_string());
let outer_start_boundary = Boundary::new(outer_start, BoundaryMode::Exclude);
let outer_end_boundary = Boundary::new(outer_end, BoundaryMode::Exclude);
let outer_snippet = Snippet::Between {
start: outer_start_boundary,
end: outer_end_boundary,
};
let section_content = rope
.slice(outer_snippet.resolve(&rope).unwrap().start..outer_snippet.resolve(&rope).unwrap().end)
.to_string();
let inner_rope = Rope::from_str(§ion_content);
let inner_target = Target::Literal("<p>inner content</p>".to_string());
let inner_boundary = Boundary::new(inner_target, BoundaryMode::Include);
let inner_snippet = Snippet::At(inner_boundary);
let new_section_content = inner_snippet.replace(&inner_rope, "<p>updated content</p>").unwrap();
let final_result = outer_snippet.replace(&rope, &new_section_content.to_string()).unwrap();
assert_eq!(
final_result.to_string(),
"<div>\n <section>\n <p>updated content</p>\n </section>\n</div>"
);
}
#[test]
fn test_workflow_extend_matching_pattern() {
let rope = Rope::from_str("data:\nline 1\nline 2\nline 3\nline 4\nrest of file");
let target = Target::Literal("data:".to_string());
let newline_target = Target::Literal("\n".to_string());
let boundary = Boundary::new(
target,
BoundaryMode::Extend(Extent::Matching(3, newline_target))
);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "\nreplaced data\n").unwrap();
assert_eq!(result.to_string(), "data:\nreplaced data\nline 4\nrest of file");
}
#[test]
fn test_workflow_position_based_editing() {
let rope = Rope::from_str("line 1\nline 2\nline 3\n");
let target = Target::Position { line: 2, col: 6 };
let boundary = Boundary::new(target, BoundaryMode::Exclude);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "X").unwrap();
assert_eq!(result.to_string(), "line 1\nline X2\nline 3\n");
}
#[cfg(feature = "regex")]
#[test]
fn test_workflow_regex_boundary_replacement() {
let rope = Rope::from_str("Config: version=1.2.3, status=active, mode=production");
let target = Target::pattern(r"version=\d+\.\d+\.\d+").unwrap();
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.replace(&rope, "version=2.0.0").unwrap();
assert_eq!(result.to_string(), "Config: version=2.0.0, status=active, mode=production");
}
#[test]
fn test_workflow_edge_case_single_char_rope() {
let rope = Rope::from_str("x");
let snippet_all = Snippet::All;
let result1 = snippet_all.replace(&rope, "y").unwrap();
assert_eq!(result1.to_string(), "y");
let target_char = Target::Char(0);
let boundary_exclude = Boundary::new(target_char, BoundaryMode::Exclude);
let snippet_insert = Snippet::At(boundary_exclude);
let result2 = snippet_insert.replace(&rope, "a").unwrap();
assert_eq!(result2.to_string(), "ax");
let boundary_include = Boundary::new(Target::Char(0), BoundaryMode::Include);
let snippet_delete = Snippet::At(boundary_include);
let result3 = snippet_delete.replace(&rope, "").unwrap();
assert_eq!(result3.to_string(), "");
}
#[test]
fn test_workflow_edge_case_eof_operations() {
let rope = Rope::from_str("line 1\nline 2\n");
let eof_pos = rope.len_chars();
let target_eof = Target::Char(eof_pos - 1); let boundary_after = Boundary::new(target_eof, BoundaryMode::Include);
let snippet_from_last = Snippet::From(boundary_after);
let result1 = snippet_from_last.replace(&rope, "line 3\n").unwrap();
assert_eq!(result1.to_string(), "line 1\nline 2\nline 3\n");
let last_line = Target::Line(rope.len_lines() - 1);
let boundary_last_line = Boundary::new(last_line, BoundaryMode::Exclude);
let snippet_to_eof = Snippet::From(boundary_last_line);
let result2 = snippet_to_eof.replace(&rope, "").unwrap();
assert_eq!(result2.to_string(), "line 1\nline 2\n");
let target_end = Target::Char(rope.len_chars() - 1);
let boundary_to_end = Boundary::new(target_end, BoundaryMode::Include);
let snippet_append = Snippet::From(boundary_to_end);
let result3 = snippet_append.replace(&rope, "appended").unwrap();
assert_eq!(result3.to_string(), "line 1\nline 2\nappended");
}