use std::io;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
Black,
}
pub trait Output: Send + Sync {
fn write(&mut self, content: &str) -> io::Result<()>;
fn write_line(&mut self, content: &str) -> io::Result<()> {
self.write(content)?;
self.write("\n")
}
fn flush(&mut self) -> io::Result<()>;
}
pub trait ColoredOutput: Output {
fn write_colored(&mut self, content: &str, color: Color) -> io::Result<()>;
fn write_line_colored(&mut self, content: &str, color: Color) -> io::Result<()> {
self.write_colored(content, color)?;
self.write("\n")
}
}
pub struct StdOutput {
use_color: bool,
}
impl StdOutput {
pub fn new() -> Self {
Self { use_color: false }
}
pub fn with_color() -> Self {
Self { use_color: true }
}
}
impl Default for StdOutput {
fn default() -> Self {
Self::new()
}
}
impl Output for StdOutput {
fn write(&mut self, content: &str) -> io::Result<()> {
print!("{content}");
Ok(())
}
fn flush(&mut self) -> io::Result<()> {
use std::io::Write;
io::stdout().flush()
}
}
impl ColoredOutput for StdOutput {
fn write_colored(&mut self, content: &str, color: Color) -> io::Result<()> {
if self.use_color {
use colored::Colorize;
let colored_text = match color {
Color::Red => content.red().to_string(),
Color::Green => content.green().to_string(),
Color::Yellow => content.yellow().to_string(),
Color::Blue => content.blue().to_string(),
Color::Magenta => content.magenta().to_string(),
Color::Cyan => content.cyan().to_string(),
Color::White => content.white().to_string(),
Color::Black => content.black().to_string(),
};
print!("{colored_text}");
} else {
print!("{content}");
}
Ok(())
}
}
pub trait ReporterWithOutput {
fn report_to(&self, results: &[crate::CheckResult], output: &mut dyn Output) -> io::Result<()>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_std_output() {
let mut output = StdOutput::new();
assert!(output.write("test").is_ok());
assert!(output.write_line("test line").is_ok());
assert!(output.flush().is_ok());
}
#[test]
fn test_std_output_colored() {
let mut output = StdOutput::with_color();
assert!(output.write_colored("red text", Color::Red).is_ok());
assert!(
output
.write_line_colored("green line", Color::Green)
.is_ok()
);
}
#[test]
fn test_std_output_no_color() {
let mut output = StdOutput::new();
assert!(output.write_colored("plain text", Color::Blue).is_ok());
}
#[test]
fn test_std_output_default() {
let output = StdOutput::default();
assert!(!output.use_color);
}
#[test]
fn test_std_output_all_colors() {
let mut output = StdOutput::with_color();
assert!(output.write_colored("Red", Color::Red).is_ok());
assert!(output.write_colored("Green", Color::Green).is_ok());
assert!(output.write_colored("Yellow", Color::Yellow).is_ok());
assert!(output.write_colored("Blue", Color::Blue).is_ok());
assert!(output.write_colored("Magenta", Color::Magenta).is_ok());
assert!(output.write_colored("Cyan", Color::Cyan).is_ok());
assert!(output.write_colored("White", Color::White).is_ok());
assert!(output.write_colored("Black", Color::Black).is_ok());
let mut no_color_output = StdOutput::new();
assert!(no_color_output.write_colored("Plain", Color::Red).is_ok());
}
#[test]
fn test_std_output_basic_operations() {
let mut output = StdOutput::new();
assert!(output.write("Test").is_ok());
assert!(output.write_line("Test line").is_ok());
assert!(output.flush().is_ok());
}
}