#[cfg(test)]
mod tests {
use super::super::security::*;
#[test]
fn test_identifier_escaping_prevents_injection() {
assert_eq!(escape_identifier("users"), "\"users\"");
assert_eq!(escape_identifier("user\"table"), "\"user\"\"table\"");
let malicious_table = "users\"; DROP TABLE secrets; --";
let escaped = escape_identifier(malicious_table);
assert_eq!(escaped, "\"users\"\"; DROP TABLE secrets; --\"");
let sql = format!("SELECT * FROM {}", escaped);
assert!(sql.contains("\"users\"\"; DROP TABLE secrets; --\""));
}
#[test]
fn test_identifier_validation_blocks_dangerous_names() {
assert!(validate_identifier("users").is_ok());
assert!(validate_identifier("user_profile").is_ok());
assert!(validate_identifier("table1").is_ok());
assert!(validate_identifier("user-profile").is_err());
assert!(validate_identifier("user profile").is_err());
assert!(validate_identifier("user;table").is_err());
assert!(validate_identifier("user'table").is_err());
assert!(validate_identifier("user\"table").is_err());
assert!(validate_identifier("user\ntable").is_err());
assert!(validate_identifier("SELECT").is_err());
assert!(validate_identifier("DROP").is_err());
assert!(validate_identifier("UNION").is_err());
assert!(validate_identifier("EXEC").is_err());
assert!(validate_identifier("").is_err());
let long_identifier = "a".repeat(64);
assert!(validate_identifier(&long_identifier).is_err());
assert!(validate_identifier("1table").is_err());
}
#[test]
fn test_query_pattern_validation_detects_attacks() {
assert!(validate_query_pattern("SELECT * FROM users WHERE id = $1").is_ok());
assert!(validate_query_pattern("INSERT INTO users (name) VALUES ($1)").is_ok());
assert!(validate_query_pattern("SELECT * FROM users; DROP TABLE users").is_err());
assert!(validate_query_pattern("SELECT * FROM users;DELETE FROM users").is_err());
assert!(validate_query_pattern("SELECT * FROM users UNION SELECT * FROM secrets").is_err());
assert!(
validate_query_pattern("SELECT * FROM users UNION ALL SELECT password FROM admin")
.is_err()
);
assert!(validate_query_pattern("SELECT * FROM users WHERE id = 1'; --").is_err());
assert!(validate_query_pattern("SELECT * FROM users WHERE id = 1'/*").is_err());
assert!(validate_query_pattern("EXEC sp_executesql 'DROP TABLE users'").is_err());
assert!(validate_query_pattern("EXECUTE xp_cmdshell 'dir'").is_err());
assert!(validate_query_pattern("SELECT * FROM INFORMATION_SCHEMA.TABLES").is_err());
assert!(validate_query_pattern("SELECT * FROM sys.tables").is_err());
}
#[test]
fn test_parameter_validation_allows_safe_content() {
assert!(validate_parameter("john_doe").is_ok());
assert!(validate_parameter("user@example.com").is_ok());
assert!(validate_parameter("123").is_ok());
assert!(validate_parameter("'; DROP TABLE users; --").is_ok());
assert!(validate_parameter("UNION SELECT password FROM admin").is_ok());
assert!(validate_parameter("1' OR '1'='1").is_ok());
let large_param = "x".repeat(70000);
assert!(validate_parameter(&large_param).is_err());
}
#[test]
fn test_identifier_whitelist_strict_validation() {
let whitelist = IdentifierWhitelist::new(vec!["users", "posts", "comments"]);
assert!(whitelist.validate("users").is_ok());
assert!(whitelist.validate("posts").is_ok());
assert!(whitelist.validate("comments").is_ok());
assert!(whitelist.validate("secrets").is_err());
assert!(whitelist.validate("admin").is_err());
assert!(whitelist.validate("'; DROP TABLE users; --").is_err());
assert_eq!(whitelist.escape_if_allowed("users").unwrap(), "\"users\"");
assert!(whitelist.escape_if_allowed("secrets").is_err());
}
#[test]
fn test_count_query_injection_prevention() {
let malicious_relation = "users'; DROP TABLE secrets; --";
assert!(validate_identifier(malicious_relation).is_err());
let safe_relation = "users";
assert!(validate_identifier(safe_relation).is_ok());
let malicious_ids = vec![
"1'; DROP TABLE users; --".to_string(),
"1 UNION SELECT password FROM admin".to_string(),
];
for id in &malicious_ids {
assert!(validate_parameter(id).is_ok());
}
}
#[test]
fn test_complete_injection_attack_scenarios() {
let attack_table = "users; DROP TABLE secrets; --";
assert!(validate_identifier(attack_table).is_err());
let attack_column = "id; DELETE FROM users; --";
assert!(validate_identifier(attack_column).is_err());
let union_attack = "SELECT id FROM users UNION SELECT password FROM admin";
assert!(validate_query_pattern(union_attack).is_err());
let blind_attack = "1' AND (SELECT COUNT(*) FROM admin) > 0 --";
assert!(validate_parameter(blind_attack).is_ok());
let time_attack = "1'; WAITFOR DELAY '00:00:10'; --";
assert!(validate_query_pattern(time_attack).is_err());
let proc_attack = "1'; EXEC xp_cmdshell 'net user hacker password /add'; --";
assert!(validate_query_pattern(proc_attack).is_err());
let schema_attack = "SELECT table_name FROM information_schema.tables";
assert!(validate_query_pattern(schema_attack).is_err());
}
#[test]
fn test_parameter_binding_security() {
let test_cases = vec![
"normal_value",
"'; DROP TABLE users; --",
"1' OR '1'='1",
"1 UNION SELECT password FROM admin",
"1'; EXEC xp_cmdshell 'dir'; --",
"1' AND (SELECT COUNT(*) FROM admin) > 0 --",
];
for test_case in test_cases {
assert!(
validate_parameter(test_case).is_ok(),
"Parameter validation failed for: {}",
test_case
);
}
}
#[test]
fn test_edge_case_escaping() {
let empty = "";
assert!(validate_identifier(empty).is_err());
let quotes_only = "\"\"\"";
let escaped = escape_identifier(quotes_only);
assert_eq!(escaped, "\"\"\"\"\"\"\"\"");
let unicode = "table_名前";
assert!(validate_identifier(unicode).is_err());
let control = "table\x00name";
assert!(validate_identifier(control).is_err());
let max_length = "a".repeat(63);
assert!(validate_identifier(&max_length).is_ok());
let too_long = "a".repeat(64);
assert!(validate_identifier(&too_long).is_err());
}
}