fish-shell/src/tests/pager.rs
Johannes Altmanninger 3cfa09d1bd Make test_init() return a scope guard
To be used in the next commit.
2024-03-24 16:33:35 +01:00

197 lines
8 KiB
Rust

use crate::common::get_ellipsis_char;
use crate::complete::{CompleteFlags, Completion};
use crate::pager::{Pager, SelectionMotion};
use crate::termsize::Termsize;
use crate::tests::prelude::*;
use crate::wchar::prelude::*;
use crate::wcstringutil::StringFuzzyMatch;
#[test]
#[serial]
fn test_pager_navigation() {
let _cleanup = test_init();
// Generate 19 strings of width 10. There's 2 spaces between completions, and our term size is
// 80; these can therefore fit into 6 columns (6 * 12 - 2 = 70) or 5 columns (58) but not 7
// columns (7 * 12 - 2 = 82).
//
// You can simulate this test by creating 19 files named "file00.txt" through "file_18.txt".
let mut completions = vec![];
for _ in 0..19 {
completions.push(Completion::new(
L!("abcdefghij").to_owned(),
"".into(),
StringFuzzyMatch::exact_match(),
CompleteFlags::default(),
));
}
let mut pager = Pager::default();
pager.set_completions(&completions, true);
pager.set_term_size(&Termsize::defaults());
let mut render = pager.render();
assert_eq!(render.term_width, Some(80));
assert_eq!(render.term_height, Some(24));
let rows = 4;
let cols = 5;
// We have 19 completions. We can fit into 6 columns with 4 rows or 5 columns with 4 rows; the
// second one is better and so is what we ought to have picked.
assert_eq!(render.rows, rows);
assert_eq!(render.cols, cols);
// Initially expect to have no completion index.
assert!(render.selected_completion_idx.is_none());
// Here are navigation directions and where we expect the selection to be.
macro_rules! validate {
($pager:ident, $render:ident, $dir:expr, $sel:expr) => {
$pager.select_next_completion_in_direction($dir, &$render);
$pager.update_rendering(&mut $render);
assert_eq!(
Some($sel),
$render.selected_completion_idx,
"For command {:?}",
$dir
);
};
}
// Tab completion to get into the list.
validate!(pager, render, SelectionMotion::Next, 0);
// Westward motion in upper left goes to the last filled column in the last row.
validate!(pager, render, SelectionMotion::West, 15);
// East goes back.
validate!(pager, render, SelectionMotion::East, 0);
validate!(pager, render, SelectionMotion::West, 15);
validate!(pager, render, SelectionMotion::West, 11);
validate!(pager, render, SelectionMotion::East, 15);
validate!(pager, render, SelectionMotion::East, 0);
// "Next" motion goes down the column.
validate!(pager, render, SelectionMotion::Next, 1);
validate!(pager, render, SelectionMotion::Next, 2);
validate!(pager, render, SelectionMotion::West, 17);
validate!(pager, render, SelectionMotion::East, 2);
validate!(pager, render, SelectionMotion::East, 6);
validate!(pager, render, SelectionMotion::East, 10);
validate!(pager, render, SelectionMotion::East, 14);
validate!(pager, render, SelectionMotion::East, 18);
validate!(pager, render, SelectionMotion::West, 14);
validate!(pager, render, SelectionMotion::East, 18);
// Eastward motion wraps back to the upper left, westward goes to the prior column.
validate!(pager, render, SelectionMotion::East, 3);
validate!(pager, render, SelectionMotion::East, 7);
validate!(pager, render, SelectionMotion::East, 11);
validate!(pager, render, SelectionMotion::East, 15);
// Pages.
validate!(pager, render, SelectionMotion::PageNorth, 12);
validate!(pager, render, SelectionMotion::PageSouth, 15);
validate!(pager, render, SelectionMotion::PageNorth, 12);
validate!(pager, render, SelectionMotion::East, 16);
validate!(pager, render, SelectionMotion::PageSouth, 18);
validate!(pager, render, SelectionMotion::East, 3);
validate!(pager, render, SelectionMotion::North, 2);
validate!(pager, render, SelectionMotion::PageNorth, 0);
validate!(pager, render, SelectionMotion::PageSouth, 3);
}
#[test]
#[serial]
fn test_pager_layout() {
let _cleanup = test_init();
// These tests are woefully incomplete
// They only test the truncation logic for a single completion
let rendered_line = |pager: &mut Pager, width: isize| {
pager.set_term_size(&Termsize::new(width, 24));
let rendering = pager.render();
let sd = &rendering.screen_data;
assert_eq!(sd.line_count(), 1);
let line = sd.line(0);
WString::from(Vec::from_iter((0..line.len()).map(|i| line.char_at(i))))
};
let compute_expected = |expected: &wstr| {
let ellipsis_char = get_ellipsis_char();
if ellipsis_char != '\u{2026}' {
// hack: handle the case where ellipsis is not L'\x2026'
expected.replace(L!("\u{2026}"), wstr::from_char_slice(&[ellipsis_char]))
} else {
expected.to_owned()
}
};
macro_rules! validate {
($pager:expr, $width:expr, $expected:expr) => {
assert_eq!(
rendered_line($pager, $width),
compute_expected($expected),
"width {}",
$width
);
};
}
let mut pager = Pager::default();
// These test cases have equal completions and descriptions
let c1s = vec![Completion::new(
L!("abcdefghij").to_owned(),
L!("1234567890").to_owned(),
StringFuzzyMatch::exact_match(),
CompleteFlags::default(),
)];
pager.set_completions(&c1s, true);
validate!(&mut pager, 26, L!("abcdefghij (1234567890)"));
validate!(&mut pager, 25, L!("abcdefghij (1234567890)"));
validate!(&mut pager, 24, L!("abcdefghij (1234567890)"));
validate!(&mut pager, 23, L!("abcdefghij (12345678…)"));
validate!(&mut pager, 22, L!("abcdefghij (1234567…)"));
validate!(&mut pager, 21, L!("abcdefghij (123456…)"));
validate!(&mut pager, 20, L!("abcdefghij (12345…)"));
validate!(&mut pager, 19, L!("abcdefghij (1234…)"));
validate!(&mut pager, 18, L!("abcdefgh… (1234…)"));
validate!(&mut pager, 17, L!("abcdefg… (1234…)"));
validate!(&mut pager, 16, L!("abcdefg… (123…)"));
// These test cases have heavyweight completions
let c2s = vec![Completion::new(
L!("abcdefghijklmnopqrs").to_owned(),
L!("1").to_owned(),
StringFuzzyMatch::exact_match(),
CompleteFlags::default(),
)];
pager.set_completions(&c2s, true);
validate!(&mut pager, 26, L!("abcdefghijklmnopqrs (1)"));
validate!(&mut pager, 25, L!("abcdefghijklmnopqrs (1)"));
validate!(&mut pager, 24, L!("abcdefghijklmnopqrs (1)"));
validate!(&mut pager, 23, L!("abcdefghijklmnopq… (1)"));
validate!(&mut pager, 22, L!("abcdefghijklmnop… (1)"));
validate!(&mut pager, 21, L!("abcdefghijklmno… (1)"));
validate!(&mut pager, 20, L!("abcdefghijklmn… (1)"));
validate!(&mut pager, 19, L!("abcdefghijklm… (1)"));
validate!(&mut pager, 18, L!("abcdefghijkl… (1)"));
validate!(&mut pager, 17, L!("abcdefghijk… (1)"));
validate!(&mut pager, 16, L!("abcdefghij… (1)"));
// These test cases have no descriptions
let c3s = vec![Completion::new(
L!("abcdefghijklmnopqrst").to_owned(),
L!("").to_owned(),
StringFuzzyMatch::exact_match(),
CompleteFlags::default(),
)];
pager.set_completions(&c3s, true);
validate!(&mut pager, 26, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 25, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 24, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 23, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 22, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 21, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 20, L!("abcdefghijklmnopqrst"));
validate!(&mut pager, 19, L!("abcdefghijklmnopqr…"));
validate!(&mut pager, 18, L!("abcdefghijklmnopq…"));
validate!(&mut pager, 17, L!("abcdefghijklmnop…"));
validate!(&mut pager, 16, L!("abcdefghijklmno…"));
}