use assert_cmd::cargo::cargo_bin_cmd;
use lineguard::config::load_config;
use predicates::prelude::*;
use tempfile::TempDir;
#[test]
fn test_invalid_toml_syntax() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
[checks
newline_ending = true
"#,
)
.unwrap();
let mut cmd = cargo_bin_cmd!("lineguard");
cmd.arg(".")
.arg("--config")
.arg(&config_path)
.assert()
.failure()
.code(4)
.stderr(predicate::str::contains("Error loading configuration"));
}
#[test]
fn test_unknown_config_fields() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
unknown_field = true
not_a_real_option = "value"
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_ok());
let config = config.unwrap();
assert!(config.checks.newline_ending); assert!(config.checks.trailing_spaces); assert!(config.ignore_patterns.is_empty()); assert!(config.file_extensions.is_empty()); }
#[test]
fn test_invalid_type_for_config_field() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
[checks]
newline_ending = "yes" # Should be boolean
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("invalid type")
|| error_msg.contains("expected")
|| error_msg.contains("boolean")
);
}
#[test]
fn test_empty_config_file() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(&config_path, "").unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_ok());
let config = config.unwrap();
assert!(config.checks.newline_ending);
assert!(config.checks.trailing_spaces);
assert!(config.ignore_patterns.is_empty());
assert!(config.file_extensions.is_empty());
}
#[test]
fn test_config_file_with_only_comments() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
# This is a comment
# Another comment
# [checks]
# newline_ending = false
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_ok());
let config = config.unwrap();
assert!(config.checks.newline_ending);
assert!(config.checks.trailing_spaces);
assert!(config.ignore_patterns.is_empty());
assert!(config.file_extensions.is_empty());
}
#[test]
fn test_config_file_not_found() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("nonexistent.toml");
let config = load_config(Some(config_path.as_path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("Configuration file not found")
&& error_msg.contains("nonexistent.toml")
);
}
#[test]
fn test_malformed_ignore_patterns() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
ignore_patterns = "not_an_array"
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("invalid type")
|| error_msg.contains("expected")
|| error_msg.contains("array")
|| error_msg.contains("sequence")
);
}
#[test]
fn test_malformed_file_extensions() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
file_extensions = 123
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("invalid type")
|| error_msg.contains("expected")
|| error_msg.contains("array")
|| error_msg.contains("sequence")
);
}
#[test]
fn test_config_with_invalid_utf8() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
use std::io::Write;
let mut file = std::fs::File::create(&config_path).unwrap();
file.write_all(&[0xFF, 0xFE, 0xFD]).unwrap();
drop(file);
let config = load_config(Some(config_path.as_path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("UTF-8")
|| error_msg.contains("utf8")
|| error_msg.contains("invalid")
|| error_msg.contains("encoding")
);
}
#[test]
fn test_config_directory_instead_of_file() {
let temp_dir = TempDir::new().unwrap();
let config = load_config(Some(temp_dir.path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("Is a directory")
|| error_msg.contains("directory")
|| error_msg.contains("I/O")
|| error_msg.contains("Access is denied")
|| error_msg.contains("Permission denied")
);
}
#[test]
fn test_circular_config_inclusion() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
# include = ".lineguardrc"
[checks]
newline_ending = true
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_ok()); }
#[test]
fn test_config_with_extreme_values() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
let mut long_patterns = vec![];
for i in 0..1000 {
long_patterns.push(format!("pattern_{i}"));
}
let config_content = format!(
r#"
ignore_patterns = {long_patterns:?}
file_extensions = ["txt"]
"#
);
std::fs::write(&config_path, config_content).unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_ok());
let config = config.unwrap();
assert_eq!(config.ignore_patterns.len(), 1000);
}
#[test]
fn test_nested_config_sections() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
[checks]
newline_ending = true
trailing_spaces = false
[checks.advanced]
# This would be an invalid nested structure
something = true
"#,
)
.unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_ok());
let config = config.unwrap();
assert!(config.checks.newline_ending); assert!(!config.checks.trailing_spaces); }
#[test]
#[cfg(unix)]
fn test_config_permissions_issue() {
use std::os::unix::fs::PermissionsExt;
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join(".lineguardrc");
std::fs::write(
&config_path,
r#"
[checks]
newline_ending = true
"#,
)
.unwrap();
let mut perms = std::fs::metadata(&config_path).unwrap().permissions();
perms.set_mode(0o000);
std::fs::set_permissions(&config_path, perms).unwrap();
let config = load_config(Some(config_path.as_path()));
assert!(config.is_err());
let error = config.unwrap_err();
let error_msg = error.to_string();
assert!(
error_msg.contains("Permission denied")
|| error_msg.contains("permission")
|| error_msg.contains("denied")
);
let mut perms = std::fs::metadata(&config_path).unwrap().permissions();
perms.set_mode(0o644);
std::fs::set_permissions(&config_path, perms).unwrap();
}