comandare 0.3.0

TCP Command Execution
Documentation
use std::io::Write;
use std::sync::{Arc, Mutex};

type LogStream = Arc<Mutex<dyn Write + Send>>;

pub trait Loggable {
    fn out(&mut self, message: String);
    fn err(&mut self, message: String);
}

pub struct Logger {
    debug: bool,
    stdout: LogStream,
    stderr: LogStream,
}

impl Logger {
    pub fn new(debug: bool, stdout: LogStream, stderr: LogStream) -> Self {
        Logger {
            debug,
            stdout,
            stderr,
        }
    }
}

impl Loggable for Logger {
    fn out(&mut self, message: String) {
        if self.debug {
            let mut stdout = self.stdout.lock().unwrap();
            stdout.write_all(message.as_bytes()).unwrap();
            stdout.flush().unwrap();
        }
    }

    fn err(&mut self, message: String) {
        let mut stderr = self.stderr.lock().unwrap();
        stderr.write_all(message.as_bytes()).unwrap();
        stderr.flush().unwrap();
    }
}

impl Clone for Logger {
    fn clone(&self) -> Self {
        Logger {
            debug: self.debug,
            stdout: self.stdout.clone(),
            stderr: self.stderr.clone(),
        }
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    use mockall::mock;
    use mockall::predicate;
    use std::io::Result;

    mock!{
        Stdout {}
        trait Write{
            fn write(&mut self, buf: &[u8]) -> Result<usize>;
            fn write_all(&mut self, mut buf: &[u8]) -> Result<()>;
            fn flush(&mut self) -> Result<()>;
        }
    }

    mock!{
        Stderr {}
        trait Write{
            fn write(&mut self, buf: &[u8]) -> Result<usize>;
            fn write_all(&mut self, mut buf: &[u8]) -> Result<()>;
            fn flush(&mut self) -> Result<()>;
        }
    }

    #[test]
    fn logs_out() {
        let value = "info";
        let argument = format!("{}", value.clone());

        let mut stdout_mock = MockStdout::new();
        stdout_mock.expect_write_all()
            .with(predicate::eq(value.clone().as_bytes()))
            .times(1)
            .returning(|_| Ok(()));
        stdout_mock.expect_flush()
            .times(1)
            .returning(|| Ok(()));

        let mut stderr_mock = MockStderr::new();
        stderr_mock.expect_write_all()
            .never();
        stderr_mock.expect_flush()
            .never();

        let mut logger = Logger::new(
            true,
            Arc::new(Mutex::new(stdout_mock)),
            Arc::new(Mutex::new(stderr_mock))
        );
        logger.out(argument);
    }

    #[test]
    fn logs_err() {
        let value = "error";
        let argument = format!("{}", value.clone());

        let mut stdout_mock = MockStdout::new();
        stdout_mock.expect_write_all()
            .never();
        stdout_mock.expect_flush()
            .never();

        let mut stderr_mock = MockStderr::new();
        stderr_mock.expect_write_all()
            .with(predicate::eq(value.clone().as_bytes()))
            .times(1)
            .returning(|_| Ok(()));
        stderr_mock.expect_flush()
            .times(1)
            .returning(|| Ok(()));

        let mut logger = Logger::new(
            true,
            Arc::new(Mutex::new(stdout_mock)),
            Arc::new(Mutex::new(stderr_mock))
        );
        logger.err(argument.clone());
    }
}