use crate::helpers::{append_stdout, VioFakeMessage};
use crate::vio::VirtualIo;
use std::env::VarError;
pub struct VioFake {
pub(crate) environment_variables: Vec<(String, String)>,
pub(crate) expected_messages: Vec<VioFakeMessage>,
actual_messages: Vec<VioFakeMessage>,
messages_index: usize,
}
impl VioFake {
pub(crate) fn new(
expected_messages: Vec<VioFakeMessage>,
environment_variables: Vec<(String, String)>,
) -> Self {
Self {
expected_messages,
environment_variables,
actual_messages: Vec::new(),
messages_index: 0,
}
}
#[must_use]
pub const fn get_expected(&self) -> &Vec<VioFakeMessage> {
&self.expected_messages
}
#[must_use]
pub const fn get_actual(&self) -> &Vec<VioFakeMessage> {
&self.actual_messages
}
}
impl VirtualIo for VioFake {
fn print<S: Into<String>>(&mut self, message: S) -> &mut Self {
let new_message_added = append_stdout(&mut self.actual_messages, message.into());
if new_message_added {
self.messages_index += 1;
}
self
}
fn println<S: Into<String>>(&mut self, message: S) -> &mut Self {
let new_message_added = append_stdout(&mut self.actual_messages, message.into());
append_stdout(&mut self.actual_messages, "\n".to_string());
if new_message_added {
self.messages_index += 1;
}
self
}
fn read_line(&mut self) -> String {
match self.expected_messages.get(self.messages_index) {
Some(VioFakeMessage::StdIn(ref message)) => {
self.messages_index += 1;
self.actual_messages
.push(VioFakeMessage::StdIn(message.clone()));
message.clone()
}
_ => panic!(
"Expected STDIN message, instead got {:?}",
self.expected_messages[self.messages_index]
),
}
}
fn get_environment_var<S: Into<String>>(&self, variable: S) -> Result<String, VarError> {
let name = variable.into();
for var in &self.environment_variables {
if var.0 == name {
return Ok(var.1.clone());
}
}
Err(VarError::NotPresent)
}
fn get_environment_vars(&self) -> Vec<(String, String)> {
self.environment_variables.clone()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::vio::VirtualIo;
use crate::VioFakeBuilder;
#[test]
fn vio_fake_handles_correct_print_messages() {
let mut vio = VioFakeBuilder::new()
.expect_stdout("My name is ")
.expect_stdout("John Smith\n")
.expect_stdout("Your name is Jane Doe\n")
.expect_stdout("Together, ")
.expect_stdout("we are two people\n")
.build();
vio.println("My name is John Smith");
vio.println("Your name is Jane Doe");
vio.println("Together, we are two people");
assert_eq!(vio.get_expected(), vio.get_actual());
}
#[test]
fn vio_fake_handles_incorrect_print_messages() {
let mut vio = VioFakeBuilder::new().expect_stdout("Hello, world!").build();
vio.println("Hello, Jane Doe!");
assert_ne!(vio.get_expected(), vio.get_actual());
}
#[test]
fn vio_fake_handles_correct_read_line_messages() {
let mut vio = VioFakeBuilder::new()
.provide_stdin("My name is Jane Doe")
.build();
let output = vio.read_line();
assert_eq!(output, "My name is Jane Doe");
assert_eq!(vio.get_expected(), vio.get_actual());
}
#[test]
fn vio_fake_handles_correct_ordering_of_io() {
let mut vio = VioFakeBuilder::new()
.expect_stdout("My name is ")
.expect_stdout("John Smith\n")
.provide_stdin("My name is Jane Doe")
.expect_stdout("Your name is Jane Doe\n")
.expect_stdout("Together, ")
.expect_stdout("we are two people\n")
.build();
vio.println("My name is John Smith");
let output = vio.read_line();
assert_eq!(output, "My name is Jane Doe");
vio.println("Your name is Jane Doe");
vio.println("Together, we are two people");
assert_eq!(vio.get_expected(), vio.get_actual());
}
#[test]
#[should_panic]
fn vio_fake_panics_on_incorrect_ordering_of_io() {
let mut vio = VioFakeBuilder::new()
.provide_stdin("My name is Jane Doe")
.build();
vio.println("My name is John Smith");
vio.read_line();
}
#[test]
#[should_panic]
fn vio_fake_panics_if_not_enough_inputs() {
let mut vio = VioFakeBuilder::new()
.provide_stdin("My name is Jane Doe")
.build();
vio.println("My name is John Smith");
vio.read_line();
vio.read_line();
}
#[test]
fn vio_get_environment_variable() {
let vio = VioFakeBuilder::new()
.set_environment_var("HELLO", "WORLD")
.build();
assert_eq!(vio.get_environment_var("HELLO"), Ok("WORLD".to_string()));
assert_eq!(
vio.get_environment_var("DOES_NOT_EXIST"),
Err(VarError::NotPresent)
);
}
#[test]
fn vio_get_environment_variables() {
let vio = VioFakeBuilder::new()
.set_environment_var("HELLO", "WORLD")
.set_environment_var("MY_MOOD", "GOOD")
.build();
assert_eq!(
vio.get_environment_vars(),
vec![
("HELLO".to_string(), "WORLD".to_string()),
("MY_MOOD".to_string(), "GOOD".to_string())
]
);
}
}