cargo hollywood
Diffstat (limited to 'src/test/ui/test_list.rs')
| -rw-r--r-- | src/test/ui/test_list.rs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/test/ui/test_list.rs b/src/test/ui/test_list.rs new file mode 100644 index 0000000..c4d9da2 --- /dev/null +++ b/src/test/ui/test_list.rs @@ -0,0 +1,130 @@ +use crate::cargo::TestResult; +use crate::test::TestState; + +use super::ls::SList; +use super::Test; +use ratatui::{ + layout::{Constraint::Percentage, Direction::Horizontal}, + prelude::*, + style::Stylize, + widgets::{Block, Borders, List, ListItem}, + Frame, +}; +use std::time::Duration; +#[derive(Default)] +pub struct TestList { + a: SList, + b: SList, + c: SList, +} + +trait RExt<'a> { + fn pl(&mut self, list: impl Into<Line<'a>>); +} + +impl<'a> RExt<'a> for Vec<ListItem<'a>> { + fn pl(&mut self, list: impl Into<Line<'a>>) { + self.push(ListItem::new(list.into())); + } +} + +impl TestList { + fn has(&mut self, n: usize) { + self.all().map(|a| a.has(n)); + } + + fn all(&mut self) -> [&mut SList; 3] { + [&mut self.a, &mut self.b, &mut self.c] + } + + pub fn next(&mut self) { + self.all().map(SList::next); + } + + pub fn prev(&mut self) { + self.all().map(SList::prev); + } + + pub fn selects<'a>(&'a self, state: &'a TestState) -> Option<&Test> { + state.tests.get(self.a.state.selected()?) + } + + pub fn stdout<'a>(&'a self, state: &'a TestState) -> Option<&str> { + self.selects(state)?.stdout() + } +} + +pub fn test_list<B: Backend>(f: &mut Frame<B>, state: &mut TestState, chunk: Rect) { + let mut tests = Vec::<ListItem>::new(); + let mut test_side1 = Vec::<ListItem>::new(); + let mut test_side2 = Vec::<ListItem>::new(); + fn time<'v>(secs: f32) -> Line<'v> { + let dur = Duration::from_secs_f32(secs); + let time = humantime::format_duration(dur).to_string(); + match (secs / 16.).round() as usize { + 0 => Line::styled(time, Style::default().green()), + 1 => Line::styled(time, Style::default().yellow()), + _ => Line::styled(time, Style::default().red()), + } + } + for test in &state.tests { + match test { + Test::InProgress { name } => { + tests.pl(name.bold().yellow()); + test_side1.pl("in progress".yellow().italic()); + test_side2.pl(""); + } + Test::Succeeded(TestResult { + name, + exec_time, + stdout: _, + }) => { + tests.pl(name.bold().green()); + test_side1.pl("passed".green().italic()); + test_side2.pl(time(*exec_time)); + } + Test::Failed(TestResult { + name, + exec_time, + stdout: _, + }) => { + tests.pl(name.bold().red()); + test_side1.pl("failed".red().bold().italic()); + test_side2.pl(time(*exec_time)); + } + Test::Ignored { name } => { + tests.pl(name.bold().yellow()); + test_side1.pl("ignored".yellow().italic()); + test_side2.pl(""); + } + } + } + let sides = Layout::default() + .direction(Horizontal) + .constraints([Percentage(80), Percentage(10), Percentage(10)]) + .split(chunk); + let hl = Style::default().on_light_green().italic(); + state.test_list.has(tests.len()); + f.render_stateful_widget( + List::new(tests) + .highlight_style(hl) + .highlight_symbol("> ") + .block(Block::default().borders(Borders::LEFT | Borders::TOP | Borders::BOTTOM)), + sides[0], + &mut state.test_list.a.state, + ); + f.render_stateful_widget( + List::new(test_side1) + .highlight_style(hl) + .block(Block::default().borders(Borders::TOP | Borders::BOTTOM)), + sides[1], + &mut state.test_list.b.state, + ); + f.render_stateful_widget( + List::new(test_side2) + .highlight_style(hl) + .block(Block::default().borders(Borders::TOP | Borders::BOTTOM | Borders::RIGHT)), + sides[2], + &mut state.test_list.c.state, + ); +} |