use crate::snip::snippet::boundary::{Boundary, BoundaryMode, Extent};
use crate::snip::Target;
use crate::Rope;
#[test]
fn test_resolve_exclude_mode() {
let rope = Rope::from_str("alpha\nbeta\ngamma\n");
let target = Target::Line(1);
let boundary = Boundary::new(target, BoundaryMode::Exclude);
let resolved = boundary.resolve(&rope).unwrap();
let line_start = rope.line_to_char(1);
let line_end = rope.line_to_char(2);
assert!(
line_start < line_end,
"line start should be before line end"
);
assert_eq!(resolved.start, line_end);
assert_eq!(resolved.end, line_end);
}
#[test]
fn test_resolve_include_mode() {
let rope = Rope::from_str("alpha\nbeta\ngamma\n");
let target = Target::Line(1);
let boundary = Boundary::new(target, BoundaryMode::Include);
let resolved = boundary.resolve(&rope).unwrap();
let line_start = rope.line_to_char(1);
let line_end = rope.line_to_char(2);
assert_eq!(resolved.start, line_start);
assert_eq!(resolved.end, line_end);
}
#[test]
fn test_resolve_extend_lines() {
let rope = Rope::from_str("one\ntwo\nthree\nfour\n");
let target_line = 1;
let extent_lines = 2;
let target = Target::Line(target_line);
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Lines(extent_lines)));
let _target_line_start = rope.line_to_char(target_line); let target_line_end = rope.line_to_char(target_line + 1);
let extend_from_line = rope.char_to_line(target_line_end);
let extended_to_line = extend_from_line + extent_lines; let extended_to_char = rope.line_to_char(extended_to_line);
let resolved = boundary.resolve(&rope).unwrap();
assert_eq!(
resolved.start, target_line_end,
"Start should be at end of target line"
);
assert_eq!(
resolved.end, extended_to_char,
"End should be 2 lines forward from where we started extending"
);
}
#[test]
fn test_resolve_extend_chars() {
let rope = Rope::from_str("abcdefg");
let target = Target::Char(2);
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Chars(3)));
let resolved = boundary.resolve(&rope).unwrap();
assert_eq!(resolved.start, 3); assert_eq!(resolved.end, 6); }
#[test]
fn test_resolve_extend_bytes() {
let rope = Rope::from_str("hello 🎉");
let space_char_idx = 5; let ext_size = 4; let target = Target::Char(space_char_idx);
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Bytes(ext_size)));
let resolved = boundary.resolve(&rope).unwrap();
let target_end = space_char_idx + 1; assert_eq!(resolved.start, target_end, "Should start at end of space");
let start_byte = rope.char_to_byte(target_end); let target_byte = start_byte + ext_size;
let result_char = rope.byte_to_char(target_byte);
assert_eq!(
resolved.end, result_char,
"Should extend through the entire emoji"
);
}
#[test]
fn test_resolve_extend_matching_literal() {
let rope = Rope::from_str("a\nb\nc\nd\n");
let target = Target::Line(0);
let needle = Target::Literal("\n".to_string());
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Matching(2, needle)));
let resolved = boundary.resolve(&rope).unwrap();
let start = rope.line_to_char(1); let end = rope.line_to_char(3); assert_eq!(resolved.start, start);
assert_eq!(resolved.end, end);
}
#[test]
fn test_extend_matching_invalid() {
let rope = Rope::from_str("abc");
let target = Target::Line(0);
let empty_literal = Target::Literal(String::new());
let boundary = Boundary::new(
target,
BoundaryMode::Extend(Extent::Matching(1, empty_literal)),
);
let result = boundary.resolve(&rope);
if let Err(e) = &result {
println!("extend_matching_invalid: error={e:?}");
}
assert!(matches!(
result,
Err(crate::snip::BoundaryError::InvalidExtent)
));
}
#[test]
fn test_extend_out_of_bounds() {
let rope = Rope::from_str("abc");
let target = Target::Char(1);
let boundary = Boundary::new(target, BoundaryMode::Extend(Extent::Chars(10)));
let result = boundary.resolve(&rope);
assert!(matches!(
result,
Err(crate::snip::BoundaryError::ExtentOutOfBounds)
));
}