//! Unit tests for native Linux WireGuard conversion utilities and error invariants. //! //! These tests verify CIDR parsing, endpoint parsing, key decoding, and peer //! filtering without requiring CAP_NET_ADMIN or kernel mutation. use base64::Engine as _; use nx9_wg_core::types::wireguard::PeerState; use nx9_wireguard::WireGuardError; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; #[test] fn test_ipv4_cidr_parsing() { let net: ipnet::IpNet = "10.0.0.2/32".parse().unwrap(); assert_eq!(net.addr(), IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2))); assert_eq!(net.prefix_len(), 32); } #[test] fn test_ipv6_cidr_parsing() { let net: ipnet::IpNet = "fd00::2/128".parse().unwrap(); assert!(net.addr().is_ipv6()); assert_eq!(net.prefix_len(), 128); } #[test] fn test_multiple_allowed_ips_parsing() { let csv = "10.0.0.2/32, fd00::2/128"; let nets: Vec = csv .split(',') .map(|s| s.trim()) .filter(|s| !s.is_empty()) .map(|s| s.parse::().unwrap()) .collect(); assert_eq!(nets.len(), 2); assert!(nets[0].addr().is_ipv4()); assert!(nets[1].addr().is_ipv6()); } #[test] fn test_empty_allowed_ips() { let csv = ""; let nets: Vec = csv .split(',') .map(|s| s.trim()) .filter(|s| !s.is_empty()) .filter_map(|s| s.parse::().ok()) .collect(); assert!(nets.is_empty()); } #[test] fn test_invalid_cidr_rejected() { let result = "invalid/cidr".parse::(); assert!(result.is_err()); } #[test] fn test_ipv4_endpoint_parsing() { let addr: SocketAddr = "198.51.100.2:45000".parse().unwrap(); assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(198, 51, 100, 2))); assert_eq!(addr.port(), 45000); } #[test] fn test_ipv6_endpoint_parsing() { let addr: SocketAddr = "[2001:db8::1]:51820".parse().unwrap(); assert!(addr.ip().is_ipv6()); assert_eq!(addr.port(), 51820); } #[test] fn test_invalid_endpoint_rejected() { let result = "not-an-endpoint".parse::(); assert!(result.is_err()); } #[test] fn test_base64_key_decode_valid() { let key_bytes = [0xAAu8; 32]; let b64 = base64::engine::general_purpose::STANDARD.encode(key_bytes); let decoded = base64::engine::general_purpose::STANDARD .decode(&b64) .unwrap(); assert_eq!(decoded.len(), 32); let mut arr = [0u8; 32]; arr.copy_from_slice(&decoded); assert_eq!(arr, key_bytes); } #[test] fn test_base64_key_decode_wrong_length() { let short_key = [0xBBu8; 16]; let b64 = base64::engine::general_purpose::STANDARD.encode(short_key); let decoded = base64::engine::general_purpose::STANDARD .decode(&b64) .unwrap(); assert_ne!(decoded.len(), 32); } #[test] fn test_base64_key_decode_invalid_base64() { let result = base64::engine::general_purpose::STANDARD.decode("not!valid!base64!!!"); assert!(result.is_err()); } #[test] fn test_peer_state_filtering() { let states = [ PeerState::Active, PeerState::Disabled, PeerState::Revoked, PeerState::Expired, ]; let active_count = states.iter().filter(|s| **s == PeerState::Active).count(); assert_eq!(active_count, 1, "only Active peers should be synchronized"); } #[test] fn test_error_display_no_key_leakage() { let err = WireGuardError::Key("invalid base64".to_string()); let display = format!("{err}"); assert!(!display.contains("secret")); assert!(!display.contains("private")); assert!(display.contains("invalid base64")); } #[test] fn test_error_variants_exist() { let _ = format!("{}", WireGuardError::InterfaceNotFound("wg0".into())); let _ = format!("{}", WireGuardError::WrongInterfaceType("eth0".into())); let _ = format!("{}", WireGuardError::Unsupported("no kernel module".into())); let _ = format!("{}", WireGuardError::InvalidEndpoint("bad:ep".into())); let _ = format!("{}", WireGuardError::InvalidAllowedIp("bad/cidr".into())); } #[test] fn test_prefix_length_preservation() { let cases = [ ("10.0.0.0/8", 8), ("10.0.0.0/16", 16), ("10.0.0.0/24", 24), ("10.0.0.1/32", 32), ("fd00::/64", 64), ("fd00::1/128", 128), ("0.0.0.0/0", 0), ("::/0", 0), ]; for (cidr, expected_prefix) in cases { let net: ipnet::IpNet = cidr.parse().unwrap(); assert_eq!( net.prefix_len(), expected_prefix, "prefix mismatch for {cidr}" ); } }