Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement base integration tests #16

Merged
merged 5 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ edition = "2021"

[dependencies]
anyhow = "1.0.75"
assert_cmd = "2.0.12"
clap = { version = "4.4.3", features = ["derive"] }
crossterm = "0.27.0"
dirs = "5.0.1"
Expand All @@ -18,3 +17,6 @@ serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107"
tempfile = "3.8.0"
tui = "0.19.0"

[dev-dependencies]
assert_cmd = "2.0.12"
122 changes: 122 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,125 @@ fn restore_terminal(

Ok(())
}

#[cfg(test)]
mod tests {
use std::{io::Write, time::Instant};

use anyhow::{Context, Result};
use predicates::Predicate;
use tui::{backend::TestBackend, buffer::Buffer, Frame, Terminal};

use crate::{
args::Args,
config::Config,
expected_input::ExpectedInput,
runner::{FrameWrapper, Runner},
};

fn configure_terminal() -> Result<Terminal<TestBackend>, anyhow::Error> {
let backend = TestBackend::new(400, 400);
let terminal = Terminal::new(backend).context("Unable to create terminal")?;

Ok(terminal)
}

fn extract_text_from_buffer(buffer: &Buffer) -> String {
let mut text = String::new();

for y in 0..buffer.area.height {
for x in 0..buffer.area.height {
let cell = buffer.get(x, y);
text.push_str(&cell.symbol);
}
text.push('\n');
}

text
}

fn setup_terminal(args: Args) -> Result<(Config, ExpectedInput, Terminal<TestBackend>)> {
let config_file_path = dirs::home_dir()
.context("Unable to get home directory")?
.join(".config")
.join("donkeytype")
.join("donkeytype-config.json");

let config = Config::new(args, config_file_path).context("Unable to create config")?;
let expected_input =
ExpectedInput::new(&config).context("Unable to create expected input")?;
let terminal = configure_terminal().context("Unable to configure terminal")?;

Ok((config, expected_input, terminal))
}

#[test]
fn should_print_default_expected_input() -> Result<()> {
let mut temp_dict_file =
tempfile::NamedTempFile::new().expect("Unable to create temp file");
temp_dict_file
.write_all(r#"hello world"#.as_bytes())
.expect("Unable to write to temp file");

let args = Args {
dictionary_path: Some(temp_dict_file.path().display().to_string()),
duration: None,
numbers: None,
uppercase: None,
uppercase_ratio: None,
numbers_ratio: None,
};

let (config, expected_input, mut terminal) = setup_terminal(args)?;

let mut app = Runner::new(config, expected_input);
let start_time = Instant::now();

terminal
.draw(|f: &mut Frame<TestBackend>| {
let mut frame_wrapper = FrameWrapper::new(f);
app.render(&mut frame_wrapper, start_time.elapsed().as_secs());
})
.context("Unable to draw in terminal")?;

let text = extract_text_from_buffer(terminal.backend().buffer());

let predicate = predicates::str::contains("hello world");

assert_eq!(true, predicate.eval(&text));

Ok(())
}

#[test]
fn should_print_help_message_for_normal_mode() -> Result<()> {
let args = Args {
dictionary_path: None,
duration: None,
uppercase: None,
uppercase_ratio: None,
numbers: None,
numbers_ratio: None,
};

let (config, expected_input, mut terminal) = setup_terminal(args)?;

let mut app = Runner::new(config, expected_input);
let start_time = Instant::now();

terminal
.draw(|f: &mut Frame<TestBackend>| {
let mut frame_wrapper = FrameWrapper::new(f);
app.render(&mut frame_wrapper, start_time.elapsed().as_secs());
})
.context("Unable to draw in terminal")?;

let text = extract_text_from_buffer(terminal.backend().buffer());

let predicate = predicates::str::contains("press 'e' to start the test, press 'q' to quit");

assert_eq!(true, predicate.eval(&text));

Ok(())
}
}
4 changes: 2 additions & 2 deletions src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ impl Runner {
/// There are two areas being rendered,
/// input area - where user input and expected input is displayed,
/// and info arae - where help message and time remaining is rendered.
fn render(&mut self, frame: &mut impl FrameWrapperInterface, time_elapsed: u64) {
pub fn render(&mut self, frame: &mut impl FrameWrapperInterface, time_elapsed: u64) {
let areas = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(1), Constraint::Length(1)].as_ref())
Expand Down Expand Up @@ -424,7 +424,7 @@ impl Runner {

/// Used for generating mocks using `mockall` crate
#[automock]
trait FrameWrapperInterface {
pub trait FrameWrapperInterface {
fn render_widget<W: Widget + 'static>(&mut self, widget: W, area: Rect);
fn set_cursor(&mut self, x: u16, y: u16);
fn size(&self) -> Rect;
Expand Down