More unit testing of tui

This commit is contained in:
Wojciech Kozlowski 2023-04-13 09:59:45 +02:00
parent 230f3cb893
commit c9c40b3c76
6 changed files with 113 additions and 11 deletions

View File

@ -25,10 +25,13 @@ grcov codecov/debug/profraw \
--ignore-not-existing \ --ignore-not-existing \
--ignore "tests/*" \ --ignore "tests/*" \
--ignore "src/main.rs" \ --ignore "src/main.rs" \
--excl-start "mod tests \{" \ --excl-start "mod tests \{|GRCOV_EXCL_START" \
--excl-stop "GRCOV_EXCL_STOP" \
--output-path ./codecov/debug/coverage/ --output-path ./codecov/debug/coverage/
xdg-open codecov/debug/coverage/index.html xdg-open codecov/debug/coverage/index.html
``` ```
Note that some changes may not be visible until `codecov/debug/coverage` is removed and the `grcov` Note that some changes may not be visible until `codecov/debug/coverage` is removed and the `grcov`
command is rerun. command is rerun.
For most cases `cargo clean` can be replaced with `rm -rf ./codecov/debug/{coverage,profraw}`.

View File

@ -25,7 +25,7 @@ macro_rules! collection {
"artist a.a.2.1".to_string(), "artist a.a.2.1".to_string(),
"artist a.a.2.2".to_string(), "artist a.a.2.2".to_string(),
], ],
format: TrackFormat::Flac, format: TrackFormat::Mp3,
}, },
Track { Track {
number: 3, number: 3,
@ -45,7 +45,7 @@ macro_rules! collection {
number: 1, number: 1,
title: "track a.b.1".to_string(), title: "track a.b.1".to_string(),
artist: vec!["artist a.b.1".to_string()], artist: vec!["artist a.b.1".to_string()],
format: TrackFormat::Mp3, format: TrackFormat::Flac,
}, },
Track { Track {
number: 2, number: 2,
@ -148,7 +148,7 @@ macro_rules! collection {
number: 1, number: 1,
title: "track c.b.1".to_string(), title: "track c.b.1".to_string(),
artist: vec!["artist c.b.1".to_string()], artist: vec!["artist c.b.1".to_string()],
format: TrackFormat::Mp3, format: TrackFormat::Flac,
}, },
Track { Track {
number: 2, number: 2,
@ -157,7 +157,7 @@ macro_rules! collection {
"artist c.b.2.1".to_string(), "artist c.b.2.1".to_string(),
"artist c.b.2.2".to_string(), "artist c.b.2.2".to_string(),
], ],
format: TrackFormat::Mp3, format: TrackFormat::Flac,
}, },
], ],
}, },

View File

@ -45,7 +45,6 @@ pub struct EventChannel {
receiver: mpsc::Receiver<Event>, receiver: mpsc::Receiver<Event>,
} }
#[derive(Clone)]
pub struct EventSender { pub struct EventSender {
sender: mpsc::Sender<Event>, sender: mpsc::Sender<Event>,
} }
@ -89,6 +88,7 @@ pub struct EventListener {
events: EventSender, events: EventSender,
} }
// GRCOV_EXCL_START
impl EventListener { impl EventListener {
pub fn new(events: EventSender) -> EventListener { pub fn new(events: EventSender) -> EventListener {
EventListener { events } EventListener { events }
@ -117,3 +117,42 @@ impl EventListener {
}) })
} }
} }
// GRCOV_EXCL_STOP
#[cfg(test)]
mod tests {
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use super::{Event, EventChannel};
#[test]
fn event_sender() {
let channel = EventChannel::new();
let sender = channel.sender();
let receiver = channel.receiver();
let event = Event::Key(KeyEvent::new(KeyCode::Up, KeyModifiers::empty()));
let result = sender.send(event);
assert!(result.is_ok());
drop(receiver);
let result = sender.send(event);
assert!(result.is_err());
}
#[test]
fn event_receiver() {
let channel = EventChannel::new();
let sender = channel.sender();
let receiver = channel.receiver();
let event = Event::Key(KeyEvent::new(KeyCode::Up, KeyModifiers::empty()));
sender.send(event).unwrap();
let result = receiver.recv();
assert!(result.is_ok());
drop(sender);
let result = receiver.recv();
assert!(result.is_err());
}
}

View File

@ -6,6 +6,7 @@ pub struct EventHandler {
events: EventReceiver, events: EventReceiver,
} }
// GRCOV_EXCL_START
impl EventHandler { impl EventHandler {
pub fn new(events: EventReceiver) -> Self { pub fn new(events: EventReceiver) -> Self {
EventHandler { events } EventHandler { events }
@ -51,3 +52,4 @@ impl EventHandler {
} }
} }
} }
// GRCOV_EXCL_STOP

View File

@ -77,7 +77,7 @@ impl<B: Backend> Tui<B> {
fn run_loop(&mut self) -> Result<(), Error> { fn run_loop(&mut self) -> Result<(), Error> {
while self.app.is_running() { while self.app.is_running() {
self.terminal self.terminal
.draw(|frame| self.ui.render(&mut self.app, frame))?; .draw(|frame| self.ui.render(&self.app, frame))?;
self.handler.handle_next_event(&mut self.app)?; self.handler.handle_next_event(&mut self.app)?;
} }

View File

@ -313,10 +313,6 @@ impl Ui {
} }
pub fn render<B: Backend>(&mut self, app: &App, frame: &mut Frame<'_, B>) { pub fn render<B: Backend>(&mut self, app: &App, frame: &mut Frame<'_, B>) {
// This is where you add new widgets.
// See the following resources:
// - https://docs.rs/ratatui/latest/ratatui/widgets/index.html
// - https://github.com/tui-rs-revival/ratatui/tree/master/examples
let areas = Self::construct_areas(frame.size()); let areas = Self::construct_areas(frame.size());
let app_state = Self::construct_app_state(app); let app_state = Self::construct_app_state(app);
@ -325,3 +321,65 @@ impl Ui {
Self::render_track_column(app_state.tracks, areas.tracks, frame); Self::render_track_column(app_state.tracks, areas.tracks, frame);
} }
} }
#[cfg(test)]
mod tests {
// This is UI so the only sensible unit test is to run the code through various app states.
use ratatui::{backend::TestBackend, Terminal};
use crate::{tests::{MockCollectionManager, COLLECTION}, tui::app::App};
use super::Ui;
#[test]
fn empty() {
let backend = TestBackend::new(150, 30);
let mut terminal = Terminal::new(backend).unwrap();
let mut collection_manager = MockCollectionManager::new();
let collection = vec![];
collection_manager
.expect_rescan_library()
.returning(|| Ok(()));
collection_manager
.expect_get_collection()
.return_const(collection);
let app = App::new(Box::new(collection_manager)).unwrap();
let mut ui = Ui::new();
terminal.draw(|frame| ui.render(&app, frame)).unwrap();
}
#[test]
fn collection() {
let backend = TestBackend::new(150, 30);
let mut terminal = Terminal::new(backend).unwrap();
let mut collection_manager = MockCollectionManager::new();
let collection = COLLECTION.to_owned();
collection_manager
.expect_rescan_library()
.returning(|| Ok(()));
collection_manager
.expect_get_collection()
.return_const(collection);
let mut app = App::new(Box::new(collection_manager)).unwrap();
let mut ui = Ui::new();
terminal.draw(|frame| ui.render(&app, frame)).unwrap();
// Change the track (which has a different track format).
app.increment_category();
app.increment_category();
app.increment_selection();
terminal.draw(|frame| ui.render(&app, frame)).unwrap();
}
}