use super::interface::{LogInspector, LogLine};
use crate::{assert_contains_in_order, assert_contains_none};
use std::sync::RwLock;

impl LogInspector for RwLock<Vec<LogLine>> {
    fn assert_logs_contain_in_order(&self, expected: &Vec<LogLine>) {
        assert_contains_in_order!(self.read().unwrap().to_vec(), expected);
    }

    fn assert_logs_contain_none(&self, expected: &Vec<LogLine>) {
        assert_contains_none!(self.read().unwrap().to_vec(), expected);
    }
}

#[cfg(test)]
mod tests {
    mod when_asserting_logs_contain_in_order {
        use crate::logging::interface::{LogInspector, LogLine};
        use log::Level;
        use std::sync::RwLock;

        #[test]
        fn should_succeed_if_log_contains_the_expected_items_in_order() {
            let logs = RwLock::new(vec![LogLine(Level::Error, "Oops!".to_string())]);

            logs.assert_logs_contain_in_order(&vec![LogLine(Level::Error, "Oops!".to_string())]);
        }

        #[test]
        #[should_panic(
            expected = r#"Expected to find each of [LogLine(Error, "Oops!")] in order in [LogLine(Info, "Hello")] - Missing LogLine(Error, "Oops!")"#
        )]
        fn should_fail_if_log_does_not_contain_all_of_the_expected_items_in_order() {
            let logs = RwLock::new(vec![LogLine(Level::Info, "Hello".to_string())]);

            logs.assert_logs_contain_in_order(&vec![LogLine(Level::Error, "Oops!".to_string())]);
        }
    }

    mod when_asserting_logs_contain_none {
        use crate::logging::interface::{LogInspector, LogLine};
        use log::Level;
        use std::sync::RwLock;

        #[test]
        fn should_succeed_if_log_contains_none_of_the_expected_items() {
            let logs = RwLock::new(vec![LogLine(Level::Info, "Hello".to_string())]);

            logs.assert_logs_contain_none(&vec![LogLine(Level::Error, "Oops!".to_string())]);
        }

        #[test]
        #[should_panic(
            expected = r#"Expected to find none of [LogLine(Error, "Oops!")] in order in [LogLine(Error, "Oops!")] - Found LogLine(Error, "Oops!")"#
        )]
        fn should_fail_if_log_contains_any_of_the_expected_items() {
            let logs = RwLock::new(vec![LogLine(Level::Error, "Oops!".to_string())]);

            logs.assert_logs_contain_none(&vec![LogLine(Level::Error, "Oops!".to_string())]);
        }
    }
}
