use crate::app::*;
fn make_diff_line(file_idx: usize, new_lineno: Option<u32>) -> AnnotatedLine {
AnnotatedLine::DiffLine {
file_idx,
hunk_idx: 0,
line_idx: 0,
old_lineno: None,
new_lineno,
}
}
fn make_diff_line_with_old(
file_idx: usize,
old_lineno: Option<u32>,
new_lineno: Option<u32>,
) -> AnnotatedLine {
AnnotatedLine::DiffLine {
file_idx,
hunk_idx: 0,
line_idx: 0,
old_lineno,
new_lineno,
}
}
fn make_sbs_line(file_idx: usize, new_lineno: Option<u32>) -> AnnotatedLine {
AnnotatedLine::SideBySideLine {
file_idx,
hunk_idx: 0,
del_line_idx: None,
add_line_idx: None,
old_lineno: None,
new_lineno,
}
}
#[test]
fn should_find_exact_match() {
let annotations = vec![
AnnotatedLine::FileHeader { file_idx: 0 },
make_diff_line(0, Some(10)),
make_diff_line(0, Some(11)),
make_diff_line(0, Some(12)),
];
let result = find_source_line(&annotations, 0, 11, LineSide::New);
assert_eq!(result, FindSourceLineResult::Exact(2));
}
#[test]
fn should_find_nearest_when_no_exact_match() {
let annotations = vec![
make_diff_line(0, Some(10)),
make_diff_line(0, Some(15)),
make_diff_line(0, Some(20)),
];
let result = find_source_line(&annotations, 0, 12, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(0));
}
#[test]
fn should_find_nearest_above_target() {
let annotations = vec![
make_diff_line(0, Some(10)),
make_diff_line(0, Some(15)),
make_diff_line(0, Some(20)),
];
let result = find_source_line(&annotations, 0, 18, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(2));
}
#[test]
fn should_return_not_found_for_empty_annotations() {
let annotations: Vec<AnnotatedLine> = vec![];
let result = find_source_line(&annotations, 0, 42, LineSide::New);
assert_eq!(result, FindSourceLineResult::NotFound);
}
#[test]
fn should_return_not_found_when_no_lines_in_current_file() {
let annotations = vec![make_diff_line(1, Some(10)), make_diff_line(1, Some(20))];
let result = find_source_line(&annotations, 0, 10, LineSide::New);
assert_eq!(result, FindSourceLineResult::NotFound);
}
#[test]
fn should_skip_lines_from_other_files() {
let annotations = vec![
make_diff_line(0, Some(100)), make_diff_line(1, Some(42)), make_diff_line(0, Some(50)), ];
let result = find_source_line(&annotations, 0, 42, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(2));
}
#[test]
fn should_skip_non_diff_line_annotations() {
let annotations = vec![
AnnotatedLine::FileHeader { file_idx: 0 },
AnnotatedLine::HunkHeader {
file_idx: 0,
hunk_idx: 0,
},
AnnotatedLine::Spacing,
make_diff_line(0, Some(42)),
];
let result = find_source_line(&annotations, 0, 42, LineSide::New);
assert_eq!(result, FindSourceLineResult::Exact(3));
}
#[test]
fn should_skip_diff_lines_with_no_new_lineno() {
let annotations = vec![make_diff_line(0, None), make_diff_line(0, Some(20))];
let result = find_source_line(&annotations, 0, 5, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(1));
}
#[test]
fn should_work_with_side_by_side_lines() {
let annotations = vec![
make_sbs_line(0, Some(10)),
make_sbs_line(0, Some(20)),
make_sbs_line(0, Some(30)),
];
let result = find_source_line(&annotations, 0, 20, LineSide::New);
assert_eq!(result, FindSourceLineResult::Exact(1));
}
#[test]
fn should_handle_mixed_diff_and_sbs_lines() {
let annotations = vec![
make_diff_line(0, Some(10)),
make_sbs_line(0, Some(20)),
make_diff_line(0, Some(30)),
];
let result = find_source_line(&annotations, 0, 25, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(1));
}
#[test]
fn should_return_not_found_when_only_non_line_annotations() {
let annotations = vec![
AnnotatedLine::FileHeader { file_idx: 0 },
AnnotatedLine::Spacing,
AnnotatedLine::HunkHeader {
file_idx: 0,
hunk_idx: 0,
},
];
let result = find_source_line(&annotations, 0, 42, LineSide::New);
assert_eq!(result, FindSourceLineResult::NotFound);
}
#[test]
fn should_prefer_exact_match_over_earlier_nearest() {
let annotations = vec![
make_diff_line(0, Some(41)), make_diff_line(0, Some(42)), make_diff_line(0, Some(43)), ];
let result = find_source_line(&annotations, 0, 42, LineSide::New);
assert_eq!(result, FindSourceLineResult::Exact(1));
}
#[test]
fn should_find_nearest_for_target_zero() {
let annotations = vec![make_diff_line(0, Some(1)), make_diff_line(0, Some(5))];
let result = find_source_line(&annotations, 0, 0, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(0));
}
#[test]
fn should_tie_break_nearest_by_iteration_order() {
let annotations = vec![
make_diff_line(0, Some(30)),
make_diff_line(0, Some(50)),
make_diff_line(0, Some(10)),
];
let result = find_source_line(&annotations, 0, 20, LineSide::New);
assert_eq!(result, FindSourceLineResult::Nearest(0));
}
#[test]
fn should_match_old_lineno_when_side_is_old() {
let annotations = vec![
make_diff_line_with_old(0, Some(5), None),
make_diff_line_with_old(0, Some(10), None),
make_diff_line(0, Some(50)), ];
let exact = find_source_line(&annotations, 0, 10, LineSide::Old);
assert_eq!(exact, FindSourceLineResult::Exact(1));
let nearest = find_source_line(&annotations, 0, 7, LineSide::Old);
assert_eq!(nearest, FindSourceLineResult::Nearest(0));
}
#[test]
fn should_not_match_new_lineno_when_side_is_old() {
let annotations = vec![make_diff_line(0, Some(42))];
let result = find_source_line(&annotations, 0, 42, LineSide::Old);
assert_eq!(result, FindSourceLineResult::NotFound);
}