use super::windows::{
WindowsFetcher, classify_adapter, is_hardware_interface, map_if_type_fallback,
};
use crate::network::{AdapterKind, AddressFetcher};
use std::net::{Ipv4Addr, Ipv6Addr};
use windows::Win32::NetworkManagement::IpHelper::{
IF_TYPE_ETHERNET_CSMACD, IF_TYPE_IEEE80211, IF_TYPE_SOFTWARE_LOOPBACK,
};
const IF_TYPE_PPP: u32 = 23;
const IF_TYPE_TUNNEL: u32 = 131;
mod map_if_type_fallback_tests {
use super::*;
#[test]
fn ethernet() {
assert_eq!(
map_if_type_fallback(IF_TYPE_ETHERNET_CSMACD),
AdapterKind::Ethernet
);
}
#[test]
fn wireless() {
assert_eq!(
map_if_type_fallback(IF_TYPE_IEEE80211),
AdapterKind::Wireless
);
}
#[test]
fn loopback() {
assert_eq!(
map_if_type_fallback(IF_TYPE_SOFTWARE_LOOPBACK),
AdapterKind::Loopback
);
}
#[test]
fn tunnel_is_virtual() {
assert_eq!(map_if_type_fallback(IF_TYPE_TUNNEL), AdapterKind::Virtual);
}
#[test]
fn ppp_is_virtual() {
assert_eq!(map_if_type_fallback(IF_TYPE_PPP), AdapterKind::Virtual);
}
#[test]
fn unknown_preserves_code() {
assert_eq!(map_if_type_fallback(999), AdapterKind::Other(999));
}
}
mod classify_adapter_tests {
use super::*;
const INVALID_IF_INDEX: u32 = 0;
#[test]
fn tunnel_always_virtual_regardless_of_index() {
assert_eq!(
classify_adapter(IF_TYPE_TUNNEL, INVALID_IF_INDEX),
AdapterKind::Virtual
);
}
#[test]
fn ppp_always_virtual_regardless_of_index() {
assert_eq!(
classify_adapter(IF_TYPE_PPP, INVALID_IF_INDEX),
AdapterKind::Virtual
);
}
#[test]
fn loopback_always_loopback_regardless_of_index() {
assert_eq!(
classify_adapter(IF_TYPE_SOFTWARE_LOOPBACK, INVALID_IF_INDEX),
AdapterKind::Loopback
);
}
#[test]
fn unknown_type_preserves_code() {
assert_eq!(
classify_adapter(999, INVALID_IF_INDEX),
AdapterKind::Other(999)
);
}
}
mod is_hardware_interface_tests {
use super::*;
#[test]
fn invalid_index_returns_none() {
assert!(is_hardware_interface(0).is_none());
}
#[test]
fn very_large_index_returns_none() {
assert!(is_hardware_interface(u32::MAX).is_none());
}
}
mod windows_fetcher_tests {
use super::*;
#[test]
fn new_creates_instance() {
let _fetcher = WindowsFetcher::new();
}
#[test]
fn default_creates_instance() {
let _fetcher = WindowsFetcher::default();
}
}
mod integration_tests {
use super::*;
#[test]
fn fetch_adapters_returns_at_least_loopback() {
let fetcher = WindowsFetcher::new();
let result = fetcher.fetch();
assert!(result.is_ok(), "fetch() failed: {:?}", result.err());
let adapters = result.unwrap();
let has_loopback_addr = adapters.iter().any(|a| {
a.ipv4_addresses.contains(&Ipv4Addr::LOCALHOST)
|| a.ipv6_addresses.contains(&Ipv6Addr::LOCALHOST)
});
assert!(
has_loopback_addr,
"Expected at least loopback address, got adapters: {adapters:?}"
);
}
#[test]
fn fetch_adapters_names_are_not_empty() {
let fetcher = WindowsFetcher::new();
let adapters = fetcher.fetch().expect("fetch() failed");
for adapter in &adapters {
assert!(
!adapter.name.is_empty(),
"Adapter name should not be empty: {adapter:?}"
);
}
}
#[test]
fn loopback_adapter_has_loopback_kind() {
let fetcher = WindowsFetcher::new();
let adapters = fetcher.fetch().expect("fetch() failed");
let loopback = adapters.iter().find(|a| {
a.ipv4_addresses.contains(&Ipv4Addr::LOCALHOST)
|| a.ipv6_addresses.contains(&Ipv6Addr::LOCALHOST)
});
assert!(loopback.is_some(), "No loopback adapter found");
assert_eq!(
loopback.unwrap().kind,
AdapterKind::Loopback,
"Loopback adapter should have Loopback kind"
);
}
#[test]
fn virtual_adapters_are_not_ethernet_or_wireless() {
let fetcher = WindowsFetcher::new();
let adapters = fetcher.fetch().expect("fetch() failed");
for adapter in &adapters {
let name_lower = adapter.name.to_lowercase();
let is_likely_virtual =
name_lower.contains("vethernet") || adapter.name.starts_with("本地连接*");
if is_likely_virtual {
assert!(
adapter.kind == AdapterKind::Virtual,
"Adapter '{}' looks like a virtual adapter but is classified as {:?}",
adapter.name,
adapter.kind
);
}
}
}
}