use std::any::Any;
use std::borrow::Cow;
use std::io::Cursor;
use std::sync::{Arc, Mutex};
use timber_rust::service::write::{AtemporalMessageFormatter, StandardMessageFormatter};
use timber_rust::service::{ServiceError, StringFmtWrite, WriteMessageFormatter};
use timber_rust::{
DirectLogger, Fallback, LogLevel, Logger, LoggerStatus, Message, MessageFactory, QueuedLogger,
Service,
};
struct ArcedFmtWrite {
buffer: Arc<Mutex<String>>,
}
impl Service for ArcedFmtWrite {
fn status(&self) -> LoggerStatus {
LoggerStatus::Running
}
fn work(&self, msg: &Message) -> Result<(), ServiceError> {
let mut formatter = AtemporalMessageFormatter::default();
let mut guard = self.buffer.lock().map_err(|_| ServiceError::LockPoisoned)?;
formatter.format_fmt(msg, &mut *guard)?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Fallback for ArcedFmtWrite {}
#[test]
pub fn test_default_message_formatter() {
let mut formatter = StandardMessageFormatter::new();
let message = MessageFactory::string_msg(LogLevel::Debug, "Test message");
let iso_8601_regex = regex::Regex::new(
r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})\s+\[\s+DEBUG\s+]\s+Test message"
).unwrap();
let mut buffer = Vec::new();
let mut sink = Cursor::new(&mut buffer);
formatter
.format_io(&message, &mut sink)
.expect("Could not format message");
let output = String::from_utf8(buffer).expect("Output is not valid UTF-8");
assert!(
iso_8601_regex.is_match(output.trim()),
"Output format mismatch! Got: {}",
output
);
let mut buffer = String::with_capacity(128);
formatter
.format_fmt(&message, &mut buffer)
.expect("Could not format message");
assert!(
iso_8601_regex.is_match(&buffer),
"Output format mismatch! Got: {}",
output
);
}
#[test]
pub fn test_logger_level() {
assert_eq!(Cow::from(LogLevel::Debug), "DEBUG");
assert_eq!(Cow::from(LogLevel::Info), "INFO");
assert_eq!(Cow::from(LogLevel::Success), "SUCCESS");
assert_eq!(Cow::from(LogLevel::Warn), "WARN");
assert_eq!(Cow::from(LogLevel::Error), "ERROR");
assert_eq!(Cow::from(LogLevel::Critical), "CRITICAL");
assert_eq!(Cow::from(LogLevel::Fatal), "FATAL");
}
#[test]
pub fn test_direct_logger() {
let buffer = String::with_capacity(128);
let formatter = AtemporalMessageFormatter {};
let service = StringFmtWrite::<AtemporalMessageFormatter>::with_formatter(buffer, formatter);
let logger_impl = DirectLogger::new(service, 0);
let logger = Logger::new(logger_impl);
logger
.log(("DEBUG", "Hello world 1"))
.log(("DEBUG", "Hello world 2"))
.log(("DEBUG", "Hello world 3"));
let expected = "\
[ DEBUG ] Hello world 1\n\
[ DEBUG ] Hello world 2\n\
[ DEBUG ] Hello world 3\n";
let logger_impl = logger.get_implementation();
let logger_impl = logger_impl
.as_any()
.downcast_ref::<DirectLogger>()
.expect("Can't downcast to DirectLogger");
let service = logger_impl
.get_service()
.as_any()
.downcast_ref::<StringFmtWrite<AtemporalMessageFormatter>>()
.expect("Can't downcast to AtemporalMessageFormatter");
let res = service.inspect_writer(|writer| {
assert_eq!(writer, expected, "Buffer content and expected do not math");
true
});
assert!(res.is_some());
}
#[test]
pub fn test_queued_logger_1woker() {
let buffer = Arc::new(Mutex::new(String::with_capacity(128)));
let service = Box::new(ArcedFmtWrite {
buffer: buffer.clone(),
});
let logger_impl = QueuedLogger::new(service, 0, 1);
let logger = Logger::new(logger_impl);
logger
.log(("DEBUG", "Hello world 1"))
.log(("DEBUG", "Hello world 2"))
.log(("DEBUG", "Hello world 3"));
drop(logger);
let expected = "\
[ DEBUG ] Hello world 1\n\
[ DEBUG ] Hello world 2\n\
[ DEBUG ] Hello world 3\n";
let string = buffer.lock().expect("Couldn't lock buffer");
assert_eq!(
string.as_str(),
expected,
"Buffer content and expected do not math"
);
}
#[test]
pub fn test_queued_logger() {
let buffer = Arc::new(Mutex::new(String::with_capacity(128)));
let service = Box::new(ArcedFmtWrite {
buffer: buffer.clone(),
});
let logger_impl = QueuedLogger::new(service, 0, 4);
let logger = Logger::new(logger_impl);
for i in 1..1000 {
let line = format!("Hello world {}", i);
logger.log(("DEBUG", line));
}
drop(logger);
let string = buffer.lock().expect("Couldn't lock buffer");
for i in 1..1000 {
let line = format!("Hello world {}\n", i);
assert!(string.contains(line.as_str()), "Log line not found");
}
}