use crate::snip::snippet::{Boundary, BoundaryMode, Extent, Snippet, SnippetError};
use crate::snip::Target;
use crate::Rope;
#[test]
fn test_resolve_at_single_line() {
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 resolution = snippet.resolve(&rope).unwrap();
let line_start = rope.line_to_char(1); let line_end = rope.line_to_char(2);
assert_eq!(resolution.start, line_start);
assert_eq!(resolution.end, line_end);
assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"line2\n"
);
}
#[test]
fn test_resolve_at_exclude_mode() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let target = Target::Line(1);
let boundary = Boundary::new(target, BoundaryMode::Exclude);
let snippet = Snippet::At(boundary);
let resolution = snippet.resolve(&rope).unwrap();
let line_end = rope.line_to_char(2);
assert_eq!(resolution.start, line_end);
assert_eq!(resolution.end, line_end);
assert_eq!(resolution.start, resolution.end, "Should be zero-width");
}
#[test]
fn test_resolve_from_boundary_to_eof() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let target = Target::Line(1);
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::From(boundary);
let resolution = snippet.resolve(&rope).unwrap();
let line_end = rope.line_to_char(2); let eof = rope.len_chars();
assert_eq!(resolution.start, line_end);
assert_eq!(resolution.end, eof);
assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"line3\n"
);
}
#[test]
fn test_resolve_to_boundary_from_bof_include() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let target = Target::Line(2);
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::To(boundary);
let resolution = snippet.resolve(&rope).unwrap();
let bof = 0;
let line_end = rope.line_to_char(3);
assert_eq!(resolution.start, bof);
assert_eq!(resolution.end, line_end); assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"line1\nline2\nline3\n" );
}
#[test]
fn test_resolve_to_boundary_from_bof_exclude() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let target = Target::Line(2);
let boundary = Boundary::new(target, BoundaryMode::Exclude);
let snippet = Snippet::To(boundary);
let resolution = snippet.resolve(&rope).unwrap();
let bof = 0;
let line_start = rope.line_to_char(2);
assert_eq!(resolution.start, bof);
assert_eq!(resolution.end, line_start); assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"line1\nline2\n" );
}
#[test]
fn test_resolve_between_boundaries() {
let rope = Rope::from_str("<!-- start -->content here<!-- 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 resolution = snippet.resolve(&rope).unwrap();
let start_marker_end = 14; let end_marker_start = 26;
assert_eq!(resolution.start, start_marker_end);
assert_eq!(resolution.end, end_marker_start);
assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"content here"
);
}
#[test]
fn test_resolve_between_asymmetric_modes() {
let rope = Rope::from_str("<!-- start -->content here<!-- 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::Include);
let end_boundary = Boundary::new(end_target, BoundaryMode::Exclude);
let snippet = Snippet::Between {
start: start_boundary,
end: end_boundary,
};
let resolution = snippet.resolve(&rope).unwrap();
let start_marker_start = 0; let end_marker_start = 26;
assert_eq!(resolution.start, start_marker_start);
assert_eq!(resolution.end, end_marker_start);
assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"<!-- start -->content here"
);
}
#[test]
fn test_resolve_all_entire_rope() {
let rope = Rope::from_str("line1\nline2\nline3\n");
let snippet = Snippet::All;
let resolution = snippet.resolve(&rope).unwrap();
let bof = 0;
let eof = rope.len_chars();
assert_eq!(resolution.start, bof);
assert_eq!(resolution.end, eof);
assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"line1\nline2\nline3\n"
);
}
#[test]
fn test_resolve_invalid_range_error() {
let rope = Rope::from_str("abc<!-- end --><!-- start -->xyz");
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.resolve(&rope);
assert!(matches!(result, Err(SnippetError::InvalidRange { .. })));
}
#[test]
fn test_resolve_out_of_bounds_error() {
let rope = Rope::from_str("short");
let target = Target::Char(3);
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Chars(100)));
let snippet = Snippet::At(boundary);
let result = snippet.resolve(&rope);
assert!(matches!(result, Err(SnippetError::BoundaryError(_))));
}
#[test]
fn test_resolve_boundary_error_propagation() {
let rope = Rope::from_str("hello world");
let target = Target::Literal("nonexistent".to_string());
let boundary = Boundary::new(target, BoundaryMode::Include);
let snippet = Snippet::At(boundary);
let result = snippet.resolve(&rope);
assert!(matches!(result, Err(SnippetError::BoundaryError(_))));
}
#[test]
fn test_resolve_with_extend_mode() {
let rope = Rope::from_str("line1\nline2\nline3\nline4\nline5\n");
let target = Target::Line(1); let extent_lines = 2;
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Lines(extent_lines)));
let snippet = Snippet::At(boundary);
let resolution = snippet.resolve(&rope).unwrap();
let target_line_end = rope.line_to_char(2); let extended_line = rope.char_to_line(target_line_end) + extent_lines; let extended_char = rope.line_to_char(extended_line);
assert_eq!(resolution.start, target_line_end);
assert_eq!(resolution.end, extended_char);
assert_eq!(
rope.slice(resolution.start..resolution.end).to_string(),
"line3\nline4\n"
);
}