use std::fs;
use guardy::config::{
core::CONFIG,
files::loader::ConfigFileLoader,
hooks::{HookCommand, HookDefinition},
};
use tempfile::TempDir;
#[tokio::test]
async fn test_hooks_config_loading_from_global_config() {
let hooks_config = &CONFIG.hooks;
assert!(!hooks_config.skip_all);
assert!(hooks_config.parallel);
assert!(!hooks_config.pre_commit.skip);
assert!(!hooks_config.commit_msg.skip);
println!("✅ Global hooks config loaded successfully");
}
#[tokio::test]
async fn test_hooks_config_loading_via_config_loader() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::create_dir(temp_path.join(".git")).unwrap();
let config_with_dashes = r#"
[hooks]
parallel = true
skip-all = false
[hooks.pre-commit]
parallel = true
skip = false
[hooks.pre-commit.commands.rust-format]
run = "cargo fmt --check"
glob = ["*.rs"]
stage-fixed = true
description = "Format Rust code with dashes"
"#;
fs::write(temp_path.join("guardy.toml"), config_with_dashes).unwrap();
let loader = ConfigFileLoader::new("guardy");
let merged_config: Option<serde_json::Value> =
loader.discover_and_load_merged_in(temp_path).unwrap();
assert!(merged_config.is_some(), "Should load config file");
let config = merged_config.unwrap();
let hooks_section = config.get("hooks").expect("Should have hooks section");
let pre_commit = guardy::config::macros::get_flexible_key::<HookDefinition>(
hooks_section,
"pre_commit", );
assert!(
pre_commit.is_some(),
"Should find pre_commit/pre-commit via flexible lookup"
);
let pre_commit = pre_commit.unwrap();
assert!(pre_commit.parallel);
assert!(!pre_commit.skip);
assert_eq!(pre_commit.commands.len(), 1);
let rust_format = pre_commit
.commands
.get("rust-format")
.expect("Should have rust-format command");
assert_eq!(rust_format.run, "cargo fmt --check");
assert!(
rust_format.stage_fixed,
"Should parse stage-fixed with kebab-case"
);
assert_eq!(rust_format.description, "Format Rust code with dashes");
println!("✅ Config loaded via real config system with flexible key lookup");
}
#[tokio::test]
async fn test_flexible_config_formats() {
let temp_dir = TempDir::new().unwrap();
let temp_path = temp_dir.path();
fs::create_dir(temp_path.join(".git")).unwrap();
let config_with_underscores = r#"
[hooks]
[hooks.pre_commit]
parallel = true
[hooks.pre_commit.commands.test]
run = "echo test"
stage_fixed = true
"#;
fs::write(temp_path.join("guardy.toml"), config_with_underscores).unwrap();
let loader = ConfigFileLoader::new("guardy");
let merged_config: Option<serde_json::Value> =
loader.discover_and_load_merged_in(temp_path).unwrap();
assert!(merged_config.is_some());
let config = merged_config.unwrap();
let hooks = config.get("hooks").unwrap();
let pre_commit_underscore =
guardy::config::macros::get_flexible_key::<HookDefinition>(hooks, "pre_commit");
let pre_commit_dash =
guardy::config::macros::get_flexible_key::<HookDefinition>(hooks, "pre-commit");
assert!(
pre_commit_underscore.is_some() || pre_commit_dash.is_some(),
"Should find hook with either underscore or dash lookup"
);
println!("✅ Both underscore and dash formats work correctly");
}
#[test]
fn test_hook_command_defaults() {
let cmd: HookCommand = serde_json::from_str(r#"{"run": "echo test"}"#)
.expect("Failed to deserialize minimal HookCommand");
assert_eq!(cmd.run, "echo test");
assert_eq!(cmd.description, "");
assert!(!cmd.continue_on_error);
assert!(!cmd.all_files);
assert!(!cmd.stage_fixed);
assert!(cmd.glob.is_empty());
assert!(cmd.file_types.is_empty());
}
#[test]
fn test_hook_definition_defaults() {
let hook: HookDefinition =
serde_json::from_str(r#"{}"#).expect("Failed to deserialize empty HookDefinition");
assert!(!hook.parallel);
assert!(!hook.skip);
assert!(hook.commands.is_empty());
assert!(hook.scripts.is_empty());
}