use std::{
fs::{self, File},
io::Write,
path::PathBuf,
time::{SystemTime, UNIX_EPOCH},
};
use crate::{
logger::{init, load_config_from_file, set_errors::ReadFromConfigFileError},
Level, CONFIG,
};
use crate::logger::formatter::LogFormatter;
fn temp_env_file(contents: &str) -> PathBuf {
let mut path = std::env::temp_dir();
let ts = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
path.push(format!("loggit_env_test_{}.env", ts));
let mut file = File::create(&path).expect("failed to create temp env‑file");
write!(file, "{}", contents).expect("failed to write temp env‑file");
path
}
fn config_snapshot() -> crate::Config {
CONFIG.read().expect("CONFIG should be initialised").clone()
}
#[test]
fn env_enabled_variants() {
init();
let p = temp_env_file("enabled=false\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(
res,
Err(ReadFromConfigFileError::DisabledToBeUsed)
));
fs::remove_file(p).ok();
init();
let p = temp_env_file("level=info\n");
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
fs::remove_file(p).ok();
init();
let p = temp_env_file("enabled=maybe\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(res, Err(ReadFromConfigFileError::ParseError(_))));
fs::remove_file(p).ok();
}
#[test]
fn env_all_levels_valid() {
let cases = [
("trace", Level::TRACE),
("debug", Level::DEBUG),
("info", Level::INFO),
("warn", Level::WARN),
("error", Level::ERROR),
];
for (lvl_str, lvl_enum) in cases {
init();
let p = temp_env_file(&format!("enabled=true\nlevel={}\n", lvl_str));
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
let cfg = config_snapshot();
assert_eq!(cfg.level, lvl_enum, "level `{}` not applied", lvl_str);
fs::remove_file(p).ok();
}
init();
let p = temp_env_file("level=verbose\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(res, Err(ReadFromConfigFileError::ParseError(_))));
fs::remove_file(p).ok();
}
#[test]
fn env_print_to_terminal_variants() {
init();
let p = temp_env_file("print_to_terminal=true\n");
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
assert!(config_snapshot().print_to_terminal);
fs::remove_file(p).ok();
init();
let p = temp_env_file("print_to_terminal=false\n");
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
assert!(!config_snapshot().print_to_terminal);
fs::remove_file(p).ok();
init();
let p = temp_env_file("print_to_terminal=nope\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(res, Err(ReadFromConfigFileError::ParseError(_))));
fs::remove_file(p).ok();
}
#[test]
fn env_colorized_variants() {
init();
let p = temp_env_file("colorized=true\n");
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
assert!(config_snapshot().colorized);
fs::remove_file(p).ok();
init();
let p = temp_env_file("colorized=false\n");
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
assert!(!config_snapshot().colorized);
fs::remove_file(p).ok();
init();
let p = temp_env_file("colorized=rainbow\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(res, Err(ReadFromConfigFileError::ParseError(_))));
fs::remove_file(p).ok();
}
#[test]
fn env_global_formatting_ok_and_bad() {
init();
let fmt_txt = "[{level}] {message}";
let p = temp_env_file(&format!("global_formatting=\"{}\"\n", fmt_txt));
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
let cfg = config_snapshot();
let expected = LogFormatter::parse_from_string(fmt_txt).unwrap();
assert_eq!(cfg.trace_log_format.parts, expected.parts);
assert_eq!(cfg.debug_log_format.parts, expected.parts);
assert_eq!(cfg.error_log_format.parts, expected.parts);
fs::remove_file(p).ok();
init();
let bad_fmt = "<red>[{level}]"; let p = temp_env_file(&format!("global_formatting={}\n", bad_fmt));
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(
res,
Err(ReadFromConfigFileError::SetLevelFormatting(_))
));
fs::remove_file(p).ok();
}
#[test]
fn env_individual_level_formatting_invalid() {
init();
let p = temp_env_file("debug_formatting=<blue>{message}\n"); let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(
res,
Err(ReadFromConfigFileError::SetLevelFormatting(_))
));
fs::remove_file(p).ok();
}
#[test]
fn env_file_and_compression_and_rotations() {
init();
let p = temp_env_file(
"file_name=app_{date}_{time}.txt\ncompression=zip\nrotations=\"1 day,500 MB,12:30\"\n",
);
assert!(load_config_from_file(p.to_str().unwrap()).is_ok());
let cfg = config_snapshot();
assert!(
cfg.file_manager.is_some(),
"file_manager should be configured"
);
let fm_dbg = format!("{:?}", cfg.file_manager.as_ref().unwrap());
assert!(
fm_dbg.contains("rotation: ["),
"rotations should be present"
);
fs::remove_file(p).ok();
}
#[test]
fn env_file_invalid_format() {
init();
let p = temp_env_file("file_name=bad<name>.txt\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(res, Err(ReadFromConfigFileError::SetFile(_))));
fs::remove_file(p).ok();
}
#[test]
fn env_compression_without_file() {
init();
let p = temp_env_file("compression=zip\n"); let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(
res,
Err(ReadFromConfigFileError::SetCompression(_))
));
fs::remove_file(p).ok();
}
#[test]
fn env_invalid_compression_value() {
init();
let p = temp_env_file("file_name=app_{date}.txt\ncompression=rar\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(
res,
Err(ReadFromConfigFileError::SetCompression(_))
));
fs::remove_file(p).ok();
}
#[test]
fn env_rotations_invalid() {
init();
let p = temp_env_file("file_name=app_{date}.txt\nrotations=invalid\n");
let res = load_config_from_file(p.to_str().unwrap());
assert!(matches!(res, Err(ReadFromConfigFileError::AddRotation(_))));
fs::remove_file(p).ok();
}
#[test]
fn env_missing_file() {
init();
let bogus_path = "/no/such/path/to_env_file.loggit";
let res = load_config_from_file(bogus_path);
assert!(matches!(
res,
Err(ReadFromConfigFileError::IncorrectFileExtension)
));
let bogus_path = "/no/such/path/to_env_file.env";
let res = load_config_from_file(bogus_path);
assert!(matches!(
res,
Err(ReadFromConfigFileError::ReadFileError(_))
));
}