mod macros;
mod printer;
pub use printer::Printer;
use std::fmt::Arguments;
pub fn standard() -> Printer {
Printer::standard()
}
pub fn null() -> Printer {
Printer::null()
}
pub fn test() -> Printer {
Printer::test()
}
pub trait Print: Clone {
fn print_fmt(&self, args: Arguments<'_>);
fn println_fmt(&self, args: Arguments<'_>);
fn print(&self, s: &str) {
self.print_fmt(format_args!("{}", s));
}
fn println(&self, s: &str) {
self.println_fmt(format_args!("{}", s));
}
fn eprint(&self, s: &str) {
self.eprint_fmt(format_args!("{}", s));
}
fn eprintln(&self, s: &str) {
self.eprintln_fmt(format_args!("{}", s));
}
fn eprint_fmt(&self, args: Arguments<'_>);
fn eprintln_fmt(&self, args: Arguments<'_>);
}
#[derive(Clone, Debug, Default, Copy)]
pub struct StandardPrint;
#[cfg_attr(test, mutants::skip)]
impl Print for StandardPrint {
fn print_fmt(&self, args: Arguments<'_>) {
std::print!("{}", args);
}
fn println_fmt(&self, args: Arguments<'_>) {
std::println!("{}", args);
}
fn eprint_fmt(&self, args: Arguments<'_>) {
std::eprint!("{}", args);
}
fn eprintln_fmt(&self, args: Arguments<'_>) {
std::eprintln!("{}", args);
}
}
#[derive(Clone, Debug, Default, Copy)]
pub struct NullPrint;
impl Print for NullPrint {
fn print_fmt(&self, _args: Arguments<'_>) {}
fn println_fmt(&self, _args: Arguments<'_>) {}
fn eprint_fmt(&self, _args: Arguments<'_>) {}
fn eprintln_fmt(&self, _args: Arguments<'_>) {}
}
#[derive(Clone, Debug, Default)]
pub struct TestPrint {
stdout: std::sync::Arc<std::sync::Mutex<String>>,
stderr: std::sync::Arc<std::sync::Mutex<String>>,
}
impl TestPrint {
pub fn new() -> Self {
Self {
stdout: std::sync::Arc::new(std::sync::Mutex::new(String::new())),
stderr: std::sync::Arc::new(std::sync::Mutex::new(String::new())),
}
}
pub fn output(&self) -> String {
self.stdout.lock().unwrap().clone()
}
pub fn stderr(&self) -> String {
self.stderr.lock().unwrap().clone()
}
pub fn clear(&self) {
self.stdout.lock().unwrap().clear();
self.stderr.lock().unwrap().clear();
}
}
impl Print for TestPrint {
fn print_fmt(&self, args: Arguments<'_>) {
(&self).print_fmt(args)
}
fn println_fmt(&self, args: Arguments<'_>) {
(&self).println_fmt(args)
}
fn eprint_fmt(&self, args: Arguments<'_>) {
(&self).eprint_fmt(args)
}
fn eprintln_fmt(&self, args: Arguments<'_>) {
(&self).eprintln_fmt(args)
}
}
impl Print for &TestPrint {
fn print_fmt(&self, args: Arguments<'_>) {
let mut output = self.stdout.lock().unwrap();
output.push_str(&format!("{}", args));
}
fn println_fmt(&self, args: Arguments<'_>) {
let mut output = self.stdout.lock().unwrap();
output.push_str(&format!("{}\n", args));
}
fn eprint_fmt(&self, args: Arguments<'_>) {
let mut output = self.stderr.lock().unwrap();
output.push_str(&format!("{}", args));
}
fn eprintln_fmt(&self, args: Arguments<'_>) {
let mut output = self.stderr.lock().unwrap();
output.push_str(&format!("{}\n", args));
}
}
#[cfg(test)]
mod tests {
use crate::{kxprint, kxprintln};
use super::*;
#[test]
fn test_standard_print() {
let printer = Printer::standard();
printer.println("This is a test");
kxprintln!(printer, "This is a {} test", "macro");
}
#[test]
fn test_null_print() {
let printer = Printer::null();
printer.println("This should not appear anywhere");
kxprintln!(printer, "This should also, {}", "not appear anywhere");
}
#[test]
fn test_test_print() {
let printer = Printer::test();
let test_print = printer.as_test().unwrap();
printer.print("Hello");
kxprint!(printer, " ");
printer.println("World");
assert_eq!(test_print.output(), "Hello World\n");
printer.eprint("Error: ");
printer.eprintln("something went wrong");
assert_eq!(test_print.stderr(), "Error: something went wrong\n");
test_print.clear();
assert_eq!(test_print.output(), "");
assert_eq!(test_print.stderr(), "");
printer.println("info: running task");
printer.eprintln("error: task failed");
assert_eq!(test_print.output(), "info: running task\n");
assert_eq!(test_print.stderr(), "error: task failed\n");
test_print.clear();
printer.println("New message");
kxprintln!(printer, "second line");
assert_eq!(test_print.output(), "New message\nsecond line\n");
}
#[test]
fn test_print_in_function() {
fn print_message(printer: &Printer) {
printer.println("Test message");
kxprintln!(printer, "{} test message", "Second");
}
let printer = Printer::test();
let test_print = printer.as_test().unwrap();
print_message(&printer);
assert_eq!(test_print.output(), "Test message\nSecond test message\n");
}
}