test(buffer): allow with_lines to accept Vec<Into<Line>> (#494)

This allows writing unit tests without having to call set_style on the
expected buffer.

E.g.:
```rust
use crate::style::Stylize;
let mut buf = Buffer::empty(Rect::new(0, 0, 10, 10));
buf.set_string(0, 0, "foo", Style::new().red());
buf.set_string(0, 1, "bar", Style::new().blue());
assert_eq!(buf, Buffer::with_lines(vec!["foo".red(), "bar".blue()]));
```

Inspired by https://github.com/ratatui-org/ratatui/issues/493#issuecomment-1714844468
This commit is contained in:
Josh McKinney 2023-09-12 11:53:43 -07:00 committed by GitHub
parent 42f816999e
commit 94af2a29e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 69 deletions

View file

@ -175,24 +175,16 @@ impl Buffer {
}
/// Returns a Buffer containing the given lines
pub fn with_lines<S>(lines: Vec<S>) -> Buffer
pub fn with_lines<'a, S>(lines: Vec<S>) -> Buffer
where
S: AsRef<str>,
S: Into<Line<'a>>,
{
let lines = lines.into_iter().map(Into::into).collect::<Vec<_>>();
let height = lines.len() as u16;
let width = lines
.iter()
.map(|i| i.as_ref().width() as u16)
.max()
.unwrap_or_default();
let mut buffer = Buffer::empty(Rect {
x: 0,
y: 0,
width,
height,
});
let width = lines.iter().map(Line::width).max().unwrap_or_default() as u16;
let mut buffer = Buffer::empty(Rect::new(0, 0, width, height));
for (y, line) in lines.iter().enumerate() {
buffer.set_string(0, y as u16, line, Style::default());
buffer.set_line(0, y as u16, line, width);
}
buffer
}
@ -1066,4 +1058,13 @@ mod tests {
let skipped: Vec<bool> = one.content().iter().map(|c| c.skip).collect();
assert_eq!(skipped, vec![true, true, false, false, false, false]);
}
#[test]
fn with_lines_accepts_into_lines() {
use crate::style::Stylize;
let mut buf = Buffer::empty(Rect::new(0, 0, 3, 2));
buf.set_string(0, 0, "foo", Style::new().red());
buf.set_string(0, 1, "bar", Style::new().blue());
assert_eq!(buf, Buffer::with_lines(vec!["foo".red(), "bar".blue()]));
}
}

View file

@ -1055,6 +1055,7 @@ mod tests {
use pretty_assertions::assert_eq;
use crate::{
assert_buffer_eq,
prelude::{Constraint::*, *},
widgets::{Paragraph, Widget},
};
@ -1078,7 +1079,8 @@ mod tests {
let s: String = c.to_string().repeat(area.width as usize);
Paragraph::new(s).render(layout[i], &mut buffer);
}
assert_eq!(buffer.content, Buffer::with_lines(vec![expected]).content);
let expected = Buffer::with_lines(vec![expected]);
assert_buffer_eq!(buffer, expected);
}
#[test]

View file

