use clap::Parser;
use lanflare_cli::{Cli, Commands};
use lanflare_core::config::AppConfig;
use lanflare_core::crypto::cert::generate_self_signed;
#[test]
fn test_cli_parsing_status() {
let cli = Cli::try_parse_from(["lanflare", "status"]).expect("parse status");
assert!(matches!(cli.command, Some(Commands::Status)));
}
#[test]
fn test_cli_parsing_scan() {
let cli = Cli::try_parse_from(["lanflare", "scan", "--duration", "5", "--no-mdns", "-s"])
.expect("parse scan");
match cli.command {
Some(Commands::Scan(args)) => {
assert_eq!(args.duration, 5);
assert!(!args.no_multicast);
assert!(args.no_mdns);
assert!(args.subnet);
assert!(!args.no_subnet);
}
_ => panic!("expected Scan command"),
}
}
#[test]
fn test_cli_parsing_send() {
let cli = Cli::try_parse_from(["lanflare", "send", "file1.txt", "file2.pdf", "-t", "192.168.1.5", "--pin", "1234"])
.expect("parse send");
match cli.command {
Some(Commands::Send(args)) => {
assert_eq!(args.files.len(), 2);
assert_eq!(args.to.as_deref(), Some("192.168.1.5"));
assert_eq!(args.pin.as_deref(), Some("1234"));
}
_ => panic!("expected Send command"),
}
}
#[test]
fn test_cli_parsing_receive() {
let cli = Cli::try_parse_from(["lanflare", "receive", "-d", "/tmp/downloads", "-p", "53318", "--auto-accept", "--pin", "9999"])
.expect("parse receive");
match cli.command {
Some(Commands::Receive(args)) => {
assert_eq!(args.dir.unwrap().to_str(), Some("/tmp/downloads"));
assert_eq!(args.port, Some(53318));
assert!(args.auto_accept);
assert_eq!(args.pin.as_deref(), Some("9999"));
}
_ => panic!("expected Receive command"),
}
}
#[tokio::test]
async fn test_cli_status_handler() {
let config = AppConfig::default();
let identity = generate_self_signed().expect("generate identity");
let result = lanflare_cli::commands::status(&config, &identity).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_cli_send_handler_file_not_found() {
let config = AppConfig::default();
let identity = generate_self_signed().expect("generate identity");
let send_opts = lanflare_cli::commands::SendOptions {
files: vec!["/nonexistent/path/to/random_file.bin".into()],
to: Some("192.168.1.20".to_string()),
pin: None,
};
let result = lanflare_cli::commands::send(&config, &identity, &send_opts).await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("File not found"));
}
#[test]
fn test_match_target_peer() {
use lanflare_core::discovery::registry::{DiscoveredPeer, PeerEndpoint};
use lanflare_core::discovery::DiscoverySource;
use lanflare_proto::discovery::{DeviceType, ProtocolType};
use std::collections::{HashMap, HashSet};
use std::net::{IpAddr, Ipv4Addr};
let mut sources = HashSet::new();
sources.insert(DiscoverySource::Multicast);
let p1 = DiscoveredPeer {
fingerprint: "AAAA1111BBBB2222CCCC3333DDDD4444EEEE5555FFFF66667777888899990000".to_string(),
alias: "Bob's Workstation".to_string(),
version: "2.0".to_string(),
device_model: Some("Linux".to_string()),
device_type: Some(DeviceType::Desktop),
port: 53317,
protocol: ProtocolType::Https,
download: false,
endpoints: vec![PeerEndpoint {
ip: IpAddr::V4(Ipv4Addr::new(192, 168, 1, 50)),
scope_id: None,
sources: sources.clone(),
first_seen_ms: 1000,
last_seen_ms: 1000,
}],
discovery_sources: sources.clone(),
first_seen_ms: 1000,
last_seen_ms: 1000,
metadata: HashMap::new(),
};
let p2 = DiscoveredPeer {
fingerprint: "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF".to_string(),
alias: "Alice's Phone".to_string(),
version: "2.0".to_string(),
device_model: Some("Pixel 8".to_string()),
device_type: Some(DeviceType::Mobile),
port: 53318,
protocol: ProtocolType::Https,
download: false,
endpoints: vec![PeerEndpoint {
ip: IpAddr::V4(Ipv4Addr::new(192, 168, 1, 99)),
scope_id: None,
sources: sources.clone(),
first_seen_ms: 1000,
last_seen_ms: 1000,
}],
discovery_sources: sources,
first_seen_ms: 1000,
last_seen_ms: 1000,
metadata: HashMap::new(),
};
let peers = vec![p1, p2];
assert_eq!(lanflare_cli::commands::match_target_peer("Bob's Workstation", &peers).unwrap().alias, "Bob's Workstation");
assert_eq!(lanflare_cli::commands::match_target_peer("phone", &peers).unwrap().alias, "Alice's Phone");
assert_eq!(lanflare_cli::commands::match_target_peer("192.168.1.50", &peers).unwrap().alias, "Bob's Workstation");
assert_eq!(lanflare_cli::commands::match_target_peer("12345678", &peers).unwrap().alias, "Alice's Phone");
assert!(lanflare_cli::commands::match_target_peer("Nonexistent", &peers).is_none());
assert!(lanflare_cli::commands::match_target_peer("", &peers).is_none());
}
#[tokio::test]
async fn test_cli_transfer_orchestration_e2e() {
use std::time::Duration;
use tokio::sync::mpsc;
use uuid::Uuid;
use lanflare_core::client::transfer::{OutgoingFile, TransferOptions, TransferOrchestrator};
use lanflare_core::client::{LsClient, LsClientConfig};
use lanflare_core::discovery::registry::PeerRegistry;
use lanflare_core::server::start_server;
use lanflare_proto::discovery::{DeviceType, ProtocolType, RegisterDtoV2};
let temp_rx_dir = std::env::temp_dir().join(format!("cli_rx_{}", Uuid::new_v4()));
let temp_tx_dir = std::env::temp_dir().join(format!("cli_tx_{}", Uuid::new_v4()));
tokio::fs::create_dir_all(&temp_rx_dir).await.unwrap();
tokio::fs::create_dir_all(&temp_tx_dir).await.unwrap();
let test_file = temp_tx_dir.join("payload.txt");
tokio::fs::write(&test_file, b"LanFlare CLI transfer verified!").await.unwrap();
let outgoing = OutgoingFile::from_path(&test_file)
.await
.unwrap()
.with_computed_sha256()
.await
.unwrap();
let rx_identity = generate_self_signed().unwrap();
let rx_config = AppConfig {
alias: "CLI Receiver".to_string(),
port: 0,
download_dir: temp_rx_dir.clone(),
auto_accept: true,
pin: None,
};
let registry = PeerRegistry::new();
let (ev_tx, _ev_rx) = mpsc::channel(100);
let server_handle = start_server(rx_config, Some(rx_identity.clone()), registry, Some(ev_tx))
.await
.unwrap();
let bound_port = server_handle.bound_port();
let base_url = format!("https://127.0.0.1:{bound_port}");
let tx_identity = generate_self_signed().unwrap();
let client_config = LsClientConfig {
timeout: Duration::from_secs(10),
connect_timeout: Duration::from_secs(3),
tls_identity: Some(tx_identity.clone()),
target_fingerprint: Some(rx_identity.fingerprint.clone()),
};
let client = LsClient::new(client_config).unwrap();
let sender_info = RegisterDtoV2 {
alias: "CLI Sender".to_string(),
version: "2.0".to_string(),
device_model: Some("CLI Test".to_string()),
device_type: Some(DeviceType::Desktop),
fingerprint: tx_identity.fingerprint.clone(),
port: 53317,
protocol: ProtocolType::Https,
download: false,
};
let orchestrator = TransferOrchestrator::new(client, sender_info);
let (progress_tx, mut progress_rx) = mpsc::channel(100);
let mut tracker = lanflare_cli::tui::TransferProgressTracker::new(false);
let transfer_task = tokio::spawn(async move {
orchestrator
.transfer(
&base_url,
vec![outgoing],
TransferOptions::default(),
Some(progress_tx),
)
.await
});
while let Some(ev) = progress_rx.recv().await {
tracker.handle_event(&ev);
}
transfer_task.await.unwrap().unwrap();
let received_path = temp_rx_dir.join("payload.txt");
assert!(received_path.exists());
let content = tokio::fs::read(&received_path).await.unwrap();
assert_eq!(content, b"LanFlare CLI transfer verified!");
server_handle.stop();
}