use ::std::collections::HashMap; use ::std::io; use ::std::sync::{Arc, Mutex}; use ::tui::backend::Backend; use ::tui::buffer::Cell; use ::tui::layout::Rect; #[derive(Hash, Debug, PartialEq)] pub enum TerminalEvent { Clear, HideCursor, ShowCursor, GetCursor, Flush, Draw, } pub struct TestBackend { pub events: Arc>>, pub draw_events: Arc>>, terminal_width: Arc>, terminal_height: Arc>, } impl TestBackend { pub fn new( log: Arc>>, draw_log: Arc>>, terminal_width: Arc>, terminal_height: Arc>, ) -> TestBackend { TestBackend { events: log, draw_events: draw_log, terminal_width, terminal_height, } } } #[derive(Hash, Eq, PartialEq)] struct Point { x: u16, y: u16, } impl Backend for TestBackend { fn clear(&mut self) -> io::Result<()> { self.events.lock().unwrap().push(TerminalEvent::Clear); Ok(()) } fn hide_cursor(&mut self) -> io::Result<()> { self.events.lock().unwrap().push(TerminalEvent::HideCursor); Ok(()) } fn show_cursor(&mut self) -> io::Result<()> { self.events.lock().unwrap().push(TerminalEvent::ShowCursor); Ok(()) } fn get_cursor(&mut self) -> io::Result<(u16, u16)> { self.events.lock().unwrap().push(TerminalEvent::GetCursor); Ok((0, 0)) } fn set_cursor(&mut self, _x: u16, _y: u16) -> io::Result<()> { Ok(()) } fn draw<'a, I>(&mut self, content: I) -> io::Result<()> where I: Iterator, { // use std::fmt::Write; self.events.lock().unwrap().push(TerminalEvent::Draw); let mut string = String::with_capacity(content.size_hint().0 * 3); let mut coordinates = HashMap::new(); for (x, y, cell) in content { coordinates.insert(Point { x, y }, cell); } let terminal_height = self.terminal_height.lock().unwrap(); let terminal_width = self.terminal_width.lock().unwrap(); for y in 0..*terminal_height { for x in 0..*terminal_width { match coordinates.get(&Point { x, y }) { Some(cell) => { // this will contain no style information at all // should be good enough for testing string.push_str(&cell.symbol); } None => { string.push_str(" "); } } } string.push_str("\n"); } self.draw_events.lock().unwrap().push(string); Ok(()) } fn size(&self) -> io::Result { let terminal_height = self.terminal_height.lock().unwrap(); let terminal_width = self.terminal_width.lock().unwrap(); Ok(Rect::new(0, 0, *terminal_width, *terminal_height)) } fn flush(&mut self) -> io::Result<()> { self.events.lock().unwrap().push(TerminalEvent::Flush); Ok(()) } }