#![allow(clippy::unwrap_used, clippy::panic)] use super::*;
#[test]
fn test_parse_tcp_full() {
let info = ConnectionInfo::parse("postgres://user:pass@localhost:5433/mydb").unwrap();
assert_eq!(info.transport, TransportType::Tcp);
assert_eq!(info.host, Some("localhost".to_string()));
assert_eq!(info.port, Some(5433));
assert_eq!(info.database, "mydb");
assert_eq!(info.user, "user");
assert_eq!(info.password.as_ref().map(|p| p.as_str()), Some("pass"));
}
#[test]
fn test_parse_tcp_minimal() {
let info = ConnectionInfo::parse("postgres://localhost/mydb").unwrap();
assert_eq!(info.transport, TransportType::Tcp);
assert_eq!(info.host, Some("localhost".to_string()));
assert_eq!(info.port, Some(5432));
assert_eq!(info.database, "mydb");
}
#[test]
fn test_parse_unix() {
let info = ConnectionInfo::parse("postgres:///mydb").unwrap();
assert_eq!(info.transport, TransportType::Unix);
assert_eq!(info.database, "mydb");
assert_eq!(info.port, Some(5432)); assert!(info.unix_socket.is_some());
let path = info.unix_socket.unwrap();
assert!(path.to_string_lossy().contains(".s.PGSQL.5432"));
}
#[test]
fn test_parse_unix_socket_path_construction() {
let info = ConnectionInfo::parse("postgres:///mydb").unwrap();
let socket_path = info.unix_socket.unwrap();
assert!(socket_path.to_string_lossy().ends_with(".s.PGSQL.5432"));
}
#[test]
fn test_parse_unix_with_custom_directory() {
let info = ConnectionInfo::parse("postgres:///mydb?host=/custom/path").unwrap();
assert_eq!(info.transport, TransportType::Unix);
assert_eq!(info.database, "mydb");
assert_eq!(info.port, Some(5432));
let socket_path = info.unix_socket.unwrap();
assert_eq!(socket_path, PathBuf::from("/custom/path/.s.PGSQL.5432"));
}
#[test]
fn test_parse_unix_with_custom_port() {
let info = ConnectionInfo::parse("postgres:///mydb?host=/tmp&port=5433").unwrap();
assert_eq!(info.transport, TransportType::Unix);
assert_eq!(info.database, "mydb");
assert_eq!(info.port, Some(5433));
let socket_path = info.unix_socket.unwrap();
assert_eq!(socket_path, PathBuf::from("/tmp/.s.PGSQL.5433"));
}
#[test]
fn test_construct_socket_path() {
let path = construct_socket_path("/run/postgresql", 5432);
assert_eq!(path, PathBuf::from("/run/postgresql/.s.PGSQL.5432"));
let path = construct_socket_path("/var/run/postgresql", 5433);
assert_eq!(path, PathBuf::from("/var/run/postgresql/.s.PGSQL.5433"));
}
#[test]
fn test_parse_query_param() {
let host = parse_query_param("?host=/tmp", "host");
assert_eq!(host, Some("/tmp".to_string()));
let port = parse_query_param("?host=/tmp&port=5433", "port");
assert_eq!(port, Some("5433".to_string()));
let missing = parse_query_param("?host=/tmp", "port");
assert_eq!(missing, None);
let empty = parse_query_param("", "host");
assert_eq!(empty, None);
}
#[test]
fn test_parse_unix_default_database() {
let info = ConnectionInfo::parse("postgres:///").unwrap();
assert_eq!(info.transport, TransportType::Unix);
assert!(!info.database.is_empty());
}
#[test]
fn test_password_field_present() {
let info = ConnectionInfo::parse("postgres://user:secret@localhost/db").unwrap();
assert_eq!(info.password.as_ref().map(|p| p.as_str()), Some("secret"));
}
#[test]
fn test_valid_socket_dir_accepted() {
validate_socket_dir("/run/postgresql")
.unwrap_or_else(|e| panic!("expected Ok for /run/postgresql: {e}"));
validate_socket_dir("/tmp").unwrap_or_else(|e| panic!("expected Ok for /tmp: {e}"));
validate_socket_dir("/var/run/postgresql")
.unwrap_or_else(|e| panic!("expected Ok for /var/run/postgresql: {e}"));
}
#[test]
fn test_relative_socket_dir_rejected() {
let err = validate_socket_dir("run/postgresql").unwrap_err();
assert!(matches!(err, WireError::Config(_)));
let msg = err.to_string();
assert!(msg.contains("absolute"), "error must say 'absolute': {msg}");
}
#[test]
fn test_dot_dot_in_socket_dir_rejected() {
let err = validate_socket_dir("/run/../etc").unwrap_err();
assert!(matches!(err, WireError::Config(_)));
let msg = err.to_string();
assert!(msg.contains(".."), "error must mention '..': {msg}");
}
#[test]
fn test_socket_dir_too_long_rejected() {
let long = format!("/{}", "a".repeat(4096));
let err = validate_socket_dir(&long).unwrap_err();
assert!(matches!(err, WireError::Config(_)));
let msg = err.to_string();
assert!(msg.contains("4096"), "error must mention the limit: {msg}");
}
#[test]
fn test_connection_string_rejects_traversal_in_host_param() {
let result = ConnectionInfo::parse("postgres:///mydb?host=/run/../etc");
assert!(result.is_err(), "path traversal in host must be rejected");
}
#[test]
fn test_connection_string_rejects_relative_host_param() {
let result = ConnectionInfo::parse("postgres:///mydb?host=relative/path");
assert!(result.is_err(), "relative host param must be rejected");
}
#[test]
fn test_parse_ipv6_with_port() {
let info = ConnectionInfo::parse("postgres://user@[::1]:5432/db").unwrap();
assert_eq!(info.host, Some("::1".to_string()));
assert_eq!(info.port, Some(5432));
assert_eq!(info.database, "db");
assert_eq!(info.user, "user");
}
#[test]
fn test_parse_ipv6_default_port() {
let info = ConnectionInfo::parse("postgres://user@[::1]/db").unwrap();
assert_eq!(info.host, Some("::1".to_string()));
assert_eq!(info.port, Some(5432));
}
#[test]
fn test_parse_ipv6_non_default_port() {
let info = ConnectionInfo::parse("postgres://user@[::1]:5433/db").unwrap();
assert_eq!(info.host, Some("::1".to_string()));
assert_eq!(info.port, Some(5433));
}
#[test]
fn test_parse_ipv6_zone_id() {
let info = ConnectionInfo::parse("postgres://user@[fe80::1%25eth0]:5432/db").unwrap();
assert_eq!(info.host, Some("fe80::1%25eth0".to_string()));
assert_eq!(info.port, Some(5432));
}