use crate::reporter::{Color, ColoredOutput, Output};
use std::io;
#[derive(Default)]
pub struct MockOutput {
pub buffer: Vec<String>,
pub color_calls: Vec<(String, Color)>,
simulate_error: bool,
}
impl MockOutput {
pub fn new() -> Self {
Self::default()
}
pub fn simulate_error(&mut self) {
self.simulate_error = true;
}
pub fn get_output(&self) -> String {
self.buffer.join("")
}
pub fn get_lines(&self) -> Vec<&str> {
self.buffer.iter().map(|s| s.as_str()).collect()
}
pub fn clear(&mut self) {
self.buffer.clear();
self.color_calls.clear();
}
pub fn contains(&self, content: &str) -> bool {
self.get_output().contains(content)
}
pub fn contains_colored(&self, content: &str, color: Color) -> bool {
self.color_calls
.iter()
.any(|(text, c)| text.contains(content) && *c == color)
}
pub fn has_color_output(&self) -> bool {
!self.color_calls.is_empty()
}
}
impl Output for MockOutput {
fn write(&mut self, content: &str) -> io::Result<()> {
if self.simulate_error {
self.simulate_error = false;
return Err(io::Error::other("Simulated error"));
}
self.buffer.push(content.to_string());
Ok(())
}
fn flush(&mut self) -> io::Result<()> {
if self.simulate_error {
self.simulate_error = false;
return Err(io::Error::other("Simulated flush error"));
}
Ok(())
}
}
impl ColoredOutput for MockOutput {
fn write_colored(&mut self, content: &str, color: Color) -> io::Result<()> {
if self.simulate_error {
self.simulate_error = false;
return Err(io::Error::other("Simulated error"));
}
self.color_calls.push((content.to_string(), color));
self.buffer.push(content.to_string());
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mock_output_capture() {
let mut output = MockOutput::new();
output.write_line("test").unwrap();
assert_eq!(output.buffer, vec!["test", "\n"]);
}
#[test]
fn test_mock_output_write() {
let mut output = MockOutput::new();
output.write("hello").unwrap();
output.write(" ").unwrap();
output.write("world").unwrap();
assert_eq!(output.get_output(), "hello world");
}
#[test]
fn test_mock_output_write_line() {
let mut output = MockOutput::new();
output.write_line("line 1").unwrap();
output.write_line("line 2").unwrap();
assert_eq!(output.get_output(), "line 1\nline 2\n");
assert_eq!(output.get_lines(), vec!["line 1", "\n", "line 2", "\n"]);
}
#[test]
fn test_mock_output_colored() {
let mut output = MockOutput::new();
output.write_colored("error", Color::Red).unwrap();
output.write_colored("success", Color::Green).unwrap();
assert_eq!(output.get_output(), "errorsuccess");
assert_eq!(output.color_calls.len(), 2);
assert_eq!(output.color_calls[0], ("error".to_string(), Color::Red));
assert_eq!(output.color_calls[1], ("success".to_string(), Color::Green));
}
#[test]
fn test_mock_output_colored_line() {
let mut output = MockOutput::new();
output.write_line_colored("warning", Color::Yellow).unwrap();
assert_eq!(output.get_output(), "warning\n");
assert!(output.contains_colored("warning", Color::Yellow));
}
#[test]
fn test_mock_output_error_simulation() {
let mut output = MockOutput::new();
output.simulate_error();
let result = output.write("test");
assert!(result.is_err());
assert_eq!(result.unwrap_err().kind(), io::ErrorKind::Other);
let result2 = output.write("test");
assert!(result2.is_ok());
}
#[test]
fn test_mock_output_flush() {
let mut output = MockOutput::new();
assert!(output.flush().is_ok());
output.simulate_error();
let result = output.flush();
assert!(result.is_err());
}
#[test]
fn test_mock_output_clear() {
let mut output = MockOutput::new();
output.write_line("test").unwrap();
output.write_colored("colored", Color::Blue).unwrap();
assert!(!output.buffer.is_empty());
assert!(!output.color_calls.is_empty());
output.clear();
assert!(output.buffer.is_empty());
assert!(output.color_calls.is_empty());
}
#[test]
fn test_mock_output_contains() {
let mut output = MockOutput::new();
output.write_line("hello world").unwrap();
output.write_line("goodbye").unwrap();
assert!(output.contains("hello"));
assert!(output.contains("world"));
assert!(output.contains("goodbye"));
assert!(!output.contains("missing"));
}
}