Files
2023-11-13 22:14:22 +01:00

542 lines
15 KiB
Rust

/*
* Copyright (C) 2023 Valentin Lorentz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use color_eyre::eyre::WrapErr;
use pretty_assertions::assert_eq;
use ratatui::prelude::*;
use ratatrix::buffers::{BufferItem, BufferItemContent};
use ratatrix::components::Backlog;
use ratatrix::widgets::Prerender;
fn rect(x: u16, y: u16, width: u16, height: u16) -> Rect {
Rect {
x,
y,
width,
height,
}
}
#[test]
fn test_single_item() {
let mut bl = Backlog::default();
let prerender = Prerender::new();
let item = BufferItem {
content: BufferItemContent::Text(Text::raw("hello")),
prerender: &prerender,
};
let mut buf = Buffer::empty(rect(0, 0, 18, 8));
bl.draw_items(&mut buf, rect(3, 2, 12, 4), vec![item].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ",
" ┌──────────┐ ",
" │ │ ",
" │hello │ ",
" └──────────┘ ",
" ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_single_item_cached() {
let mut bl = Backlog::default();
let prerender = Prerender::new();
let item = BufferItem {
content: BufferItemContent::Text(Text::raw("hello")),
prerender: &prerender,
};
let mut buf = Buffer::empty(rect(0, 0, 18, 8));
let area = rect(3, 2, 12, 4);
bl.draw_items(&mut buf, area, vec![item].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ",
" ┌──────────┐ ",
" │ │ ",
" │hello │ ",
" └──────────┘ ",
" ",
" ",
]);
assert_eq!(buf, expected);
assert_eq!(prerender.key(), Some(10));
let item = BufferItem {
content: BufferItemContent::Text(Text::raw("hello")),
prerender: &prerender,
};
let mut buf = Buffer::empty(rect(0, 0, 18, 8));
bl.draw_items(&mut buf, area, vec![item].into_iter())
.context("Failed to draw")
.unwrap();
assert_eq!(buf, expected);
}
/// Checks that the prerender cache does not store empty columns to the right
#[test]
fn test_only_necessary_width() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let prerender2 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi\nworld")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw(":)")),
prerender: &prerender2,
};
let mut cell = ratatui::buffer::Cell::default();
cell.set_char('.');
let mut buf = Buffer::filled(rect(0, 0, 18, 7), &cell); // poisoned buffer
let area = rect(3, 1, 12, 5);
bl.draw_items(&mut buf, area, vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
"..................",
"...┌──────────┐...",
"...│hi........│...",
"...│world.....│...",
"...│:)........│...",
"...└──────────┘...",
"..................",
]);
assert_eq!(buf, expected);
assert_eq!(prerender1.key(), Some(10));
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi\nworld")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw(":)")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 18, 7));
bl.draw_items(&mut buf, area, vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │hi... │ ", // dots are leftover from the poisoned buffer above
" │world │ ",
" │:) │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_single_item_tight() {
let mut bl = Backlog::default();
let prerender = Prerender::new();
let item = BufferItem {
content: BufferItemContent::Text(Text::raw("hello")),
prerender: &prerender,
};
let mut buf = Buffer::empty(rect(0, 0, 13, 7));
bl.draw_items(&mut buf, rect(3, 2, 7, 3), vec![item].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ",
" ┌─────┐ ",
" │hello│ ",
" └─────┘ ",
" ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_two_items() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let prerender2 = Prerender::new();
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │hi │ ",
" │world │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_two_items_scroll() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let prerender2 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │hi │ ",
" │world │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
bl.scroll_up(1);
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │ │ ",
" │hi │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
bl.scroll_up(1);
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │ │ ",
" │ │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_two_items_multiline() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let prerender2 = Prerender::new();
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world\n!")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │hi │ ",
" │world │ ",
" │! │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_two_items_tight() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let prerender2 = Prerender::new();
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 9, 6));
bl.draw_items(&mut buf, rect(1, 1, 7, 4), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌─────┐ ",
" │hi │ ",
" │world│ ",
" └─────┘ ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_cache_moved() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
// Draw once
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │ │ ",
" │hi │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
// New item added at bottom
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("hi")),
prerender: &prerender1,
};
let prerender2 = Prerender::new();
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("world")),
prerender: &prerender2,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(&mut buf, rect(1, 1, 12, 5), vec![item2, item1].into_iter())
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │hi │ ",
" │world │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
}
#[test]
fn test_overflow_and_scroll() {
let mut bl = Backlog::default();
let prerender1 = Prerender::new();
let prerender2 = Prerender::new();
let prerender3 = Prerender::new();
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("line1 x")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
prerender: &prerender2,
};
let item3 = BufferItem {
content: BufferItemContent::Text(Text::raw("line5 z")),
prerender: &prerender3,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(
&mut buf,
rect(1, 1, 12, 5),
vec![item3, item2, item1].into_iter(),
)
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │line3 y │ ",
" │line4 y │ ",
" │line5 z │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
bl.scroll_up(1);
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("line1 x")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
prerender: &prerender2,
};
let item3 = BufferItem {
content: BufferItemContent::Text(Text::raw("line5 z")),
prerender: &prerender3,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(
&mut buf,
rect(1, 1, 12, 5),
vec![item3, item2, item1].into_iter(),
)
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │line2 y │ ",
" │line3 y │ ",
" │line4 y │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
bl.scroll_up(1);
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("line1 x")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
prerender: &prerender2,
};
let item3 = BufferItem {
content: BufferItemContent::Text(Text::raw("line5 z")),
prerender: &prerender3,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(
&mut buf,
rect(1, 1, 12, 5),
vec![item3, item2, item1].into_iter(),
)
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │line1 x │ ",
" │line2 y │ ",
" │line3 y │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
bl.scroll_up(1);
let item1 = BufferItem {
content: BufferItemContent::Text(Text::raw("line1 x")),
prerender: &prerender1,
};
let item2 = BufferItem {
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
prerender: &prerender2,
};
let item3 = BufferItem {
content: BufferItemContent::Text(Text::raw("line5 z")),
prerender: &prerender3,
};
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
bl.draw_items(
&mut buf,
rect(1, 1, 12, 5),
vec![item3, item2, item1].into_iter(),
)
.context("Failed to draw")
.unwrap();
let expected = Buffer::with_lines(vec![
" ",
" ┌──────────┐ ",
" │ │ ",
" │line1 x │ ",
" │line2 y │ ",
" └──────────┘ ",
" ",
]);
assert_eq!(buf, expected);
}