use std::fs::{self, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::Path;
use crate::error::{LoggerError, LoggerResult};
#[derive(Debug)]
pub struct TextWriter;
impl TextWriter {
pub fn new() -> Self {
Self
}
pub fn write_message(&self, message: &str, file_path: &Path) -> LoggerResult<()> {
self.ensure_directory_exists(file_path)?;
let file = OpenOptions::new()
.create(true)
.append(true)
.open(file_path)
.map_err(|_| LoggerError::FileCreationFailed {
path: file_path.display().to_string(),
reason: "Failed to open file for writing".to_string(),
})?;
let mut writer = BufWriter::new(file);
writeln!(writer, "{}", message)
.map_err(|_| LoggerError::DiskFull {
path: file_path.display().to_string(),
bytes_attempted: message.len() + 1, })?;
writer.flush()
.map_err(|_| LoggerError::DiskFull {
path: file_path.display().to_string(),
bytes_attempted: message.len() + 1,
})?;
Ok(())
}
fn ensure_directory_exists(&self, file_path: &Path) -> LoggerResult<()> {
if let Some(parent_dir) = file_path.parent() {
if !parent_dir.exists() {
fs::create_dir_all(parent_dir)
.map_err(|_| LoggerError::DirectoryCreationFailed {
path: parent_dir.display().to_string(),
reason: "Failed to create parent directories".to_string(),
})?;
}
}
Ok(())
}
pub fn test_write_permissions(&self, file_path: &Path) -> LoggerResult<()> {
self.write_message("", file_path)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
use std::fs;
#[test]
fn test_write_message_creates_file() {
let temp_dir = tempdir().unwrap();
let log_path = temp_dir.path().join("test.log");
let writer = TextWriter::new();
let result = writer.write_message("Test log message", &log_path);
assert!(result.is_ok());
assert!(log_path.exists());
let content = fs::read_to_string(&log_path).unwrap();
assert_eq!(content, "Test log message\n");
}
#[test]
fn test_write_message_appends_to_existing_file() {
let temp_dir = tempdir().unwrap();
let log_path = temp_dir.path().join("test.log");
let writer = TextWriter::new();
writer.write_message("First message", &log_path).unwrap();
writer.write_message("Second message", &log_path).unwrap();
let content = fs::read_to_string(&log_path).unwrap();
assert_eq!(content, "First message\nSecond message\n");
}
#[test]
fn test_ensure_directory_creates_nested_dirs() {
let temp_dir = tempdir().unwrap();
let log_path = temp_dir.path().join("logs").join("app").join("test.log");
let writer = TextWriter::new();
let result = writer.write_message("Test", &log_path);
assert!(result.is_ok());
assert!(log_path.exists());
assert!(log_path.parent().unwrap().exists());
}
#[test]
fn test_empty_message_handling() {
let temp_dir = tempdir().unwrap();
let log_path = temp_dir.path().join("empty.log");
let writer = TextWriter::new();
let result = writer.write_message("", &log_path);
assert!(result.is_ok());
let content = fs::read_to_string(&log_path).unwrap();
assert_eq!(content, "\n"); }
}