refactor(tests): improve test logging setup and organization
- Create unit test and integration tests for logs in separate tests - Centralize temporary log file creation in common.rs - Remove redundant logging initialization code from common.rs - Update all test files to handle their own logging initialization - Add detailed debug logging throughout test execution - Add log file content display for better test debugging - Standardize error handling across test files Changes: - Create setup_test_log_file() helper in common.rs - Remove setup_test_logging() and setup_temp_log() functions - Update test files to use common setup_test_log_file(): - test_log_detail_macro.rs - test_log_timed_macro.rs - test_different_log_levels.rs - test_init_logging_with_file.rs - test_init_logging_append_mode.rs This change improves test maintainability by: 1. Reducing code duplication 2. Making test behavior more explicit 3. Improving test output for debugging 4. Following single responsibility principle
This commit is contained in:
parent
98a9649bf2
commit
852df37ffc
@ -1,3 +1,3 @@
|
|||||||
mod directory_processor_test;
|
mod directory_processor_test;
|
||||||
|
//mod logging_tests;
|
||||||
// Add other test modules here as needed
|
// Add other test modules here as needed
|
@ -1,23 +1,23 @@
|
|||||||
use std::path::PathBuf;
|
use dir_odt_to_pdf::directory_processor::DirectoryProcessor;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use crate::directory_processor::DirectoryProcessor;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_needs_copy_or_conversion() {
|
fn test_needs_processing() {
|
||||||
let temp_dir = TempDir::new().unwrap();
|
let temp_dir = TempDir::new().unwrap();
|
||||||
let source = temp_dir.path().join("source.txt");
|
let source = temp_dir.path().join("source.txt");
|
||||||
let dest = temp_dir.path().join("dest.txt");
|
let dest = temp_dir.path().join("dest.txt");
|
||||||
|
|
||||||
// Test non-existent destination
|
// Test non-existent destination
|
||||||
assert!(DirectoryProcessor::needs_copy_or_conversion(&source, &dest));
|
assert!(DirectoryProcessor::needs_processing(&source, &dest));
|
||||||
|
|
||||||
// Create files and test modification times
|
// Create files and test modification times
|
||||||
fs::write(&source, "test").unwrap();
|
fs::write(&source, "test").unwrap();
|
||||||
fs::write(&dest, "test").unwrap();
|
fs::write(&dest, "test").unwrap();
|
||||||
|
|
||||||
// Files created very close together should not need copying
|
// Files created very close together should not need copying
|
||||||
assert!(!DirectoryProcessor::needs_copy_or_conversion(&source, &dest));
|
assert!(!DirectoryProcessor::needs_processing(&source, &dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
12
tests/common.rs
Normal file
12
tests/common.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
/// Sets up a temporary directory and log file for testing
|
||||||
|
/// Returns:
|
||||||
|
/// - TempDir: The temporary directory (keep this in scope to prevent cleanup)
|
||||||
|
/// - PathBuf: Path to the log file
|
||||||
|
pub fn setup_test_log_file() -> (TempDir, PathBuf) {
|
||||||
|
let temp_dir = tempfile::TempDir::new().expect("Failed to create temporary directory for test");
|
||||||
|
let log_path = temp_dir.path().join("test.log");
|
||||||
|
(temp_dir, log_path)
|
||||||
|
}
|
50
tests/logging_writer_tests.rs
Normal file
50
tests/logging_writer_tests.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use dir_odt_to_pdf::error::{ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, LogWriter};
|
||||||
|
use log::LevelFilter;
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_writer_file_output() -> io::Result<()> {
|
||||||
|
let temp_file = NamedTempFile::new()?;
|
||||||
|
let mut writer = LogWriter::new(Some(temp_file.reopen()?));
|
||||||
|
writer.write_all(b"test message\n")?;
|
||||||
|
writer.flush()?;
|
||||||
|
let content = fs::read_to_string(temp_file.path())?;
|
||||||
|
assert_eq!(content, "test message\n");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_writer_console_output() {
|
||||||
|
let mut writer = LogWriter::new(None);
|
||||||
|
assert!(writer.write_all(b"test message\n").is_ok());
|
||||||
|
assert!(writer.flush().is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_config_default() {
|
||||||
|
let config = LogConfig::default();
|
||||||
|
assert_eq!(config.log_level, LevelFilter::Info);
|
||||||
|
assert_eq!(config.log_file, None);
|
||||||
|
assert!(!config.append_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_writer() -> Result<()> {
|
||||||
|
let mut writer = LogWriter::new(None);
|
||||||
|
writer
|
||||||
|
.write_all(b"test message\n")
|
||||||
|
.map_err(ProcessError::Io)?;
|
||||||
|
writer.flush().map_err(ProcessError::Io)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_writer_methods() -> Result<()> {
|
||||||
|
let mut writer = LogWriter::new(None);
|
||||||
|
assert!(writer.write_all(b"test message\n").is_ok());
|
||||||
|
assert!(writer.flush().is_ok());
|
||||||
|
Ok(())
|
||||||
|
}
|
46
tests/test_different_log_levels.rs
Normal file
46
tests/test_different_log_levels.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use dir_odt_to_pdf::error::{ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{LevelFilter, debug, error, info, trace, warn};
|
||||||
|
use std::fs;
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_different_log_levels() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let (_temp_dir, log_path) = common::setup_test_log_file();
|
||||||
|
|
||||||
|
// Initialize logging with Trace level
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Trace,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize logging
|
||||||
|
init_logging(config)?;
|
||||||
|
debug!("Starting test_different_log_levels test");
|
||||||
|
|
||||||
|
// Test all log levels
|
||||||
|
info!("Testing different log levels...");
|
||||||
|
trace!("trace message");
|
||||||
|
debug!("debug message");
|
||||||
|
info!("info message");
|
||||||
|
warn!("warn message");
|
||||||
|
error!("error message");
|
||||||
|
|
||||||
|
// Read and verify the log file
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("=== Log File Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
// Verify all messages are present
|
||||||
|
assert!(content.contains("trace message"));
|
||||||
|
assert!(content.contains("debug message"));
|
||||||
|
assert!(content.contains("info message"));
|
||||||
|
assert!(content.contains("warn message"));
|
||||||
|
assert!(content.contains("error message"));
|
||||||
|
debug!("Test completed successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
68
tests/test_init_logging_append_mode.rs
Normal file
68
tests/test_init_logging_append_mode.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use dir_odt_to_pdf::error::{LogError, ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{LevelFilter, debug, info};
|
||||||
|
use std::fs;
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_init_logging_append_mode() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let (_temp_dir, log_path) = common::setup_test_log_file();
|
||||||
|
debug!("Starting test_init_logging_append_mode test");
|
||||||
|
|
||||||
|
// First initialization
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("About to initialize logging for the first time...");
|
||||||
|
init_logging(config)?;
|
||||||
|
|
||||||
|
// Write first message
|
||||||
|
info!("Testing append mode...");
|
||||||
|
info!("first message");
|
||||||
|
|
||||||
|
// Read first message
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("=== Initial Log Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
assert!(content.contains("first message"));
|
||||||
|
|
||||||
|
// Try second initialization with append mode
|
||||||
|
debug!("Attempting second initialization with append mode...");
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to initialize again - this should fail
|
||||||
|
match init_logging(config) {
|
||||||
|
Err(ProcessError::Log(LogError::AlreadyInitialized)) => {
|
||||||
|
debug!("Got expected AlreadyInitialized error");
|
||||||
|
info!("second message");
|
||||||
|
|
||||||
|
// Check final contents
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("\n=== Final Log Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
assert!(content.contains("first message"));
|
||||||
|
assert!(content.contains("second message"));
|
||||||
|
debug!("Test completed successfully");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Unexpected success on second initialization");
|
||||||
|
panic!("Expected AlreadyInitialized error")
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
info!("Unexpected error: {:?}", e);
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
tests/test_init_logging_with_file.rs
Normal file
37
tests/test_init_logging_with_file.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use dir_odt_to_pdf::error::{ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{LevelFilter, debug, info};
|
||||||
|
use std::fs;
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_init_logging_with_file() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let (_temp_dir, log_path) = common::setup_test_log_file();
|
||||||
|
|
||||||
|
// Initialize logging with Debug level
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize logging
|
||||||
|
init_logging(config)?;
|
||||||
|
debug!("Starting test_init_logging_with_file test");
|
||||||
|
|
||||||
|
// Test basic logging
|
||||||
|
info!("Testing basic file logging...");
|
||||||
|
info!("test message");
|
||||||
|
|
||||||
|
// Read and verify the log file
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("=== Log File Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
assert!(content.contains("test message"));
|
||||||
|
debug!("Test completed successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
39
tests/test_log_detail_macro.rs
Normal file
39
tests/test_log_detail_macro.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use dir_odt_to_pdf::error::{ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::log_detail;
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{Level, LevelFilter, debug, info};
|
||||||
|
use std::fs;
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_detail_macro() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let (_temp_dir, log_path) = common::setup_test_log_file();
|
||||||
|
|
||||||
|
// Initialize logging with Debug level
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize logging
|
||||||
|
init_logging(config)?;
|
||||||
|
debug!("Starting test_log_detail_macro test");
|
||||||
|
|
||||||
|
// Test the macro
|
||||||
|
info!("Testing log_detail macro...");
|
||||||
|
log_detail!(Level::Info, "test detail message");
|
||||||
|
|
||||||
|
// Read and verify the log file
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("=== Log File Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
assert!(content.contains("test detail message"));
|
||||||
|
assert!(content.contains(file!()));
|
||||||
|
debug!("Test completed successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
81
tests/test_log_level_changes.rs
Normal file
81
tests/test_log_level_changes.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use dir_odt_to_pdf::error::{LogError, ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{LevelFilter, debug, info};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_level_changes() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let temp_dir = tempfile::TempDir::new().unwrap();
|
||||||
|
let log_path = temp_dir.path().join("test.log");
|
||||||
|
|
||||||
|
// Initialize logging with Info level first
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Info,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize logging
|
||||||
|
init_logging(config)?;
|
||||||
|
|
||||||
|
// Write some messages at different levels
|
||||||
|
debug!("First debug message"); // Should not appear (we're at Info level)
|
||||||
|
info!("First info message"); // Should appear
|
||||||
|
|
||||||
|
// Read the log file
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("=== Initial Log Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
// Verify initial messages
|
||||||
|
assert!(
|
||||||
|
!content.contains("First debug message"),
|
||||||
|
"Debug message should not appear at Info level"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
content.contains("First info message"),
|
||||||
|
"Info message should appear"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to change log level - this should fail with AlreadyInitialized
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
match init_logging(config) {
|
||||||
|
Err(ProcessError::Log(LogError::AlreadyInitialized)) => {
|
||||||
|
// Expected error
|
||||||
|
info!("Got expected AlreadyInitialized error");
|
||||||
|
|
||||||
|
// Write more messages
|
||||||
|
debug!("Second debug message"); // Still won't appear (still at Info level)
|
||||||
|
info!("Second info message"); // Will appear
|
||||||
|
|
||||||
|
// Check final log contents
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("\n=== Final Log Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
// Verify final state
|
||||||
|
assert!(
|
||||||
|
!content.contains("Second debug message"),
|
||||||
|
"Debug messages should still not appear"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
content.contains("Second info message"),
|
||||||
|
"Info messages should still appear"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
|
panic!("Expected AlreadyInitialized error, but logger was reinitialized")
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
42
tests/test_log_timed_macro.rs
Normal file
42
tests/test_log_timed_macro.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use dir_odt_to_pdf::error::{ProcessError, Result};
|
||||||
|
use dir_odt_to_pdf::log_timed;
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{Level, LevelFilter, debug, info};
|
||||||
|
use std::fs;
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_log_timed_macro() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let (_temp_dir, log_path) = common::setup_test_log_file();
|
||||||
|
|
||||||
|
// Initialize logging with Debug level
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize logging
|
||||||
|
init_logging(config)?;
|
||||||
|
debug!("Starting test_log_timed_macro test");
|
||||||
|
|
||||||
|
// Test the macro
|
||||||
|
info!("Testing log_timed macro...");
|
||||||
|
log_timed!(Level::Info, "test operation", {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read and verify the log file
|
||||||
|
let content = fs::read_to_string(&log_path).map_err(ProcessError::Io)?;
|
||||||
|
println!("=== Log File Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
assert!(content.contains("test operation"));
|
||||||
|
assert!(content.contains("completed in"));
|
||||||
|
assert!(content.contains("ms"));
|
||||||
|
debug!("Test completed successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
37
tests/test_simple_logging.rs
Normal file
37
tests/test_simple_logging.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use dir_odt_to_pdf::error::Result;
|
||||||
|
use dir_odt_to_pdf::logging::{LogConfig, init_logging};
|
||||||
|
use log::{LevelFilter, debug, info};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_simple_logging() -> Result<()> {
|
||||||
|
// Create a temporary file for logging
|
||||||
|
let temp_dir = tempfile::TempDir::new().unwrap();
|
||||||
|
let log_path = temp_dir.path().join("test.log");
|
||||||
|
|
||||||
|
// Initialize logging with Debug level
|
||||||
|
let config = LogConfig {
|
||||||
|
log_file: Some(log_path.clone()),
|
||||||
|
log_level: LevelFilter::Debug,
|
||||||
|
append_log: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize logging
|
||||||
|
init_logging(config)?;
|
||||||
|
|
||||||
|
// Write some log messages
|
||||||
|
debug!("This is a debug message");
|
||||||
|
info!("This is an info message");
|
||||||
|
|
||||||
|
// Read the log file
|
||||||
|
let content = fs::read_to_string(&log_path).unwrap();
|
||||||
|
println!("=== Log File Contents ===");
|
||||||
|
println!("{}", content);
|
||||||
|
println!("=======================");
|
||||||
|
|
||||||
|
// Verify log messages
|
||||||
|
assert!(content.contains("This is a debug message"));
|
||||||
|
assert!(content.contains("This is an info message"));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user