Files
galaxy/app/src/terminal/grid_renderer_tests.rs
T

265 lines
10 KiB
Rust

use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{vec2f, Vector2F};
use warpui::fonts::Cache as FontCache;
use warpui::units::{IntoLines, Lines, Pixels};
use super::{active_or_next_match, CachedBackgroundColor};
use crate::terminal::grid_size_util::calculate_grid_baseline_position;
use crate::terminal::model::index::Point;
use crate::terminal::model::selection::SelectionPoint;
use crate::terminal::{grid_renderer, SizeInfo};
fn rect_from_points(min_x: f32, min_y: f32, max_x: f32, max_y: f32) -> RectF {
RectF::from_points(vec2f(min_x, min_y), vec2f(max_x, max_y))
}
// TODO(CORE-2002): Make test non-Mac specific by switching to using bundled Roboto font.
#[test]
#[cfg_attr(
not(target_os = "macos"),
ignore = "Assumes existence of Arial font, which is only guaranteed on macOS"
)]
fn test_calculate_grid_baseline_position() {
let font_db = galaxyui::platform::test::FontDB::new();
let mut font_cache = FontCache::new(Box::new(font_db));
// Note we've restricted this unit test to Mac, so we expect Arial to exist.
let arial = font_cache
.load_system_font("Arial")
.expect("Arial must exist");
let baseline_position = calculate_grid_baseline_position(
&font_cache,
arial,
16., /* font_size */
1.2, /* line_height_ratio */
19., /* cell_size_y */
);
assert_eq!(baseline_position, vec2f(0., 15.));
}
#[test]
fn test_next_match_same_row_matches() {
let match_1 = Point::new(0, 0)..=Point::new(0, 4);
let match_2 = Point::new(1, 0)..=Point::new(1, 4);
let matches = [match_1.clone(), match_2.clone()];
let mut filter_match_iter = matches.iter();
let mut current_match = None;
// The first match should return for points (0,0) through (0,4).
for i in 0..=4 {
current_match =
active_or_next_match(&mut filter_match_iter, current_match, &Point::new(0, i));
assert_eq!(current_match, Some(&match_1));
}
// The second match should return for points (1,0) through (1,4).
for i in 0..=4 {
current_match =
active_or_next_match(&mut filter_match_iter, current_match, &Point::new(1, i));
assert_eq!(current_match, Some(&match_2));
}
// There should be no more matches left after we advance to point (2,0).
current_match = active_or_next_match(&mut filter_match_iter, current_match, &Point::new(2, 0));
assert_eq!(current_match, None);
}
#[test]
fn test_next_match_multi_row_matches() {
let match_1 = Point::new(0, 0)..=Point::new(1, 2);
let match_2 = Point::new(2, 0)..=Point::new(3, 2);
let matches = [match_1.clone(), match_2.clone()];
let mut match_iter = matches.iter();
let mut current_match = None;
// The first match should be returned for all points from (0,0) to (1,2).
let points_1 = [
Point::new(0, 0),
Point::new(0, 1),
Point::new(0, 2),
Point::new(1, 0),
Point::new(1, 1),
Point::new(1, 2),
];
for point in points_1.iter() {
current_match = active_or_next_match(&mut match_iter, current_match, point);
assert_eq!(current_match, Some(&match_1));
}
// The second match should be returned for all points from (2,0) to (3,2).
let points_2 = [
Point::new(2, 0),
Point::new(2, 1),
Point::new(2, 2),
Point::new(3, 0),
Point::new(3, 1),
Point::new(3, 2),
];
for point in points_2.iter() {
current_match = active_or_next_match(&mut match_iter, current_match, point);
assert_eq!(current_match, Some(&match_2));
}
// There should be no more matches left after we advance to point (4,0).
current_match = active_or_next_match(&mut match_iter, current_match, &Point::new(4, 0));
assert_eq!(current_match, None);
}
#[test]
fn test_active_or_next_match_point_before_next_match() {
let match_1 = Point::new(1, 0)..=Point::new(1, 4);
let match_2 = Point::new(3, 0)..=Point::new(3, 4);
let matches = [match_1.clone(), match_2.clone()];
let mut match_iter = matches.iter();
// The match for (0,0) should be the first match.
let mut current_match = active_or_next_match(&mut match_iter, None, &Point::new(0, 0));
assert_eq!(current_match, Some(&match_1));
// The match for (2,0) should be the second match.
current_match = active_or_next_match(&mut match_iter, current_match, &Point::new(2, 0));
assert_eq!(current_match, Some(&match_2));
}
#[test]
fn test_calculate_background_bounds() {
let origin = vec2f(100., 100.);
let cell_size = vec2f(2., 4.);
let max_columns = 150;
let create_cached = |start_row: usize, start_col: usize, end_row: usize, end_col: usize| {
CachedBackgroundColor {
start: SelectionPoint {
row: start_row.into_lines(),
col: start_col,
},
end: SelectionPoint {
row: end_row.into_lines(),
col: end_col,
},
background_color: Default::default(),
}
};
// Background with 1 row
let (start_row, start_col, end_row, end_col) = (10, 20, 10, 130);
let cached = create_cached(start_row, start_col, end_row, end_col);
assert_eq!(
grid_renderer::calculate_background_bounds(origin, cached, cell_size, max_columns),
vec![rect_from_points(
origin.x() + (start_col as f32) * cell_size.x(),
origin.y() + (start_row as f32) * cell_size.y(),
origin.x() + (end_col as f32 + 1.) * cell_size.x(),
origin.y() + (end_row as f32 + 1.) * cell_size.y()
)]
);
// Background with 2 rows
let (start_row, start_col, end_row, end_col) = (20, 30, 21, 100);
let cached = create_cached(start_row, start_col, end_row, end_col);
assert_eq!(
grid_renderer::calculate_background_bounds(origin, cached, cell_size, max_columns),
vec![
rect_from_points(
origin.x() + (start_col as f32) * cell_size.x(),
origin.y() + (start_row as f32) * cell_size.y(),
origin.x() + (max_columns as f32 + 1.) * cell_size.x(),
origin.y() + (start_row as f32 + 1.) * cell_size.y()
),
rect_from_points(
origin.x(),
origin.y() + (start_row as f32 + 1.) * cell_size.y(),
origin.x() + (end_col as f32 + 1.) * cell_size.x(),
origin.y() + (end_row as f32 + 1.) * cell_size.y()
),
]
);
// Background with 3+ rows
let assert_multi_row_selection_bounds =
|start_row: usize, start_col: usize, end_row: usize, end_col: usize| {
let cached = create_cached(start_row, start_col, end_row, end_col);
assert_eq!(
grid_renderer::calculate_background_bounds(origin, cached, cell_size, max_columns),
vec![
rect_from_points(
origin.x() + (start_col as f32) * cell_size.x(),
origin.y() + (start_row as f32) * cell_size.y(),
origin.x() + (max_columns as f32 + 1.) * cell_size.x(),
origin.y() + (start_row as f32 + 1.) * cell_size.y()
),
rect_from_points(
origin.x(),
origin.y() + (start_row as f32 + 1.) * cell_size.y(),
origin.x() + (max_columns as f32 + 1.) * cell_size.x(),
origin.y() + (end_row as f32) * cell_size.y()
),
rect_from_points(
origin.x(),
origin.y() + (end_row as f32) * cell_size.y(),
origin.x() + (end_col as f32 + 1.) * cell_size.x(),
origin.y() + (end_row as f32 + 1.) * cell_size.y()
),
]
);
};
assert_multi_row_selection_bounds(30, 80, 32, 40); // 3 lines
assert_multi_row_selection_bounds(40, 60, 43, 10); // 4 lines
assert_multi_row_selection_bounds(50, 140, 59, 20); // 10 lines
}
#[test]
fn test_calculate_selection_bounds() {
let origin = vec2f(100., 100.);
let size_info = SizeInfo::new(
Vector2F::zero(),
Pixels::new(2.),
Pixels::new(4.),
Pixels::new(8.),
Pixels::new(16.),
)
.with_rows_and_columns(151, 151);
let cell_width = size_info.cell_width_px.as_f32();
let cell_height = size_info.cell_height_px.as_f32();
let horizontal_padding = size_info.padding_x_px.as_f32();
let max_columns = size_info.columns - 1;
let make_selection_point = |row: usize, col: usize| SelectionPoint {
row: row.into_lines(),
col,
};
let start = make_selection_point(10, 10);
let end = make_selection_point(20, 50);
let assert_selection_bounds = |scroll_top: Lines| {
assert_eq!(
grid_renderer::calculate_selection_bounds(&start, &end, &size_info, scroll_top, origin),
vec![
rect_from_points(
origin.x() + horizontal_padding + (start.col as f32) * cell_width,
origin.y() + ((start.row - scroll_top).as_f64() as f32) * cell_height,
origin.x() + horizontal_padding + (max_columns as f32 + 1.) * cell_width,
origin.y() + ((start.row - scroll_top).as_f64() as f32 + 1.) * cell_height
),
rect_from_points(
origin.x() + horizontal_padding,
origin.y() + ((start.row - scroll_top).as_f64() as f32 + 1.) * cell_height,
origin.x() + horizontal_padding + (max_columns as f32 + 1.) * cell_width,
origin.y() + ((end.row - scroll_top).as_f64() as f32) * cell_height
),
rect_from_points(
origin.x() + horizontal_padding,
origin.y() + ((end.row - scroll_top).as_f64() as f32) * cell_height,
origin.x() + horizontal_padding + (end.col as f32 + 1.) * cell_width,
origin.y() + ((end.row - scroll_top).as_f64() as f32 + 1.) * cell_height
),
]
);
};
assert_selection_bounds(5.into_lines()); // Without scroll clipping
assert_selection_bounds(10.into_lines()); // Without scroll clipping (but on the cusp of clipping)
assert_selection_bounds(80.into_lines()); // With scroll clipping
}