use assert_cmd::Command; use predicates::prelude::*; use std::{
collections::{HashMap, hash_map::RandomState},
fs,
path::Path,
};
pub struct Tester<'a, S = RandomState> {
cmd: &'a str,
cwd: Option<&'a str>,
stdin: Option<&'a str>,
env_vars: HashMap<&'a str, &'a str, S>,
args: Vec<&'a str>,
stdout: Option<&'a str>,
stderr: Option<&'a str>,
}
impl<'a> Tester<'a> {
pub fn new(cmd: &'a str) -> Tester<'a> {
Tester {
cmd,
cwd: None,
stdin: None,
env_vars: HashMap::new(),
args: Vec::new(),
stdout: None,
stderr: None,
}
}
pub fn cwd(&'a mut self, dir: &'a str) -> &'a mut Tester<'a> {
self.cwd = Some(dir);
self
}
pub fn stdin(&'a mut self, text: &'a str) -> &'a mut Tester<'a> {
self.stdin = Some(text);
self
}
pub fn env(&'a mut self, key: &'a str, value: &'a str) -> &'a mut Tester<'a> {
self.env_vars.insert(key, value);
self
}
pub fn arg(&'a mut self, arg: &'a str) -> &'a mut Tester<'a> {
self.args.push(arg);
self
}
pub fn args(&'a mut self, args: &[&'a str]) -> &'a mut Tester<'a> {
self.args.extend_from_slice(args);
self
}
pub fn stdout(&'a mut self, text: &'a str) -> &'a mut Tester<'a> {
self.stdout = Some(text);
self
}
pub fn stderr(&'a mut self, text: &'a str) -> &'a mut Tester<'a> {
self.stderr = Some(text);
self
}
pub fn run_test(&self) -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(self.cmd)?;
cmd.env_clear();
for (key, value) in &self.env_vars {
cmd.env(key, value);
}
for arg in &self.args {
cmd.arg(arg);
}
if let Some(stdin) = self.stdin {
cmd.write_stdin(stdin);
}
let mut assert = cmd.assert();
assert = if let Some(stdout) = self.stdout {
assert.stdout(predicate::eq(stdout))
} else {
assert.failure()
};
if let Some(stderr) = self.stderr {
assert.stderr(predicate::str::contains(stderr));
}
Ok(())
}
}
pub fn write_to_file(file: &Path, text: &str) {
fs::write(file, text).expect("Unable to write file");
}