#[cfg(feature = "proxy")]
mod proxy {
use rust_mc_status::proxy::{ProxyConfig, ProxyKind, UdpSupport};
use rust_mc_status::proxy::socks5::ProxyAddr;
use rust_mc_status::McError;
use rust_mc_status::error::ConfigError;
#[test]
fn proxy_addr_parse_host_and_port() {
let addr = ProxyAddr::parse("127.0.0.1:1080").unwrap();
assert_eq!(addr.host, "127.0.0.1");
assert_eq!(addr.port, 1080);
}
#[test]
fn proxy_addr_parse_hostname() {
let addr = ProxyAddr::parse("proxy.example.com:3128").unwrap();
assert_eq!(addr.host, "proxy.example.com");
assert_eq!(addr.port, 3128);
}
#[test]
fn proxy_addr_parse_max_port() {
let addr = ProxyAddr::parse("host:65535").unwrap();
assert_eq!(addr.port, 65535);
}
#[test]
fn proxy_addr_display() {
let addr = ProxyAddr::parse("127.0.0.1:1080").unwrap();
assert_eq!(addr.to_string(), "127.0.0.1:1080");
}
#[test]
fn proxy_addr_parse_missing_port_is_error() {
let e = ProxyAddr::parse("127.0.0.1").unwrap_err();
assert!(
matches!(e, McError::Config(ConfigError::InvalidAddress(_))),
"expected ConfigError::InvalidAddress, got {e:?}"
);
}
#[test]
fn proxy_addr_parse_invalid_port_is_error() {
let e = ProxyAddr::parse("127.0.0.1:99999").unwrap_err();
assert!(
matches!(e, McError::Config(ConfigError::InvalidPort(_))),
"expected ConfigError::InvalidPort, got {e:?}"
);
}
#[test]
fn proxy_addr_parse_non_numeric_port_is_error() {
let e = ProxyAddr::parse("host:abc").unwrap_err();
assert!(matches!(e, McError::Config(ConfigError::InvalidPort(_))));
}
#[test]
fn socks5_kind_is_socks5() {
let cfg = ProxyConfig::socks5("127.0.0.1:1080");
assert_eq!(cfg.kind(), ProxyKind::Socks5);
}
#[test]
fn socks5_udp_support_is_no_by_default() {
let cfg = ProxyConfig::socks5("127.0.0.1:1080");
assert_eq!(cfg.udp_support(), UdpSupport::No);
}
#[test]
fn socks5_auth_is_none_by_default() {
let cfg = ProxyConfig::socks5("127.0.0.1:1080");
assert!(cfg.auth().is_none());
}
#[test]
fn socks5_addr_parsed_correctly() {
let cfg = ProxyConfig::socks5("proxy.example.com:1080");
assert_eq!(cfg.addr().host, "proxy.example.com");
assert_eq!(cfg.addr().port, 1080);
}
#[test]
fn socks5_with_udp_kind_is_socks5() {
let cfg = ProxyConfig::socks5_with_udp("127.0.0.1:1080");
assert_eq!(cfg.kind(), ProxyKind::Socks5);
}
#[test]
fn socks5_with_udp_udp_support_is_yes() {
let cfg = ProxyConfig::socks5_with_udp("127.0.0.1:1080");
assert_eq!(cfg.udp_support(), UdpSupport::Yes);
}
#[test]
fn socks5_with_udp_addr_parsed() {
let cfg = ProxyConfig::socks5_with_udp("10.0.0.1:9050");
assert_eq!(cfg.addr().port, 9050);
}
#[test]
fn http_kind_is_http() {
let cfg = ProxyConfig::http("squid.example.com:3128");
assert_eq!(cfg.kind(), ProxyKind::Http);
}
#[test]
fn http_udp_support_is_no() {
let cfg = ProxyConfig::http("squid.example.com:3128");
assert_eq!(cfg.udp_support(), UdpSupport::No,
"HTTP CONNECT proxies cannot support UDP");
}
#[test]
fn http_auth_is_none_by_default() {
let cfg = ProxyConfig::http("squid.example.com:3128");
assert!(cfg.auth().is_none());
}
#[test]
fn http_addr_parsed_correctly() {
let cfg = ProxyConfig::http("corporate-proxy.example.com:8080");
assert_eq!(cfg.addr().host, "corporate-proxy.example.com");
assert_eq!(cfg.addr().port, 8080);
}
#[test]
fn socks5_with_auth_stores_credentials() {
let cfg = ProxyConfig::socks5("127.0.0.1:1080")
.with_auth("alice", "s3cr3t");
let auth = cfg.auth().expect("auth should be present");
assert_eq!(auth.username, "alice");
assert_eq!(auth.password, "s3cr3t");
}
#[test]
fn http_with_auth_stores_credentials() {
let cfg = ProxyConfig::http("proxy:3128")
.with_auth("bob", "hunter2");
let auth = cfg.auth().expect("auth should be present");
assert_eq!(auth.username, "bob");
assert_eq!(auth.password, "hunter2");
}
#[test]
fn with_auth_does_not_change_kind() {
let cfg = ProxyConfig::socks5("127.0.0.1:1080")
.with_auth("user", "pass");
assert_eq!(cfg.kind(), ProxyKind::Socks5);
}
#[test]
fn with_auth_does_not_change_udp_support() {
let cfg = ProxyConfig::socks5_with_udp("127.0.0.1:1080")
.with_auth("user", "pass");
assert_eq!(cfg.udp_support(), UdpSupport::Yes);
}
#[test]
fn auth_password_hidden_in_debug_output() {
let cfg = ProxyConfig::socks5("127.0.0.1:1080")
.with_auth("alice", "supersecret");
let debug = format!("{:?}", cfg.auth().unwrap());
assert!(!debug.contains("supersecret"),
"password must not appear in Debug output: {debug}");
assert!(debug.contains("***"),
"password should be masked as ***: {debug}");
}
#[test]
fn proxy_kind_socks5_not_equal_to_http() {
assert_ne!(ProxyKind::Socks5, ProxyKind::Http);
}
#[test]
fn proxy_kind_copy() {
let k = ProxyKind::Socks5;
let k2 = k; assert_eq!(k, k2);
}
#[test]
fn udp_support_default_is_no() {
let default: UdpSupport = Default::default();
assert_eq!(default, UdpSupport::No);
}
#[test]
fn udp_support_yes_not_equal_no() {
assert_ne!(UdpSupport::Yes, UdpSupport::No);
}
#[tokio::test]
async fn bedrock_via_non_udp_socks5_returns_udp_unsupported() {
use rust_mc_status::{McClient, McError};
use rust_mc_status::error::ProxyError;
let client = McClient::builder()
.timeout(std::time::Duration::from_millis(100))
.proxy(ProxyConfig::socks5("127.0.0.1:1")) .build();
let err = client.bedrock("geo.hivebedrock.network")
.await
.expect_err("should fail with ProxyUdpUnsupported");
assert!(
matches!(err, McError::Proxy(ProxyError::UdpUnsupported(_))),
"expected ProxyUdpUnsupported, got {err:?}"
);
}
#[tokio::test]
async fn bedrock_via_http_proxy_returns_udp_unsupported() {
use rust_mc_status::{McClient, McError};
use rust_mc_status::error::ProxyError;
let client = McClient::builder()
.timeout(std::time::Duration::from_millis(100))
.proxy(ProxyConfig::http("127.0.0.1:1"))
.build();
let err = client.bedrock("geo.hivebedrock.network")
.await
.expect_err("HTTP proxy has no UDP");
assert!(
matches!(err, McError::Proxy(ProxyError::UdpUnsupported(_))),
"expected ProxyUdpUnsupported, got {err:?}"
);
}
#[tokio::test]
async fn bedrock_via_socks5_with_udp_does_not_return_udp_error() {
use rust_mc_status::{McClient, McError};
use rust_mc_status::error::ProxyError;
let client = McClient::builder()
.timeout(std::time::Duration::from_millis(100))
.proxy(ProxyConfig::socks5_with_udp("127.0.0.1:1"))
.build();
let err = client.bedrock("geo.hivebedrock.network")
.await
.expect_err("should fail (unreachable proxy)");
assert!(
!matches!(err, McError::Proxy(ProxyError::UdpUnsupported(_))),
"socks5_with_udp should NOT return UdpUnsupported, got {err:?}"
);
}
#[test]
fn clone_preserves_kind() {
let cfg = ProxyConfig::http("proxy:3128").with_auth("u", "p");
let cloned = cfg.clone();
assert_eq!(cloned.kind(), ProxyKind::Http);
assert_eq!(cloned.addr().port, 3128);
assert_eq!(cloned.auth().unwrap().username, "u");
}
}