use super::AdapterSnapshot;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum FetchError {
#[cfg(windows)]
#[error("Windows API error: {0}")]
WindowsApi(#[from] windows::core::Error),
#[error("Permission denied: {context}")]
PermissionDenied {
context: String,
},
#[error("Platform error: {message}")]
Platform {
message: String,
},
}
pub trait AddressFetcher: Send + Sync {
fn fetch(&self) -> Result<Vec<AdapterSnapshot>, FetchError>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::network::{AdapterKind, AdapterSnapshot};
use std::sync::Mutex;
struct MockFetcher {
results: Mutex<std::collections::VecDeque<Result<Vec<AdapterSnapshot>, FetchError>>>,
}
impl MockFetcher {
fn new(results: Vec<Result<Vec<AdapterSnapshot>, FetchError>>) -> Self {
Self {
results: Mutex::new(results.into()),
}
}
fn returning_snapshots(snapshots: Vec<Vec<AdapterSnapshot>>) -> Self {
Self::new(snapshots.into_iter().map(Ok).collect())
}
}
impl AddressFetcher for MockFetcher {
fn fetch(&self) -> Result<Vec<AdapterSnapshot>, FetchError> {
self.results
.lock()
.unwrap()
.pop_front()
.unwrap_or_else(|| Ok(vec![]))
}
}
#[test]
fn mock_fetcher_returns_predefined_snapshots() {
let snapshot = AdapterSnapshot::new(
"eth0",
AdapterKind::Ethernet,
vec!["192.168.1.1".parse().unwrap()],
vec![],
);
let fetcher = MockFetcher::returning_snapshots(vec![vec![snapshot.clone()]]);
let result = fetcher.fetch().unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0], snapshot);
}
#[test]
fn mock_fetcher_returns_different_results_on_each_call() {
let snapshot1 = AdapterSnapshot::new("eth0", AdapterKind::Ethernet, vec![], vec![]);
let snapshot2 = AdapterSnapshot::new("eth1", AdapterKind::Wireless, vec![], vec![]);
let fetcher = MockFetcher::returning_snapshots(vec![vec![snapshot1], vec![snapshot2]]);
let result1 = fetcher.fetch().unwrap();
let result2 = fetcher.fetch().unwrap();
assert_eq!(result1[0].name, "eth0");
assert_eq!(result2[0].name, "eth1");
}
#[test]
fn mock_fetcher_returns_empty_after_exhausting_results() {
let fetcher = MockFetcher::returning_snapshots(vec![vec![]]);
let _ = fetcher.fetch(); let result = fetcher.fetch().unwrap();
assert!(result.is_empty());
}
#[test]
fn mock_fetcher_can_return_errors() {
let fetcher = MockFetcher::new(vec![Err(FetchError::Platform {
message: "test error".to_string(),
})]);
let result = fetcher.fetch();
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("test error"));
}
#[test]
fn fetch_error_permission_denied_displays_context() {
let error = FetchError::PermissionDenied {
context: "elevated privileges required".to_string(),
};
assert!(error.to_string().contains("elevated privileges required"));
}
#[test]
fn fetch_error_platform_displays_message() {
let error = FetchError::Platform {
message: "unsupported operation".to_string(),
};
assert!(error.to_string().contains("unsupported operation"));
}
}