Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
63
vendor/tui/tests/backend_termion.rs
vendored
Normal file
63
vendor/tui/tests/backend_termion.rs
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#[cfg(feature = "termion")]
|
||||
#[test]
|
||||
fn backend_termion_should_only_write_diffs() -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::{fmt::Write, io::Cursor};
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
let mut stdout = Cursor::new(&mut bytes);
|
||||
{
|
||||
use tui::{
|
||||
backend::TermionBackend, layout::Rect, widgets::Paragraph, Terminal, TerminalOptions,
|
||||
Viewport,
|
||||
};
|
||||
let backend = TermionBackend::new(&mut stdout);
|
||||
let area = Rect::new(0, 0, 3, 1);
|
||||
let mut terminal = Terminal::with_options(
|
||||
backend,
|
||||
TerminalOptions {
|
||||
viewport: Viewport::fixed(area),
|
||||
},
|
||||
)?;
|
||||
terminal.draw(|f| {
|
||||
f.render_widget(Paragraph::new("a"), area);
|
||||
})?;
|
||||
terminal.draw(|f| {
|
||||
f.render_widget(Paragraph::new("ab"), area);
|
||||
})?;
|
||||
terminal.draw(|f| {
|
||||
f.render_widget(Paragraph::new("abc"), area);
|
||||
})?;
|
||||
}
|
||||
|
||||
let expected = {
|
||||
use termion::{color, cursor, style};
|
||||
let mut s = String::new();
|
||||
// First draw
|
||||
write!(s, "{}", cursor::Goto(1, 1))?;
|
||||
s.push('a');
|
||||
write!(s, "{}", color::Fg(color::Reset))?;
|
||||
write!(s, "{}", color::Bg(color::Reset))?;
|
||||
write!(s, "{}", style::Reset)?;
|
||||
write!(s, "{}", cursor::Hide)?;
|
||||
// Second draw
|
||||
write!(s, "{}", cursor::Goto(2, 1))?;
|
||||
s.push('b');
|
||||
write!(s, "{}", color::Fg(color::Reset))?;
|
||||
write!(s, "{}", color::Bg(color::Reset))?;
|
||||
write!(s, "{}", style::Reset)?;
|
||||
write!(s, "{}", cursor::Hide)?;
|
||||
// Third draw
|
||||
write!(s, "{}", cursor::Goto(3, 1))?;
|
||||
s.push('c');
|
||||
write!(s, "{}", color::Fg(color::Reset))?;
|
||||
write!(s, "{}", color::Bg(color::Reset))?;
|
||||
write!(s, "{}", style::Reset)?;
|
||||
write!(s, "{}", cursor::Hide)?;
|
||||
// Terminal drop
|
||||
write!(s, "{}", cursor::Show)?;
|
||||
s
|
||||
};
|
||||
assert_eq!(std::str::from_utf8(&bytes)?, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
36
vendor/tui/tests/terminal.rs
vendored
Normal file
36
vendor/tui/tests/terminal.rs
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use std::error::Error;
|
||||
use tui::{
|
||||
backend::{Backend, TestBackend},
|
||||
layout::Rect,
|
||||
widgets::Paragraph,
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn terminal_buffer_size_should_be_limited() {
|
||||
let backend = TestBackend::new(400, 400);
|
||||
let terminal = Terminal::new(backend).unwrap();
|
||||
let size = terminal.backend().size().unwrap();
|
||||
assert_eq!(size.width, 255);
|
||||
assert_eq!(size.height, 255);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_draw_returns_the_completed_frame() -> Result<(), Box<dyn Error>> {
|
||||
let backend = TestBackend::new(10, 10);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
let frame = terminal.draw(|f| {
|
||||
let paragrah = Paragraph::new("Test");
|
||||
f.render_widget(paragrah, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.buffer.get(0, 0).symbol, "T");
|
||||
assert_eq!(frame.area, Rect::new(0, 0, 10, 10));
|
||||
terminal.backend_mut().resize(8, 8);
|
||||
let frame = terminal.draw(|f| {
|
||||
let paragrah = Paragraph::new("test");
|
||||
f.render_widget(paragrah, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.buffer.get(0, 0).symbol, "t");
|
||||
assert_eq!(frame.area, Rect::new(0, 0, 8, 8));
|
||||
Ok(())
|
||||
}
|
||||
40
vendor/tui/tests/widgets_barchart.rs
vendored
Normal file
40
vendor/tui/tests/widgets_barchart.rs
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use tui::backend::TestBackend;
|
||||
use tui::buffer::Buffer;
|
||||
use tui::widgets::{BarChart, Block, Borders};
|
||||
use tui::Terminal;
|
||||
|
||||
#[test]
|
||||
fn widgets_barchart_not_full_below_max_value() {
|
||||
let test_case = |expected| {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let barchart = BarChart::default()
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.data(&[("empty", 0), ("half", 50), ("almost", 99), ("full", 100)])
|
||||
.max(100)
|
||||
.bar_width(7)
|
||||
.bar_gap(0);
|
||||
f.render_widget(barchart, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// check that bars fill up correctly up to max value
|
||||
test_case(Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ ▇▇▇▇▇▇▇███████│",
|
||||
"│ ██████████████│",
|
||||
"│ ██████████████│",
|
||||
"│ ▄▄▄▄▄▄▄██████████████│",
|
||||
"│ █████████████████████│",
|
||||
"│ █████████████████████│",
|
||||
"│ ██50█████99█████100██│",
|
||||
"│empty half almost full │",
|
||||
"└────────────────────────────┘",
|
||||
]));
|
||||
}
|
||||
346
vendor/tui/tests/widgets_block.rs
vendored
Normal file
346
vendor/tui/tests/widgets_block.rs
vendored
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::{Alignment, Rect},
|
||||
style::{Color, Style},
|
||||
text::Span,
|
||||
widgets::{Block, Borders},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn widgets_block_renders() {
|
||||
let backend = TestBackend::new(10, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let block = Block::default()
|
||||
.title(Span::styled("Title", Style::default().fg(Color::LightBlue)))
|
||||
.borders(Borders::ALL);
|
||||
f.render_widget(
|
||||
block,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 8,
|
||||
height: 8,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
"┌Title─┐ ",
|
||||
"│ │ ",
|
||||
"│ │ ",
|
||||
"│ │ ",
|
||||
"│ │ ",
|
||||
"│ │ ",
|
||||
"│ │ ",
|
||||
"└──────┘ ",
|
||||
" ",
|
||||
" ",
|
||||
]);
|
||||
for x in 1..=5 {
|
||||
expected.get_mut(x, 0).set_fg(Color::LightBlue);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_block_renders_on_small_areas() {
|
||||
let test_case = |block, area: Rect, expected| {
|
||||
let backend = TestBackend::new(area.width, area.height);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
f.render_widget(block, area);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
let one_cell_test_cases = [
|
||||
(Borders::NONE, "T"),
|
||||
(Borders::LEFT, "│"),
|
||||
(Borders::TOP, "T"),
|
||||
(Borders::RIGHT, "│"),
|
||||
(Borders::BOTTOM, "T"),
|
||||
(Borders::ALL, "┌"),
|
||||
];
|
||||
for (borders, symbol) in one_cell_test_cases.iter().cloned() {
|
||||
test_case(
|
||||
Block::default().title("Test").borders(borders),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
Buffer::empty(Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
}),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(borders),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 0,
|
||||
},
|
||||
Buffer::empty(Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 0,
|
||||
}),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(borders),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::empty(Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 1,
|
||||
}),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(borders),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec![symbol]),
|
||||
);
|
||||
}
|
||||
test_case(
|
||||
Block::default().title("Test").borders(Borders::LEFT),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["│Tes"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(Borders::RIGHT),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["Tes│"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(Borders::RIGHT),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["Tes│"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default()
|
||||
.title("Test")
|
||||
.borders(Borders::LEFT | Borders::RIGHT),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["│Te│"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(Borders::TOP),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["Test"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default().title("Test").borders(Borders::TOP),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 5,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["Test─"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default()
|
||||
.title("Test")
|
||||
.borders(Borders::LEFT | Borders::TOP),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 5,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["┌Test"]),
|
||||
);
|
||||
test_case(
|
||||
Block::default()
|
||||
.title("Test")
|
||||
.borders(Borders::LEFT | Borders::TOP),
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 6,
|
||||
height: 1,
|
||||
},
|
||||
Buffer::with_lines(vec!["┌Test─"]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_block_title_alignment() {
|
||||
let test_case = |alignment, borders, expected| {
|
||||
let backend = TestBackend::new(15, 2);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
let block = Block::default()
|
||||
.title(Span::styled("Title", Style::default()))
|
||||
.title_alignment(alignment)
|
||||
.borders(borders);
|
||||
|
||||
let area = Rect {
|
||||
x: 1,
|
||||
y: 0,
|
||||
width: 13,
|
||||
height: 2,
|
||||
};
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
f.render_widget(block, area);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// title top-left with all borders
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
Borders::ALL,
|
||||
Buffer::with_lines(vec![" ┌Title──────┐ ", " └───────────┘ "]),
|
||||
);
|
||||
|
||||
// title top-left without top border
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
Borders::LEFT | Borders::BOTTOM | Borders::RIGHT,
|
||||
Buffer::with_lines(vec![" │Title │ ", " └───────────┘ "]),
|
||||
);
|
||||
|
||||
// title top-left with no left border
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
Borders::TOP | Borders::RIGHT | Borders::BOTTOM,
|
||||
Buffer::with_lines(vec![" Title───────┐ ", " ────────────┘ "]),
|
||||
);
|
||||
|
||||
// title top-left without right border
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
Borders::LEFT | Borders::TOP | Borders::BOTTOM,
|
||||
Buffer::with_lines(vec![" ┌Title─────── ", " └──────────── "]),
|
||||
);
|
||||
|
||||
// title top-left without borders
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
Borders::NONE,
|
||||
Buffer::with_lines(vec![" Title ", " "]),
|
||||
);
|
||||
|
||||
// title center with all borders
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
Borders::ALL,
|
||||
Buffer::with_lines(vec![" ┌───Title───┐ ", " └───────────┘ "]),
|
||||
);
|
||||
|
||||
// title center without top border
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
Borders::LEFT | Borders::BOTTOM | Borders::RIGHT,
|
||||
Buffer::with_lines(vec![" │ Title │ ", " └───────────┘ "]),
|
||||
);
|
||||
|
||||
// title center with no left border
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
Borders::TOP | Borders::RIGHT | Borders::BOTTOM,
|
||||
Buffer::with_lines(vec![" ────Title───┐ ", " ────────────┘ "]),
|
||||
);
|
||||
|
||||
// title center without right border
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
Borders::LEFT | Borders::TOP | Borders::BOTTOM,
|
||||
Buffer::with_lines(vec![" ┌───Title──── ", " └──────────── "]),
|
||||
);
|
||||
|
||||
// title center without borders
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
Borders::NONE,
|
||||
Buffer::with_lines(vec![" Title ", " "]),
|
||||
);
|
||||
|
||||
// title top-right with all borders
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
Borders::ALL,
|
||||
Buffer::with_lines(vec![" ┌──────Title┐ ", " └───────────┘ "]),
|
||||
);
|
||||
|
||||
// title top-right without top border
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
Borders::LEFT | Borders::BOTTOM | Borders::RIGHT,
|
||||
Buffer::with_lines(vec![" │ Title│ ", " └───────────┘ "]),
|
||||
);
|
||||
|
||||
// title top-right with no left border
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
Borders::TOP | Borders::RIGHT | Borders::BOTTOM,
|
||||
Buffer::with_lines(vec![" ───────Title┐ ", " ────────────┘ "]),
|
||||
);
|
||||
|
||||
// title top-right without right border
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
Borders::LEFT | Borders::TOP | Borders::BOTTOM,
|
||||
Buffer::with_lines(vec![" ┌───────Title ", " └──────────── "]),
|
||||
);
|
||||
|
||||
// title top-right without borders
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
Borders::NONE,
|
||||
Buffer::with_lines(vec![" Title ", " "]),
|
||||
);
|
||||
}
|
||||
42
vendor/tui/tests/widgets_canvas.rs
vendored
Normal file
42
vendor/tui/tests/widgets_canvas.rs
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
style::{Color, Style},
|
||||
text::Span,
|
||||
widgets::canvas::Canvas,
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn widgets_canvas_draw_labels() {
|
||||
let backend = TestBackend::new(5, 5);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let label = String::from("test");
|
||||
let canvas = Canvas::default()
|
||||
.background_color(Color::Yellow)
|
||||
.x_bounds([0.0, 5.0])
|
||||
.y_bounds([0.0, 5.0])
|
||||
.paint(|ctx| {
|
||||
ctx.print(
|
||||
0.0,
|
||||
0.0,
|
||||
Span::styled(label.clone(), Style::default().fg(Color::Blue)),
|
||||
);
|
||||
});
|
||||
f.render_widget(canvas, f.size());
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut expected = Buffer::with_lines(vec![" ", " ", " ", " ", "test "]);
|
||||
for row in 0..5 {
|
||||
for col in 0..5 {
|
||||
expected.get_mut(col, row).set_bg(Color::Yellow);
|
||||
}
|
||||
}
|
||||
for col in 0..4 {
|
||||
expected.get_mut(col, 4).set_fg(Color::Blue);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected)
|
||||
}
|
||||
621
vendor/tui/tests/widgets_chart.rs
vendored
Normal file
621
vendor/tui/tests/widgets_chart.rs
vendored
Normal file
|
|
@ -0,0 +1,621 @@
|
|||
use tui::layout::Alignment;
|
||||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::{Color, Style},
|
||||
symbols,
|
||||
text::Span,
|
||||
widgets::{Axis, Block, Borders, Chart, Dataset, GraphType::Line},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
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>)
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let backend = TestBackend::new(width, height);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let chart = Chart::new(vec![]).x_axis(x_axis).y_axis(y_axis);
|
||||
f.render_widget(chart, f.size());
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(lines);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_can_render_on_small_areas() {
|
||||
let test_case = |width, height| {
|
||||
let backend = TestBackend::new(width, height);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let datasets = vec![Dataset::default()
|
||||
.marker(symbols::Marker::Braille)
|
||||
.style(Style::default().fg(Color::Magenta))
|
||||
.data(&[(0.0, 0.0)])];
|
||||
let chart = Chart::new(datasets)
|
||||
.block(Block::default().title("Plot").borders(Borders::ALL))
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 0.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
)
|
||||
.y_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 0.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
);
|
||||
f.render_widget(chart, f.size());
|
||||
})
|
||||
.unwrap();
|
||||
};
|
||||
test_case(0, 0);
|
||||
test_case(0, 1);
|
||||
test_case(1, 0);
|
||||
test_case(1, 1);
|
||||
test_case(2, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_handles_long_labels() {
|
||||
let test_case = |x_labels, y_labels, x_alignment, lines| {
|
||||
let mut x_axis = Axis::default().bounds([0.0, 1.0]);
|
||||
if let Some((left_label, right_label)) = x_labels {
|
||||
x_axis = x_axis
|
||||
.labels(vec![Span::from(left_label), Span::from(right_label)])
|
||||
.labels_alignment(x_alignment);
|
||||
}
|
||||
|
||||
let mut y_axis = Axis::default().bounds([0.0, 1.0]);
|
||||
if let Some((left_label, right_label)) = y_labels {
|
||||
y_axis = y_axis.labels(vec![Span::from(left_label), Span::from(right_label)]);
|
||||
}
|
||||
|
||||
axis_test_case(10, 5, x_axis, y_axis, lines);
|
||||
};
|
||||
|
||||
test_case(
|
||||
Some(("AAAA", "B")),
|
||||
None,
|
||||
Alignment::Left,
|
||||
vec![
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ───────",
|
||||
"AAA B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Some(("A", "BBBB")),
|
||||
None,
|
||||
Alignment::Left,
|
||||
vec![
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ─────────",
|
||||
"A BBBB",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Some(("AAAAAAAAAAA", "B")),
|
||||
None,
|
||||
Alignment::Left,
|
||||
vec![
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ───────",
|
||||
"AAA B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Some(("A", "B")),
|
||||
Some(("CCCCCCC", "D")),
|
||||
Alignment::Left,
|
||||
vec![
|
||||
"D │ ",
|
||||
" │ ",
|
||||
"CCC│ ",
|
||||
" └──────",
|
||||
" A B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Some(("AAAAAAAAAA", "B")),
|
||||
Some(("C", "D")),
|
||||
Alignment::Center,
|
||||
vec![
|
||||
"D │ ",
|
||||
" │ ",
|
||||
"C │ ",
|
||||
" └──────",
|
||||
"AAAAAAA B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Some(("AAAAAAA", "B")),
|
||||
Some(("C", "D")),
|
||||
Alignment::Right,
|
||||
vec![
|
||||
"D│ ",
|
||||
" │ ",
|
||||
"C│ ",
|
||||
" └────────",
|
||||
" AAAAA B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Some(("AAAAAAA", "BBBBBBB")),
|
||||
Some(("C", "D")),
|
||||
Alignment::Right,
|
||||
vec![
|
||||
"D│ ",
|
||||
" │ ",
|
||||
"C│ ",
|
||||
" └────────",
|
||||
" AAAAABBBB",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_handles_x_axis_labels_alignments() {
|
||||
let test_case = |y_alignment, lines| {
|
||||
let x_axis = Axis::default()
|
||||
.labels(vec![Span::from("AAAA"), Span::from("B"), Span::from("C")])
|
||||
.labels_alignment(y_alignment);
|
||||
|
||||
let y_axis = Axis::default();
|
||||
|
||||
axis_test_case(10, 5, x_axis, y_axis, lines);
|
||||
};
|
||||
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
vec![
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ───────",
|
||||
"AAA B C",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
vec![
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ────────",
|
||||
"AAAA B C",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
vec![
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
"──────────",
|
||||
"AAA B C",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_handles_y_axis_labels_alignments() {
|
||||
let test_case = |y_alignment, lines| {
|
||||
let x_axis = Axis::default().labels(create_labels(&["AAAAA", "B"]));
|
||||
|
||||
let y_axis = Axis::default()
|
||||
.labels(create_labels(&["C", "D"]))
|
||||
.labels_alignment(y_alignment);
|
||||
|
||||
axis_test_case(20, 5, x_axis, y_axis, lines);
|
||||
};
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
vec![
|
||||
"D │ ",
|
||||
" │ ",
|
||||
"C │ ",
|
||||
" └───────────────",
|
||||
"AAAAA B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
vec![
|
||||
" D │ ",
|
||||
" │ ",
|
||||
" C │ ",
|
||||
" └───────────────",
|
||||
"AAAAA B",
|
||||
],
|
||||
);
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
vec![
|
||||
" D│ ",
|
||||
" │ ",
|
||||
" C│ ",
|
||||
" └───────────────",
|
||||
"AAAAA B",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_can_have_axis_with_zero_length_bounds() {
|
||||
let backend = TestBackend::new(100, 100);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let datasets = vec![Dataset::default()
|
||||
.marker(symbols::Marker::Braille)
|
||||
.style(Style::default().fg(Color::Magenta))
|
||||
.data(&[(0.0, 0.0)])];
|
||||
let chart = Chart::new(datasets)
|
||||
.block(Block::default().title("Plot").borders(Borders::ALL))
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 0.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
)
|
||||
.y_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 0.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
);
|
||||
f.render_widget(
|
||||
chart,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_handles_overflows() {
|
||||
let backend = TestBackend::new(80, 30);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let datasets = vec![Dataset::default()
|
||||
.marker(symbols::Marker::Braille)
|
||||
.style(Style::default().fg(Color::Magenta))
|
||||
.data(&[
|
||||
(1_588_298_471.0, 1.0),
|
||||
(1_588_298_473.0, 0.0),
|
||||
(1_588_298_496.0, 1.0),
|
||||
])];
|
||||
let chart = Chart::new(datasets)
|
||||
.block(Block::default().title("Plot").borders(Borders::ALL))
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.bounds([1_588_298_471.0, 1_588_992_600.0])
|
||||
.labels(create_labels(&["1588298471.0", "1588992600.0"])),
|
||||
)
|
||||
.y_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 1.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
);
|
||||
f.render_widget(
|
||||
chart,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 80,
|
||||
height: 30,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_can_have_empty_datasets() {
|
||||
let backend = TestBackend::new(100, 100);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let datasets = vec![Dataset::default().data(&[]).graph_type(Line)];
|
||||
let chart = Chart::new(datasets)
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Empty Dataset With Line")
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 0.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
)
|
||||
.y_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 1.0])
|
||||
.labels(create_labels(&["0.0", "1.0"])),
|
||||
);
|
||||
f.render_widget(
|
||||
chart,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_chart_can_have_a_legend() {
|
||||
let backend = TestBackend::new(60, 30);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let datasets = vec![
|
||||
Dataset::default()
|
||||
.name("Dataset 1")
|
||||
.style(Style::default().fg(Color::Blue))
|
||||
.data(&[
|
||||
(0.0, 0.0),
|
||||
(10.0, 1.0),
|
||||
(20.0, 2.0),
|
||||
(30.0, 3.0),
|
||||
(40.0, 4.0),
|
||||
(50.0, 5.0),
|
||||
(60.0, 6.0),
|
||||
(70.0, 7.0),
|
||||
(80.0, 8.0),
|
||||
(90.0, 9.0),
|
||||
(100.0, 10.0),
|
||||
])
|
||||
.graph_type(Line),
|
||||
Dataset::default()
|
||||
.name("Dataset 2")
|
||||
.style(Style::default().fg(Color::Green))
|
||||
.data(&[
|
||||
(0.0, 10.0),
|
||||
(10.0, 9.0),
|
||||
(20.0, 8.0),
|
||||
(30.0, 7.0),
|
||||
(40.0, 6.0),
|
||||
(50.0, 5.0),
|
||||
(60.0, 4.0),
|
||||
(70.0, 3.0),
|
||||
(80.0, 2.0),
|
||||
(90.0, 1.0),
|
||||
(100.0, 0.0),
|
||||
])
|
||||
.graph_type(Line),
|
||||
];
|
||||
let chart = Chart::new(datasets)
|
||||
.style(Style::default().bg(Color::White))
|
||||
.block(Block::default().title("Chart Test").borders(Borders::ALL))
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 100.0])
|
||||
.title(Span::styled("X Axis", Style::default().fg(Color::Yellow)))
|
||||
.labels(create_labels(&["0.0", "50.0", "100.0"])),
|
||||
)
|
||||
.y_axis(
|
||||
Axis::default()
|
||||
.bounds([0.0, 10.0])
|
||||
.title("Y Axis")
|
||||
.labels(create_labels(&["0.0", "5.0", "10.0"])),
|
||||
);
|
||||
f.render_widget(
|
||||
chart,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 60,
|
||||
height: 30,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
"┌Chart Test────────────────────────────────────────────────┐",
|
||||
"│10.0│Y Axis ┌─────────┐│",
|
||||
"│ │ •• │Dataset 1││",
|
||||
"│ │ •• │Dataset 2││",
|
||||
"│ │ •• └─────────┘│",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ ••• •• │",
|
||||
"│ │ ••• │",
|
||||
"│5.0 │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ ••• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• ••• │",
|
||||
"│ │ •• •• │",
|
||||
"│ │ •• •• │",
|
||||
"│0.0 │• X Axis│",
|
||||
"│ └─────────────────────────────────────────────────────│",
|
||||
"│ 0.0 50.0 100.0│",
|
||||
"└──────────────────────────────────────────────────────────┘",
|
||||
]);
|
||||
|
||||
// Set expected backgound color
|
||||
for row in 0..30 {
|
||||
for col in 0..60 {
|
||||
expected.get_mut(col, row).set_bg(Color::White);
|
||||
}
|
||||
}
|
||||
|
||||
// Set expected colors of the first dataset
|
||||
let line1 = vec![
|
||||
(48, 5),
|
||||
(49, 5),
|
||||
(46, 6),
|
||||
(47, 6),
|
||||
(44, 7),
|
||||
(45, 7),
|
||||
(42, 8),
|
||||
(43, 8),
|
||||
(40, 9),
|
||||
(41, 9),
|
||||
(38, 10),
|
||||
(39, 10),
|
||||
(36, 11),
|
||||
(37, 11),
|
||||
(34, 12),
|
||||
(35, 12),
|
||||
(33, 13),
|
||||
(30, 14),
|
||||
(31, 14),
|
||||
(28, 15),
|
||||
(29, 15),
|
||||
(25, 16),
|
||||
(26, 16),
|
||||
(27, 16),
|
||||
(23, 17),
|
||||
(24, 17),
|
||||
(21, 18),
|
||||
(22, 18),
|
||||
(19, 19),
|
||||
(20, 19),
|
||||
(17, 20),
|
||||
(18, 20),
|
||||
(15, 21),
|
||||
(16, 21),
|
||||
(13, 22),
|
||||
(14, 22),
|
||||
(11, 23),
|
||||
(12, 23),
|
||||
(9, 24),
|
||||
(10, 24),
|
||||
(7, 25),
|
||||
(8, 25),
|
||||
(6, 26),
|
||||
];
|
||||
let legend1 = vec![
|
||||
(49, 2),
|
||||
(50, 2),
|
||||
(51, 2),
|
||||
(52, 2),
|
||||
(53, 2),
|
||||
(54, 2),
|
||||
(55, 2),
|
||||
(56, 2),
|
||||
(57, 2),
|
||||
];
|
||||
for (col, row) in line1 {
|
||||
expected.get_mut(col, row).set_fg(Color::Blue);
|
||||
}
|
||||
for (col, row) in legend1 {
|
||||
expected.get_mut(col, row).set_fg(Color::Blue);
|
||||
}
|
||||
|
||||
// Set expected colors of the second dataset
|
||||
let line2 = vec![
|
||||
(8, 2),
|
||||
(9, 2),
|
||||
(10, 3),
|
||||
(11, 3),
|
||||
(12, 4),
|
||||
(13, 4),
|
||||
(14, 5),
|
||||
(15, 5),
|
||||
(16, 6),
|
||||
(17, 6),
|
||||
(18, 7),
|
||||
(19, 7),
|
||||
(20, 8),
|
||||
(21, 8),
|
||||
(22, 9),
|
||||
(23, 9),
|
||||
(24, 10),
|
||||
(25, 10),
|
||||
(26, 11),
|
||||
(27, 11),
|
||||
(28, 12),
|
||||
(29, 12),
|
||||
(30, 12),
|
||||
(31, 13),
|
||||
(32, 13),
|
||||
(33, 14),
|
||||
(34, 14),
|
||||
(35, 15),
|
||||
(36, 15),
|
||||
(37, 16),
|
||||
(38, 16),
|
||||
(39, 17),
|
||||
(40, 17),
|
||||
(41, 18),
|
||||
(42, 18),
|
||||
(43, 19),
|
||||
(44, 19),
|
||||
(45, 20),
|
||||
(46, 20),
|
||||
(47, 21),
|
||||
(48, 21),
|
||||
(49, 22),
|
||||
(50, 22),
|
||||
(51, 23),
|
||||
(52, 23),
|
||||
(53, 23),
|
||||
(54, 24),
|
||||
(55, 24),
|
||||
(56, 25),
|
||||
(57, 25),
|
||||
];
|
||||
let legend2 = vec![
|
||||
(49, 3),
|
||||
(50, 3),
|
||||
(51, 3),
|
||||
(52, 3),
|
||||
(53, 3),
|
||||
(54, 3),
|
||||
(55, 3),
|
||||
(56, 3),
|
||||
(57, 3),
|
||||
];
|
||||
for (col, row) in line2 {
|
||||
expected.get_mut(col, row).set_fg(Color::Green);
|
||||
}
|
||||
for (col, row) in legend2 {
|
||||
expected.get_mut(col, row).set_fg(Color::Green);
|
||||
}
|
||||
|
||||
// Set expected colors of the x axis
|
||||
let x_axis_title = vec![(53, 26), (54, 26), (55, 26), (56, 26), (57, 26), (58, 26)];
|
||||
for (col, row) in x_axis_title {
|
||||
expected.get_mut(col, row).set_fg(Color::Yellow);
|
||||
}
|
||||
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
253
vendor/tui/tests/widgets_gauge.rs
vendored
Normal file
253
vendor/tui/tests/widgets_gauge.rs
vendored
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
symbols,
|
||||
text::Span,
|
||||
widgets::{Block, Borders, Gauge, LineGauge},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn widgets_gauge_renders() {
|
||||
let backend = TestBackend::new(40, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(2)
|
||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Percentage").borders(Borders::ALL))
|
||||
.gauge_style(Style::default().bg(Color::Blue).fg(Color::Red))
|
||||
.use_unicode(true)
|
||||
.percent(43);
|
||||
f.render_widget(gauge, chunks[0]);
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Ratio").borders(Borders::ALL))
|
||||
.gauge_style(Style::default().bg(Color::Blue).fg(Color::Red))
|
||||
.use_unicode(true)
|
||||
.ratio(0.511_313_934_313_1);
|
||||
f.render_widget(gauge, chunks[1]);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
" ",
|
||||
" ",
|
||||
" ┌Percentage────────────────────────┐ ",
|
||||
" │ ▋43% │ ",
|
||||
" └──────────────────────────────────┘ ",
|
||||
" ┌Ratio─────────────────────────────┐ ",
|
||||
" │ 51% │ ",
|
||||
" └──────────────────────────────────┘ ",
|
||||
" ",
|
||||
" ",
|
||||
]);
|
||||
|
||||
for i in 3..17 {
|
||||
expected
|
||||
.get_mut(i, 3)
|
||||
.set_bg(Color::Red)
|
||||
.set_fg(Color::Blue);
|
||||
}
|
||||
for i in 17..37 {
|
||||
expected
|
||||
.get_mut(i, 3)
|
||||
.set_bg(Color::Blue)
|
||||
.set_fg(Color::Red);
|
||||
}
|
||||
|
||||
for i in 3..20 {
|
||||
expected
|
||||
.get_mut(i, 6)
|
||||
.set_bg(Color::Red)
|
||||
.set_fg(Color::Blue);
|
||||
}
|
||||
for i in 20..37 {
|
||||
expected
|
||||
.get_mut(i, 6)
|
||||
.set_bg(Color::Blue)
|
||||
.set_fg(Color::Red);
|
||||
}
|
||||
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_gauge_renders_no_unicode() {
|
||||
let backend = TestBackend::new(40, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(2)
|
||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Percentage").borders(Borders::ALL))
|
||||
.percent(43)
|
||||
.use_unicode(false);
|
||||
f.render_widget(gauge, chunks[0]);
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Ratio").borders(Borders::ALL))
|
||||
.ratio(0.211_313_934_313_1)
|
||||
.use_unicode(false);
|
||||
f.render_widget(gauge, chunks[1]);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![
|
||||
" ",
|
||||
" ",
|
||||
" ┌Percentage────────────────────────┐ ",
|
||||
" │ 43% │ ",
|
||||
" └──────────────────────────────────┘ ",
|
||||
" ┌Ratio─────────────────────────────┐ ",
|
||||
" │ 21% │ ",
|
||||
" └──────────────────────────────────┘ ",
|
||||
" ",
|
||||
" ",
|
||||
]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_gauge_applies_styles() {
|
||||
let backend = TestBackend::new(12, 5);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let gauge = Gauge::default()
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Span::styled("Test", Style::default().fg(Color::Red)))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.gauge_style(Style::default().fg(Color::Blue).bg(Color::Red))
|
||||
.percent(43)
|
||||
.label(Span::styled(
|
||||
"43%",
|
||||
Style::default()
|
||||
.fg(Color::Green)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
));
|
||||
f.render_widget(gauge, f.size());
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
"┌Test──────┐",
|
||||
"│ │",
|
||||
"│ 43% │",
|
||||
"│ │",
|
||||
"└──────────┘",
|
||||
]);
|
||||
// title
|
||||
expected.set_style(Rect::new(1, 0, 4, 1), Style::default().fg(Color::Red));
|
||||
// gauge area
|
||||
expected.set_style(
|
||||
Rect::new(1, 1, 10, 3),
|
||||
Style::default().fg(Color::Blue).bg(Color::Red),
|
||||
);
|
||||
// filled area
|
||||
for y in 1..4 {
|
||||
expected.set_style(
|
||||
Rect::new(1, y, 4, 1),
|
||||
// filled style is invert of gauge_style
|
||||
Style::default().fg(Color::Red).bg(Color::Blue),
|
||||
);
|
||||
}
|
||||
// label (foreground and modifier from label style)
|
||||
expected.set_style(
|
||||
Rect::new(4, 2, 1, 1),
|
||||
Style::default()
|
||||
.fg(Color::Green)
|
||||
// "4" is in the filled area so background is gauge_style foreground
|
||||
.bg(Color::Blue)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
expected.set_style(
|
||||
Rect::new(5, 2, 2, 1),
|
||||
Style::default()
|
||||
.fg(Color::Green)
|
||||
// "3%" is not in the filled area so background is gauge_style background
|
||||
.bg(Color::Red)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_gauge_supports_large_labels() {
|
||||
let backend = TestBackend::new(10, 1);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let gauge = Gauge::default()
|
||||
.percent(43)
|
||||
.label("43333333333333333333333333333%");
|
||||
f.render_widget(gauge, f.size());
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec!["4333333333"]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_line_gauge_renders() {
|
||||
let backend = TestBackend::new(20, 4);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let gauge = LineGauge::default()
|
||||
.gauge_style(Style::default().fg(Color::Green).bg(Color::White))
|
||||
.ratio(0.43);
|
||||
f.render_widget(
|
||||
gauge,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 20,
|
||||
height: 1,
|
||||
},
|
||||
);
|
||||
let gauge = LineGauge::default()
|
||||
.block(Block::default().title("Gauge 2").borders(Borders::ALL))
|
||||
.gauge_style(Style::default().fg(Color::Green))
|
||||
.line_set(symbols::line::THICK)
|
||||
.ratio(0.211_313_934_313_1);
|
||||
f.render_widget(
|
||||
gauge,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 1,
|
||||
width: 20,
|
||||
height: 3,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
"43% ────────────────",
|
||||
"┌Gauge 2───────────┐",
|
||||
"│21% ━━━━━━━━━━━━━━│",
|
||||
"└──────────────────┘",
|
||||
]);
|
||||
for col in 4..10 {
|
||||
expected.get_mut(col, 0).set_fg(Color::Green);
|
||||
}
|
||||
for col in 10..20 {
|
||||
expected.get_mut(col, 0).set_fg(Color::White);
|
||||
}
|
||||
for col in 5..7 {
|
||||
expected.get_mut(col, 2).set_fg(Color::Green);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
200
vendor/tui/tests/widgets_list.rs
vendored
Normal file
200
vendor/tui/tests/widgets_list.rs
vendored
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::{Color, Style},
|
||||
symbols,
|
||||
text::Spans,
|
||||
widgets::{Block, Borders, List, ListItem, ListState},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn widgets_list_should_highlight_the_selected_item() {
|
||||
let backend = TestBackend::new(10, 3);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let mut state = ListState::default();
|
||||
state.select(Some(1));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let items = vec![
|
||||
ListItem::new("Item 1"),
|
||||
ListItem::new("Item 2"),
|
||||
ListItem::new("Item 3"),
|
||||
];
|
||||
let list = List::new(items)
|
||||
.highlight_style(Style::default().bg(Color::Yellow))
|
||||
.highlight_symbol(">> ");
|
||||
f.render_stateful_widget(list, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![" Item 1 ", ">> Item 2 ", " Item 3 "]);
|
||||
for x in 0..10 {
|
||||
expected.get_mut(x, 1).set_bg(Color::Yellow);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_list_should_truncate_items() {
|
||||
let backend = TestBackend::new(10, 2);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
struct TruncateTestCase<'a> {
|
||||
selected: Option<usize>,
|
||||
items: Vec<ListItem<'a>>,
|
||||
expected: Buffer,
|
||||
}
|
||||
|
||||
let cases = vec![
|
||||
// An item is selected
|
||||
TruncateTestCase {
|
||||
selected: Some(0),
|
||||
items: vec![
|
||||
ListItem::new("A very long line"),
|
||||
ListItem::new("A very long line"),
|
||||
],
|
||||
expected: Buffer::with_lines(vec![
|
||||
format!(">> A ve{} ", symbols::line::VERTICAL),
|
||||
format!(" A ve{} ", symbols::line::VERTICAL),
|
||||
]),
|
||||
},
|
||||
// No item is selected
|
||||
TruncateTestCase {
|
||||
selected: None,
|
||||
items: vec![
|
||||
ListItem::new("A very long line"),
|
||||
ListItem::new("A very long line"),
|
||||
],
|
||||
expected: Buffer::with_lines(vec![
|
||||
format!("A very {} ", symbols::line::VERTICAL),
|
||||
format!("A very {} ", symbols::line::VERTICAL),
|
||||
]),
|
||||
},
|
||||
];
|
||||
for case in cases {
|
||||
let mut state = ListState::default();
|
||||
state.select(case.selected);
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let list = List::new(case.items.clone())
|
||||
.block(Block::default().borders(Borders::RIGHT))
|
||||
.highlight_symbol(">> ");
|
||||
f.render_stateful_widget(list, Rect::new(0, 0, 8, 2), &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&case.expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_list_should_clamp_offset_if_items_are_removed() {
|
||||
let backend = TestBackend::new(10, 4);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let mut state = ListState::default();
|
||||
|
||||
// render with 6 items => offset will be at 2
|
||||
state.select(Some(5));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let items = vec![
|
||||
ListItem::new("Item 0"),
|
||||
ListItem::new("Item 1"),
|
||||
ListItem::new("Item 2"),
|
||||
ListItem::new("Item 3"),
|
||||
ListItem::new("Item 4"),
|
||||
ListItem::new("Item 5"),
|
||||
];
|
||||
let list = List::new(items).highlight_symbol(">> ");
|
||||
f.render_stateful_widget(list, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![" Item 2 ", " Item 3 ", " Item 4 ", ">> Item 5 "]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
|
||||
// render again with 1 items => check offset is clamped to 1
|
||||
state.select(Some(1));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let items = vec![ListItem::new("Item 3")];
|
||||
let list = List::new(items).highlight_symbol(">> ");
|
||||
f.render_stateful_widget(list, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![" Item 3 ", " ", " ", " "]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_list_should_display_multiline_items() {
|
||||
let backend = TestBackend::new(10, 6);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let mut state = ListState::default();
|
||||
state.select(Some(1));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let items = vec![
|
||||
ListItem::new(vec![Spans::from("Item 1"), Spans::from("Item 1a")]),
|
||||
ListItem::new(vec![Spans::from("Item 2"), Spans::from("Item 2b")]),
|
||||
ListItem::new(vec![Spans::from("Item 3"), Spans::from("Item 3c")]),
|
||||
];
|
||||
let list = List::new(items)
|
||||
.highlight_style(Style::default().bg(Color::Yellow))
|
||||
.highlight_symbol(">> ");
|
||||
f.render_stateful_widget(list, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
" Item 1 ",
|
||||
" Item 1a",
|
||||
">> Item 2 ",
|
||||
" Item 2b",
|
||||
" Item 3 ",
|
||||
" Item 3c",
|
||||
]);
|
||||
for x in 0..10 {
|
||||
expected.get_mut(x, 2).set_bg(Color::Yellow);
|
||||
expected.get_mut(x, 3).set_bg(Color::Yellow);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_list_should_repeat_highlight_symbol() {
|
||||
let backend = TestBackend::new(10, 6);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let mut state = ListState::default();
|
||||
state.select(Some(1));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let items = vec![
|
||||
ListItem::new(vec![Spans::from("Item 1"), Spans::from("Item 1a")]),
|
||||
ListItem::new(vec![Spans::from("Item 2"), Spans::from("Item 2b")]),
|
||||
ListItem::new(vec![Spans::from("Item 3"), Spans::from("Item 3c")]),
|
||||
];
|
||||
let list = List::new(items)
|
||||
.highlight_style(Style::default().bg(Color::Yellow))
|
||||
.highlight_symbol(">> ")
|
||||
.repeat_highlight_symbol(true);
|
||||
f.render_stateful_widget(list, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
" Item 1 ",
|
||||
" Item 1a",
|
||||
">> Item 2 ",
|
||||
">> Item 2b",
|
||||
" Item 3 ",
|
||||
" Item 3c",
|
||||
]);
|
||||
for x in 0..10 {
|
||||
expected.get_mut(x, 2).set_bg(Color::Yellow);
|
||||
expected.get_mut(x, 3).set_bg(Color::Yellow);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
220
vendor/tui/tests/widgets_paragraph.rs
vendored
Normal file
220
vendor/tui/tests/widgets_paragraph.rs
vendored
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Alignment,
|
||||
text::{Span, Spans, Text},
|
||||
widgets::{Block, Borders, Paragraph, Wrap},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
const SAMPLE_STRING: &str = "The library is based on the principle of immediate rendering with \
|
||||
intermediate buffers. This means that at each new frame you should build all widgets that are \
|
||||
supposed to be part of the UI. While providing a great flexibility for rich and \
|
||||
interactive UI, this may introduce overhead for highly dynamic content.";
|
||||
|
||||
#[test]
|
||||
fn widgets_paragraph_can_wrap_its_content() {
|
||||
let test_case = |alignment, expected| {
|
||||
let backend = TestBackend::new(20, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let text = vec![Spans::from(SAMPLE_STRING)];
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.alignment(alignment)
|
||||
.wrap(Wrap { trim: true });
|
||||
f.render_widget(paragraph, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
Buffer::with_lines(vec![
|
||||
"┌──────────────────┐",
|
||||
"│The library is │",
|
||||
"│based on the │",
|
||||
"│principle of │",
|
||||
"│immediate │",
|
||||
"│rendering with │",
|
||||
"│intermediate │",
|
||||
"│buffers. This │",
|
||||
"│means that at each│",
|
||||
"└──────────────────┘",
|
||||
]),
|
||||
);
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
Buffer::with_lines(vec![
|
||||
"┌──────────────────┐",
|
||||
"│ The library is│",
|
||||
"│ based on the│",
|
||||
"│ principle of│",
|
||||
"│ immediate│",
|
||||
"│ rendering with│",
|
||||
"│ intermediate│",
|
||||
"│ buffers. This│",
|
||||
"│means that at each│",
|
||||
"└──────────────────┘",
|
||||
]),
|
||||
);
|
||||
test_case(
|
||||
Alignment::Center,
|
||||
Buffer::with_lines(vec![
|
||||
"┌──────────────────┐",
|
||||
"│ The library is │",
|
||||
"│ based on the │",
|
||||
"│ principle of │",
|
||||
"│ immediate │",
|
||||
"│ rendering with │",
|
||||
"│ intermediate │",
|
||||
"│ buffers. This │",
|
||||
"│means that at each│",
|
||||
"└──────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_paragraph_renders_double_width_graphemes() {
|
||||
let backend = TestBackend::new(10, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
let s = "コンピュータ上で文字を扱う場合、典型的には文字による通信を行う場合にその両端点では、";
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let text = vec![Spans::from(s)];
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.wrap(Wrap { trim: true });
|
||||
f.render_widget(paragraph, size);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let expected = Buffer::with_lines(vec![
|
||||
"┌────────┐",
|
||||
"│コンピュ│",
|
||||
"│ータ上で│",
|
||||
"│文字を扱│",
|
||||
"│う場合、│",
|
||||
"│典型的に│",
|
||||
"│は文字に│",
|
||||
"│よる通信│",
|
||||
"│を行う場│",
|
||||
"└────────┘",
|
||||
]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_paragraph_renders_mixed_width_graphemes() {
|
||||
let backend = TestBackend::new(10, 7);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
let s = "aコンピュータ上で文字を扱う場合、";
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let text = vec![Spans::from(s)];
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.wrap(Wrap { trim: true });
|
||||
f.render_widget(paragraph, size);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let expected = Buffer::with_lines(vec![
|
||||
// The internal width is 8 so only 4 slots for double-width characters.
|
||||
"┌────────┐",
|
||||
"│aコンピ │", // Here we have 1 latin character so only 3 double-width ones can fit.
|
||||
"│ュータ上│",
|
||||
"│で文字を│",
|
||||
"│扱う場合│",
|
||||
"│、 │",
|
||||
"└────────┘",
|
||||
]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_paragraph_can_wrap_with_a_trailing_nbsp() {
|
||||
let nbsp: &str = "\u{00a0}";
|
||||
let line = Spans::from(vec![Span::raw("NBSP"), Span::raw(nbsp)]);
|
||||
let backend = TestBackend::new(20, 3);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let expected = Buffer::with_lines(vec![
|
||||
"┌──────────────────┐",
|
||||
"│NBSP\u{00a0} │",
|
||||
"└──────────────────┘",
|
||||
]);
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
|
||||
let paragraph = Paragraph::new(line).block(Block::default().borders(Borders::ALL));
|
||||
f.render_widget(paragraph, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
#[test]
|
||||
fn widgets_paragraph_can_scroll_horizontally() {
|
||||
let test_case = |alignment, scroll, expected| {
|
||||
let backend = TestBackend::new(20, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let text = Text::from(
|
||||
"段落现在可以水平滚动了!\nParagraph can scroll horizontally!\nShort line",
|
||||
);
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.alignment(alignment)
|
||||
.scroll(scroll);
|
||||
f.render_widget(paragraph, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
test_case(
|
||||
Alignment::Left,
|
||||
(0, 7),
|
||||
Buffer::with_lines(vec![
|
||||
"┌──────────────────┐",
|
||||
"│在可以水平滚动了!│",
|
||||
"│ph can scroll hori│",
|
||||
"│ine │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└──────────────────┘",
|
||||
]),
|
||||
);
|
||||
// only support Alignment::Left
|
||||
test_case(
|
||||
Alignment::Right,
|
||||
(0, 7),
|
||||
Buffer::with_lines(vec![
|
||||
"┌──────────────────┐",
|
||||
"│段落现在可以水平滚│",
|
||||
"│Paragraph can scro│",
|
||||
"│ Short line│",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└──────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
823
vendor/tui/tests/widgets_table.rs
vendored
Normal file
823
vendor/tui/tests/widgets_table.rs
vendored
Normal file
|
|
@ -0,0 +1,823 @@
|
|||
use tui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Constraint,
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Borders, Cell, Row, Table, TableState},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn widgets_table_column_spacing_can_be_changed() {
|
||||
let test_case = |column_spacing, expected| {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(&[
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
])
|
||||
.column_spacing(column_spacing);
|
||||
f.render_widget(table, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// no space between columns
|
||||
test_case(
|
||||
0,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1Head2Head3 │",
|
||||
"│ │",
|
||||
"│Row11Row12Row13 │",
|
||||
"│Row21Row22Row23 │",
|
||||
"│Row31Row32Row33 │",
|
||||
"│Row41Row42Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// one space between columns
|
||||
test_case(
|
||||
1,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// enough space to just not hide the third column
|
||||
test_case(
|
||||
6,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// enough space to hide part of the third column
|
||||
test_case(
|
||||
7,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head│",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row1│",
|
||||
"│Row21 Row22 Row2│",
|
||||
"│Row31 Row32 Row3│",
|
||||
"│Row41 Row42 Row4│",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_columns_widths_can_use_fixed_length_constraints() {
|
||||
let test_case = |widths, expected| {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(widths);
|
||||
f.render_widget(table, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// columns of zero width show nothing
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Length(0),
|
||||
Constraint::Length(0),
|
||||
Constraint::Length(0),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of 1 width trim
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(1),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│H H H │",
|
||||
"│ │",
|
||||
"│R R R │",
|
||||
"│R R R │",
|
||||
"│R R R │",
|
||||
"│R R R │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of large width just before pushing a column off
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Length(8),
|
||||
Constraint::Length(8),
|
||||
Constraint::Length(8),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_columns_widths_can_use_percentage_constraints() {
|
||||
let test_case = |widths, expected| {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(widths)
|
||||
.column_spacing(0);
|
||||
f.render_widget(table, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// columns of zero width show nothing
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(0),
|
||||
Constraint::Percentage(0),
|
||||
Constraint::Percentage(0),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of not enough width trims the data
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(11),
|
||||
Constraint::Percentage(11),
|
||||
Constraint::Percentage(11),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│HeaHeaHea │",
|
||||
"│ │",
|
||||
"│RowRowRow │",
|
||||
"│RowRowRow │",
|
||||
"│RowRowRow │",
|
||||
"│RowRowRow │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of large width just before pushing a column off
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(33),
|
||||
Constraint::Percentage(33),
|
||||
Constraint::Percentage(33),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// percentages summing to 100 should give equal widths
|
||||
test_case(
|
||||
&[Constraint::Percentage(50), Constraint::Percentage(50)],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 │",
|
||||
"│Row21 Row22 │",
|
||||
"│Row31 Row32 │",
|
||||
"│Row41 Row42 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_columns_widths_can_use_mixed_constraints() {
|
||||
let test_case = |widths, expected| {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(widths);
|
||||
f.render_widget(table, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// columns of zero width show nothing
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(0),
|
||||
Constraint::Length(0),
|
||||
Constraint::Percentage(0),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of not enough width trims the data
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(11),
|
||||
Constraint::Length(20),
|
||||
Constraint::Percentage(11),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Hea Head2 He │",
|
||||
"│ │",
|
||||
"│Row Row12 Ro │",
|
||||
"│Row Row22 Ro │",
|
||||
"│Row Row32 Ro │",
|
||||
"│Row Row42 Ro │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of large width just before pushing a column off
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(33),
|
||||
Constraint::Length(10),
|
||||
Constraint::Percentage(33),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of large size (>100% total) hide the last column
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Percentage(60),
|
||||
Constraint::Length(10),
|
||||
Constraint::Percentage(60),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 │",
|
||||
"│Row21 Row22 │",
|
||||
"│Row31 Row32 │",
|
||||
"│Row41 Row42 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_columns_widths_can_use_ratio_constraints() {
|
||||
let test_case = |widths, expected| {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(widths)
|
||||
.column_spacing(0);
|
||||
f.render_widget(table, size);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
// columns of zero width show nothing
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Ratio(0, 1),
|
||||
Constraint::Ratio(0, 1),
|
||||
Constraint::Ratio(0, 1),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of not enough width trims the data
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Ratio(1, 9),
|
||||
Constraint::Ratio(1, 9),
|
||||
Constraint::Ratio(1, 9),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│HeaHeaHea │",
|
||||
"│ │",
|
||||
"│RowRowRow │",
|
||||
"│RowRowRow │",
|
||||
"│RowRowRow │",
|
||||
"│RowRowRow │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// columns of large width just before pushing a column off
|
||||
test_case(
|
||||
&[
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// percentages summing to 100 should give equal widths
|
||||
test_case(
|
||||
&[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)],
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 │",
|
||||
"│Row21 Row22 │",
|
||||
"│Row31 Row32 │",
|
||||
"│Row41 Row42 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_can_have_rows_with_multi_lines() {
|
||||
let test_case = |state: &mut TableState, expected: Buffer| {
|
||||
let backend = TestBackend::new(30, 8);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]).height(2),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]).height(2),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.highlight_symbol(">> ")
|
||||
.widths(&[
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
])
|
||||
.column_spacing(1);
|
||||
f.render_stateful_widget(table, size, state);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
|
||||
let mut state = TableState::default();
|
||||
// no selection
|
||||
test_case(
|
||||
&mut state,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row11 Row12 Row13 │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│ │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// select first
|
||||
state.select(Some(0));
|
||||
test_case(
|
||||
&mut state,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│>> Row11 Row12 Row13 │",
|
||||
"│ Row21 Row22 Row23 │",
|
||||
"│ │",
|
||||
"│ Row31 Row32 Row33 │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// select second (we don't show partially the 4th row)
|
||||
state.select(Some(1));
|
||||
test_case(
|
||||
&mut state,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│ Row11 Row12 Row13 │",
|
||||
"│>> Row21 Row22 Row23 │",
|
||||
"│ │",
|
||||
"│ Row31 Row32 Row33 │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
|
||||
// select 4th (we don't show partially the 1st row)
|
||||
state.select(Some(3));
|
||||
test_case(
|
||||
&mut state,
|
||||
Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│ Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│ Row31 Row32 Row33 │",
|
||||
"│>> Row41 Row42 Row43 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_can_have_elements_styled_individually() {
|
||||
let backend = TestBackend::new(30, 4);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let mut state = TableState::default();
|
||||
state.select(Some(0));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]).style(Style::default().fg(Color::Green)),
|
||||
Row::new(vec![
|
||||
Cell::from("Row21"),
|
||||
Cell::from("Row22").style(Style::default().fg(Color::Yellow)),
|
||||
Cell::from(Spans::from(vec![
|
||||
Span::raw("Row"),
|
||||
Span::styled("23", Style::default().fg(Color::Blue)),
|
||||
]))
|
||||
.style(Style::default().fg(Color::Red)),
|
||||
])
|
||||
.style(Style::default().fg(Color::LightGreen)),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
|
||||
.highlight_symbol(">> ")
|
||||
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.widths(&[
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
])
|
||||
.column_spacing(1);
|
||||
f.render_stateful_widget(table, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut expected = Buffer::with_lines(vec![
|
||||
"│ Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│>> Row11 Row12 Row13 │",
|
||||
"│ Row21 Row22 Row23 │",
|
||||
]);
|
||||
// First row = row color + highlight style
|
||||
for col in 1..=28 {
|
||||
expected.get_mut(col, 2).set_style(
|
||||
Style::default()
|
||||
.fg(Color::Green)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
}
|
||||
// Second row:
|
||||
// 1. row color
|
||||
for col in 1..=28 {
|
||||
expected
|
||||
.get_mut(col, 3)
|
||||
.set_style(Style::default().fg(Color::LightGreen));
|
||||
}
|
||||
// 2. cell color
|
||||
for col in 11..=16 {
|
||||
expected
|
||||
.get_mut(col, 3)
|
||||
.set_style(Style::default().fg(Color::Yellow));
|
||||
}
|
||||
for col in 18..=23 {
|
||||
expected
|
||||
.get_mut(col, 3)
|
||||
.set_style(Style::default().fg(Color::Red));
|
||||
}
|
||||
// 3. text color
|
||||
for col in 21..=22 {
|
||||
expected
|
||||
.get_mut(col, 3)
|
||||
.set_style(Style::default().fg(Color::Blue));
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_should_render_even_if_empty() {
|
||||
let backend = TestBackend::new(30, 4);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]))
|
||||
.block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
|
||||
.widths(&[
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
])
|
||||
.column_spacing(1);
|
||||
f.render_widget(table, size);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let expected = Buffer::with_lines(vec![
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
]);
|
||||
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_columns_dont_panic() {
|
||||
let test_case = |state: &mut TableState, table: Table, width: u16| {
|
||||
let backend = TestBackend::new(width, 8);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
f.render_stateful_widget(table, size, state);
|
||||
})
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
// based on https://github.com/fdehau/tui-rs/issues/470#issuecomment-852562848
|
||||
let table1_width = 98;
|
||||
let table1 = Table::new(vec![Row::new(vec!["r1", "r2", "r3", "r4"])])
|
||||
.header(Row::new(vec!["h1", "h2", "h3", "h4"]))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.highlight_symbol(">> ")
|
||||
.column_spacing(1)
|
||||
.widths(&[
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(25),
|
||||
Constraint::Percentage(45),
|
||||
]);
|
||||
|
||||
let mut state = TableState::default();
|
||||
|
||||
// select first, which would cause a panic before fix
|
||||
state.select(Some(0));
|
||||
test_case(&mut state, table1.clone(), table1_width);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_table_should_clamp_offset_if_rows_are_removed() {
|
||||
let backend = TestBackend::new(30, 8);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
let mut state = TableState::default();
|
||||
|
||||
// render with 6 items => offset will be at 2
|
||||
state.select(Some(5));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![
|
||||
Row::new(vec!["Row01", "Row02", "Row03"]),
|
||||
Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
Row::new(vec!["Row21", "Row22", "Row23"]),
|
||||
Row::new(vec!["Row31", "Row32", "Row33"]),
|
||||
Row::new(vec!["Row41", "Row42", "Row43"]),
|
||||
Row::new(vec!["Row51", "Row52", "Row53"]),
|
||||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(&[
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
])
|
||||
.column_spacing(1);
|
||||
f.render_stateful_widget(table, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row21 Row22 Row23 │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│Row41 Row42 Row43 │",
|
||||
"│Row51 Row52 Row53 │",
|
||||
"└────────────────────────────┘",
|
||||
]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
|
||||
// render with 1 item => offset will be at 1
|
||||
state.select(Some(1));
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(vec![Row::new(vec!["Row31", "Row32", "Row33"])])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(&[
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
])
|
||||
.column_spacing(1);
|
||||
f.render_stateful_widget(table, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![
|
||||
"┌────────────────────────────┐",
|
||||
"│Head1 Head2 Head3 │",
|
||||
"│ │",
|
||||
"│Row31 Row32 Row33 │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"│ │",
|
||||
"└────────────────────────────┘",
|
||||
]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
48
vendor/tui/tests/widgets_tabs.rs
vendored
Normal file
48
vendor/tui/tests/widgets_tabs.rs
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use tui::{
|
||||
backend::TestBackend, buffer::Buffer, layout::Rect, symbols, text::Spans, widgets::Tabs,
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn widgets_tabs_should_not_panic_on_narrow_areas() {
|
||||
let backend = TestBackend::new(1, 1);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let tabs = Tabs::new(["Tab1", "Tab2"].iter().cloned().map(Spans::from).collect());
|
||||
f.render_widget(
|
||||
tabs,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![" "]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widgets_tabs_should_truncate_the_last_item() {
|
||||
let backend = TestBackend::new(10, 1);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let tabs = Tabs::new(["Tab1", "Tab2"].iter().cloned().map(Spans::from).collect());
|
||||
f.render_widget(
|
||||
tabs,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 9,
|
||||
height: 1,
|
||||
},
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
let expected = Buffer::with_lines(vec![format!(" Tab1 {} T ", symbols::line::VERTICAL)]);
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue