681 lines
18 KiB
Rust
681 lines
18 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 std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use color_eyre::eyre::WrapErr;
|
|
use pretty_assertions::assert_eq;
|
|
use ratatui::prelude::*;
|
|
|
|
use ratatrix::buffers::{BufferItem, BufferItemContent};
|
|
use ratatrix::components::Backlog;
|
|
use ratatrix::config::Config;
|
|
use ratatrix::widgets::Prerender;
|
|
|
|
fn config() -> Arc<Config> {
|
|
std::env::set_var("RATATRIX_CONFIG", PathBuf::from(".config/"));
|
|
let c = Config::new();
|
|
std::env::remove_var("RATATRIX_CONFIG");
|
|
Arc::new(c.unwrap())
|
|
}
|
|
|
|
fn rect(x: u16, y: u16, width: u16, height: u16) -> Rect {
|
|
Rect {
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
}
|
|
}
|
|
|
|
macro_rules! items_iter {
|
|
[ $($item: expr),* ] => {
|
|
|| vec![
|
|
$(
|
|
{
|
|
let BufferItem { content, prerender, unique_id } = &$item;
|
|
BufferItem {
|
|
content: content.clone(),
|
|
prerender,
|
|
unique_id: *unique_id,
|
|
}
|
|
},
|
|
)*
|
|
].into_iter()
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_item() {
|
|
let mut bl = Backlog::new(config());
|
|
let prerender = Prerender::new();
|
|
let item = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hello")),
|
|
prerender: &prerender,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 18, 8));
|
|
bl.draw_items(&mut buf, rect(3, 2, 12, 4), items_iter![item])
|
|
.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::new(config());
|
|
let prerender = Prerender::new();
|
|
let item = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hello")),
|
|
prerender: &prerender,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 18, 8));
|
|
let area = rect(3, 2, 12, 4);
|
|
bl.draw_items(&mut buf, area, items_iter![item])
|
|
.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,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 18, 8));
|
|
bl.draw_items(&mut buf, area, items_iter![item])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let prerender2 = Prerender::new();
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
|
prerender: &prerender1,
|
|
unique_id: None,
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw(":)")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
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, items_iter![item2, item1])
|
|
.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,
|
|
unique_id: None,
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw(":)")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 18, 7));
|
|
bl.draw_items(&mut buf, area, items_iter![item2, item1])
|
|
.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::new(config());
|
|
let prerender = Prerender::new();
|
|
let item = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hello")),
|
|
prerender: &prerender,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 13, 7));
|
|
bl.draw_items(&mut buf, rect(3, 2, 7, 3), items_iter![item])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi")),
|
|
prerender: &prerender1,
|
|
unique_id: None,
|
|
};
|
|
let prerender2 = Prerender::new();
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let prerender2 = Prerender::new();
|
|
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi")),
|
|
prerender: &prerender1,
|
|
unique_id: Some(123),
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world")),
|
|
prerender: &prerender2,
|
|
unique_id: Some(456),
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.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,
|
|
unique_id: Some(123),
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world")),
|
|
prerender: &prerender2,
|
|
unique_id: Some(456),
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.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,
|
|
unique_id: Some(123),
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world")),
|
|
prerender: &prerender2,
|
|
unique_id: Some(456),
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi")),
|
|
prerender: &prerender1,
|
|
unique_id: None,
|
|
};
|
|
let prerender2 = Prerender::new();
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world\n!")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi")),
|
|
prerender: &prerender1,
|
|
unique_id: None,
|
|
};
|
|
let prerender2 = Prerender::new();
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 9, 6));
|
|
bl.draw_items(&mut buf, rect(1, 1, 7, 4), items_iter![item2, item1])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi")),
|
|
prerender: &prerender1,
|
|
unique_id: None,
|
|
};
|
|
|
|
// Draw once
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item1])
|
|
.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,
|
|
unique_id: None,
|
|
};
|
|
let prerender2 = Prerender::new();
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("world")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.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::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let prerender2 = Prerender::new();
|
|
let prerender3 = Prerender::new();
|
|
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line1 x")),
|
|
prerender: &prerender1,
|
|
unique_id: None,
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let item3 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line5 z")),
|
|
prerender: &prerender3,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(
|
|
&mut buf,
|
|
rect(1, 1, 12, 5),
|
|
items_iter![item3, item2, item1],
|
|
)
|
|
.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,
|
|
unique_id: None,
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let item3 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line5 z")),
|
|
prerender: &prerender3,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(
|
|
&mut buf,
|
|
rect(1, 1, 12, 5),
|
|
items_iter![item3, item2, item1],
|
|
)
|
|
.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,
|
|
unique_id: None,
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let item3 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line5 z")),
|
|
prerender: &prerender3,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(
|
|
&mut buf,
|
|
rect(1, 1, 12, 5),
|
|
items_iter![item3, item2, item1],
|
|
)
|
|
.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,
|
|
unique_id: None,
|
|
};
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line2 y\nline3 y\nline4 y")),
|
|
prerender: &prerender2,
|
|
unique_id: None,
|
|
};
|
|
let item3 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("line5 z")),
|
|
prerender: &prerender3,
|
|
unique_id: None,
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(
|
|
&mut buf,
|
|
rect(1, 1, 12, 5),
|
|
items_iter![item3, item2, item1],
|
|
)
|
|
.context("Failed to draw")
|
|
.unwrap();
|
|
let expected = Buffer::with_lines(vec![
|
|
" ",
|
|
" ┌──────────┐ ",
|
|
" │ │ ",
|
|
" │line1 x │ ",
|
|
" │line2 y │ ",
|
|
" └──────────┘ ",
|
|
" ",
|
|
]);
|
|
assert_eq!(buf, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_scrolledup_new_line() {
|
|
let mut bl = Backlog::new(config());
|
|
let prerender1 = Prerender::new();
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
|
prerender: &prerender1,
|
|
unique_id: Some(123),
|
|
};
|
|
|
|
// Draw once
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item1])
|
|
.context("Failed to draw")
|
|
.unwrap();
|
|
let expected = Buffer::with_lines(vec![
|
|
" ",
|
|
" ┌──────────┐ ",
|
|
" │ │ ",
|
|
" │hi │ ",
|
|
" │world │ ",
|
|
" └──────────┘ ",
|
|
" ",
|
|
]);
|
|
assert_eq!(buf, expected);
|
|
|
|
// Scroll up one line
|
|
bl.scroll_up(1);
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
|
prerender: &prerender1,
|
|
unique_id: Some(123),
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item1])
|
|
.context("Failed to draw")
|
|
.unwrap();
|
|
let expected = Buffer::with_lines(vec![
|
|
" ",
|
|
" ┌──────────┐ ",
|
|
" │ │ ",
|
|
" │ │ ",
|
|
" │hi │ ",
|
|
" └──────────┘ ",
|
|
" ",
|
|
]);
|
|
assert_eq!(buf, expected);
|
|
|
|
// New item added at bottom, displayed paragraph should not move up
|
|
let item1 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("hi\nworld")),
|
|
prerender: &prerender1,
|
|
unique_id: Some(123),
|
|
};
|
|
let prerender2 = Prerender::new();
|
|
let item2 = BufferItem {
|
|
content: BufferItemContent::Text(Text::raw("!")),
|
|
prerender: &prerender2,
|
|
unique_id: Some(456),
|
|
};
|
|
let mut buf = Buffer::empty(rect(0, 0, 14, 7));
|
|
bl.draw_items(&mut buf, rect(1, 1, 12, 5), items_iter![item2, item1])
|
|
.context("Failed to draw")
|
|
.unwrap();
|
|
let expected = Buffer::with_lines(vec![
|
|
" ",
|
|
" ┌──────────┐ ",
|
|
" │ │ ",
|
|
" │ │ ",
|
|
" │hi │ ",
|
|
" └──────────┘ ",
|
|
" ",
|
|
]);
|
|
assert_eq!(buf, expected);
|
|
}
|