use flash_watcher::{
format_display_path, load_config, merge_config, run_benchmarks, validate_args, Args,
};
use std::io::Write;
use std::path::Path;
use tempfile::NamedTempFile;
#[cfg(test)]
mod tests {
use super::*;
fn create_config_file(content: &str) -> NamedTempFile {
let mut file = NamedTempFile::new().unwrap();
write!(file, "{}", content).unwrap();
file
}
#[test]
fn test_main_logic_config_loading() {
let config_yaml = r#"
command: ["cargo", "test"]
watch: ["src", "tests"]
ext: "rs"
debounce: 200
initial: true
"#;
let file = create_config_file(config_yaml);
let config_path = file.path().to_str().unwrap();
let config = load_config(config_path).unwrap();
assert_eq!(config.command, vec!["cargo", "test"]);
let mut args = Args::default();
merge_config(&mut args, config);
assert_eq!(args.command, vec!["cargo", "test"]);
assert_eq!(args.watch, vec!["src", "tests"]);
assert_eq!(args.ext, Some("rs".to_string()));
assert_eq!(args.debounce, 200);
assert!(args.initial);
}
#[test]
fn test_main_logic_config_loading_error() {
let result = load_config("nonexistent.yaml");
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Failed to read config file"));
}
#[test]
fn test_main_logic_validation() {
let mut args = Args::default();
let result = validate_args(&args);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("No command specified"));
args.command = vec!["echo".to_string(), "test".to_string()];
let result = validate_args(&args);
assert!(result.is_ok());
}
#[test]
fn test_main_logic_benchmark_mode() {
let result = run_benchmarks();
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_format_display_path_edge_cases() {
assert_eq!(format_display_path(Path::new("test.js")), "test.js");
assert_eq!(format_display_path(Path::new("src/test.js")), "test.js");
assert_eq!(
format_display_path(Path::new("/full/path/to/file.rs")),
"file.rs"
);
assert_eq!(format_display_path(Path::new(".")), ".");
assert_eq!(format_display_path(Path::new("..")), "..");
assert_eq!(format_display_path(Path::new("/")), "/");
assert_eq!(
format_display_path(Path::new("very/deep/nested/path/file.txt")),
"file.txt"
);
assert_eq!(
format_display_path(Path::new("./relative/path/file.js")),
"file.js"
);
assert_eq!(
format_display_path(Path::new("../parent/file.py")),
"file.py"
);
assert_eq!(
format_display_path(Path::new("path/file with spaces.txt")),
"file with spaces.txt"
);
assert_eq!(
format_display_path(Path::new("path/file-with-dashes.js")),
"file-with-dashes.js"
);
assert_eq!(
format_display_path(Path::new("path/file_with_underscores.rs")),
"file_with_underscores.rs"
);
}
#[test]
fn test_args_with_config_precedence() {
let config_yaml = r#"
command: ["config-command"]
watch: ["config-watch"]
ext: "config-ext"
debounce: 999
initial: true
clear: true
restart: true
stats: true
stats_interval: 999
"#;
let file = create_config_file(config_yaml);
let config = load_config(file.path().to_str().unwrap()).unwrap();
let mut args = Args {
command: vec!["cli-command".to_string()], watch: vec!["cli-watch".to_string()], ext: Some("cli-ext".to_string()), pattern: vec!["cli-pattern".to_string()], ignore: vec!["cli-ignore".to_string()], debounce: 50, initial: true, clear: true, restart: true, stats: true, stats_interval: 5, bench: false,
config: None,
fast: false,
};
let original_args = args.clone();
merge_config(&mut args, config);
assert_eq!(args.command, original_args.command);
assert_eq!(args.watch, original_args.watch);
assert_eq!(args.ext, original_args.ext);
assert_eq!(args.pattern, original_args.pattern);
assert_eq!(args.ignore, original_args.ignore);
assert_eq!(args.debounce, original_args.debounce);
assert_eq!(args.stats_interval, original_args.stats_interval);
assert!(args.initial); assert!(args.clear); assert!(args.restart); assert!(args.stats); }
#[test]
fn test_config_with_empty_command() {
let config_yaml = r#"
command: []
watch: ["src"]
"#;
let file = create_config_file(config_yaml);
let config = load_config(file.path().to_str().unwrap()).unwrap();
let mut args = Args::default();
merge_config(&mut args, config);
assert!(args.command.is_empty());
assert_eq!(args.watch, vec!["src"]);
}
#[test]
fn test_config_partial_override() {
let config_yaml = r#"
command: []
ext: "js,ts"
debounce: 300
stats: true
"#;
let file = create_config_file(config_yaml);
let config = load_config(file.path().to_str().unwrap()).unwrap();
let mut args = Args::default();
merge_config(&mut args, config);
assert_eq!(args.ext, Some("js,ts".to_string()));
assert_eq!(args.debounce, 300);
assert!(args.stats);
assert!(args.command.is_empty());
assert_eq!(args.watch, vec!["."]);
assert!(!args.initial); assert!(!args.clear); assert!(!args.restart); assert_eq!(args.stats_interval, 10); }
#[test]
fn test_config_with_null_values() {
let config_yaml = r#"
command: ["test"]
watch: null
ext: null
pattern: null
ignore: null
debounce: null
initial: null
clear: null
restart: null
stats: null
stats_interval: null
"#;
let file = create_config_file(config_yaml);
let config = load_config(file.path().to_str().unwrap()).unwrap();
let mut args = Args::default();
merge_config(&mut args, config);
assert_eq!(args.command, vec!["test"]);
assert_eq!(args.watch, vec!["."]); assert_eq!(args.ext, None); assert_eq!(args.debounce, 100); }
#[test]
fn test_invalid_config_yaml() {
let invalid_configs = vec![
"command: not-a-list",
"invalid: yaml: structure",
"[broken yaml",
"command:\n - valid\ninvalid_field: {broken: yaml",
];
for invalid_yaml in invalid_configs {
let file = create_config_file(invalid_yaml);
let result = load_config(file.path().to_str().unwrap());
assert!(
result.is_err(),
"Should fail for invalid YAML: {}",
invalid_yaml
);
}
}
#[test]
fn test_config_type_mismatches() {
let config_yaml = r#"
command: "should-be-array"
debounce: "should-be-number"
initial: "should-be-boolean"
"#;
let file = create_config_file(config_yaml);
let result = load_config(file.path().to_str().unwrap());
assert!(result.is_err());
}
}