virtual-io 0.1.0

Mock stdin/out/err for testing
Documentation
use std::{env::VarError, io::Write};

/// Virtual IO is a rust library for easily implementing stdin and stdout in a
/// testable way. It replaces all `println!` and `print!` macro calls.
///
/// ```rs
/// use virtual_io::{VirtualIo, Vio};
///
/// fn get_name() -> String {
///     get_name_base(&mut virtual_io::new())
/// }
///
/// fn get_name_base(vio: &mut impl VirtualIo) -> String {
///     vio.print("What is your name? ");
///     let name = vio.read_line();
///     vio.println(format!("Hello, {}!", name));
///     name
/// }
/// ```
pub trait VirtualIo {
    /// Prints a message to the console. Is close to the `print!` macro with
    /// one difference: output is not buffered and is instead immediately
    /// flushed.
    fn print<S: Into<String>>(&mut self, message: S) -> &mut Self;

    /// Prints a message to the console with a new line at the end. Is
    /// equivalent to the `println!` macro.
    fn println<S: Into<String>>(&mut self, message: S) -> &mut Self;

    /// Get user input from the console. The input ends when the user types
    /// a new line.
    fn read_line(&mut self) -> String;

    /// Get an environment variable. Is equivalent to `std::env::var`.
    ///
    /// # Errors
    /// Returns an error if the environment variable is not present.
    fn get_environment_var<S: Into<String>>(&self, variable: S) -> Result<String, VarError>;

    /// Get an environment variables as a vector. Each item in the vector
    /// is a (key, value) tuple.
    fn get_environment_vars(&self) -> Vec<(String, String)>;
}

#[derive(PartialEq, Eq, Debug, Default)]
pub struct Vio {}

impl VirtualIo for Vio {
    fn print<S: Into<String>>(&mut self, message: S) -> &mut Self {
        print!("{}", message.into());
        if std::io::stdout().flush().is_ok() {};
        self
    }

    fn println<S: Into<String>>(&mut self, message: S) -> &mut Self {
        println!("{}", message.into());
        self
    }

    fn read_line(&mut self) -> String {
        let mut input = String::new();
        match std::io::stdin().read_line(&mut input) {
            Ok(_) => input.trim().to_string(),
            Err(_) => String::new(),
        }
    }

    fn get_environment_var<S: Into<String>>(&self, variable: S) -> Result<String, VarError> {
        std::env::var(variable.into())
    }

    fn get_environment_vars(&self) -> Vec<(String, String)> {
        std::env::vars().collect()
    }
}

impl Vio {
    #[must_use]
    pub const fn new() -> Self {
        Self {}
    }
}