@ -750,17 +750,17 @@ mod tests {
fn test_list_style() {
let items = list_items(vec!["Item 0", "Item 1", "Item 2"]);
let list = List::new(items).style(Style::default().fg(Color::Red));
let buffer = render_widget(list, 10, 5);
let mut expected = Buffer::with_lines(vec![
"Item 0 ",
"Item 1 ",
"Item 2 ",
" ",
" ",
]);
expected.set_style(buffer.area, Style::default().fg(Color::Red));
assert_buffer_eq!(buffer, expected);
assert_buffer_eq!(
render_widget(list, 10, 5),
Buffer::with_lines(vec![
"Item 0 ".red(),
"Item 1 ".red(),
"Item 2 ".red(),
" ".red(),
" ".red(),
])
);
}
#[test]
@ -772,17 +772,16 @@ mod tests {
let mut state = ListState::default();
state.select(Some(1));
let buffer = render_stateful_widget(list, &mut state, 10, 5);
let mut expected = Buffer::with_lines(vec![
" Item 0 ",
">>Item 1 ",
" Item 2 ",
" ",
" ",
]);
expected.set_style(Rect::new(0, 1, 10, 1), Style::default().fg(Color::Yellow));
assert_buffer_eq!(buffer, expected);
assert_buffer_eq!(
render_stateful_widget(list, &mut state, 10, 5),
Buffer::with_lines(vec![
" Item 0 ".into(),
">>Item 1 ".yellow(),
" Item 2 ".into(),
" ".into(),
" ".into(),
])
);
}
#[test]
@ -923,17 +922,16 @@ mod tests {
let mut state = ListState::default();
state.select(Some(0));
let buffer = render_stateful_widget(list, &mut state, 10, 5);
let mut expected = Buffer::with_lines(vec![
">>Item 0 ",
">>Line 2 ",
" Item 1 ",
" Item 2 ",
" ",
]);
expected.set_style(Rect::new(0, 0, 10, 2), Style::default().fg(Color::Yellow));
assert_buffer_eq!(buffer, expected);
assert_buffer_eq!(
render_stateful_widget(list, &mut state, 10, 5),
Buffer::with_lines(vec![
">>Item 0 ".yellow(),
">>Line 2 ".yellow(),
" Item 1 ".into(),
" Item 2 ".into(),
" ".into(),
])
);
}
#[test]

View file

@ -179,7 +179,7 @@ mod tests {
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"]);
assert_buffer_eq!(
render(tabs, Rect::new(0, 0, 30, 1)),
Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 ",])
Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "])
);
}
@ -201,9 +201,10 @@ mod tests {
fn render_style() {
let tabs =
Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"]).style(Style::default().fg(Color::Red));
let mut expected = Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "]);
expected.set_style(Rect::new(0, 0, 30, 1), Style::default().fg(Color::Red));
assert_buffer_eq!(render(tabs, Rect::new(0, 0, 30, 1)), expected);
assert_buffer_eq!(
render(tabs, Rect::new(0, 0, 30, 1)),
Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 ".red()])
);
}
#[test]
@ -212,34 +213,39 @@ mod tests {
.highlight_style(Style::new().reversed());
// first tab selected
let mut expected = Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "]);
expected.set_style(Rect::new(1, 0, 4, 1), Style::new().reversed());
assert_buffer_eq!(
render(tabs.clone().select(0), Rect::new(0, 0, 30, 1)),
expected
Buffer::with_lines(vec![Line::from(vec![
" ".into(),
"Tab1".reversed(),
" │ Tab2 │ Tab3 │ Tab4 ".into(),
])])
);
// second tab selected
let mut expected = Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "]);
expected.set_style(Rect::new(8, 0, 4, 1), Style::new().reversed());
assert_buffer_eq!(
render(tabs.clone().select(1), Rect::new(0, 0, 30, 1)),
expected
Buffer::with_lines(vec![Line::from(vec![
" Tab1 │ ".into(),
"Tab2".reversed(),
" │ Tab3 │ Tab4 ".into(),
])])
);
// last tab selected
let mut expected = Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "]);
expected.set_style(Rect::new(22, 0, 4, 1), Style::new().reversed());
assert_buffer_eq!(
render(tabs.clone().select(3), Rect::new(0, 0, 30, 1)),
expected
Buffer::with_lines(vec![Line::from(vec![
" Tab1 │ Tab2 │ Tab3 │ ".into(),
"Tab4".reversed(),
" ".into(),
])])
);
// out of bounds selects no tab
let expected = Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "]);
assert_buffer_eq!(
render(tabs.clone().select(4), Rect::new(0, 0, 30, 1)),
expected
Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "])
);
}
@ -249,10 +255,14 @@ mod tests {
.style(Style::new().red())
.highlight_style(Style::new().reversed())
.select(0);
let mut expected = Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │ Tab4 "]);
expected.set_style(Rect::new(0, 0, 30, 1), Style::new().red());
expected.set_style(Rect::new(1, 0, 4, 1), Style::new().reversed());
assert_buffer_eq!(render(tabs, Rect::new(0, 0, 30, 1)), expected);
assert_buffer_eq!(
render(tabs, Rect::new(0, 0, 30, 1)),
Buffer::with_lines(vec![Line::from(vec![
" ".red(),
"Tab1".red().reversed(),
" │ Tab2 │ Tab3 │ Tab4 ".red(),
])])
);
}
#[test]

View file

@ -4,7 +4,7 @@ use ratatui::{
layout::{Alignment, Rect},
style::{Color, Style},
symbols,
text::Span,
text::{self, Span},
widgets::{Axis, Block, Borders, Chart, Dataset, GraphType::Line},
Terminal,
};
@ -13,9 +13,9 @@ fn create_labels<'a>(labels: &'a [&'a str]) -> Vec<Span<'a>> {
labels.iter().map(|l| Span::from(*l)).collect()
}
fn axis_test_case<S>(width: u16, height: u16, x_axis: Axis, y_axis: Axis, lines: Vec<S>)
fn axis_test_case<'a, S>(width: u16, height: u16, x_axis: Axis, y_axis: Axis, lines: Vec<S>)
where
S: AsRef<str>,
S: Into<text::Line<'a>>,
{
let backend = TestBackend::new(width, height);
let mut terminal = Terminal::new(backend).unwrap();
@ -25,6 +25,7 @@ where
f.render_widget(chart, f.size());
})
.unwrap();
let lines = lines.into_iter().map(|l| l.into()).collect();
let expected = Buffer::with_lines(lines);
terminal.backend().assert_buffer(&expected);
}