#[path = "../src/component_detection.rs"] mod component_detection; #[path = "../src/models.rs"] mod models; #[path = "../src/singbox_service.rs"] mod singbox_service; use component_detection::DetectedSingBox; use singbox_service::{ build_singbox_setup_status, ensure_safe_singbox_install_dir, parse_service_command_output, service_control_script, SingBoxServiceAction, }; use std::path::{Path, PathBuf}; #[cfg(windows)] use std::process::Command as ProcessCommand; #[test] fn setup_status_reports_missing_items_when_singbox_is_absent() { let status = build_singbox_setup_status(None); assert!(!status.ready); assert_eq!(status.missing_count, 3); assert_eq!(status.items[0].id, "sing-box-binary"); assert!(status.items[0].details.contains("SagerNet/sing-box")); assert_eq!(status.items[1].id, "winsw-wrapper"); assert!(status.items[1].details.contains("winsw/winsw")); assert_eq!(status.items[2].id, "windows-service"); } #[test] fn setup_status_reports_ready_when_binary_wrapper_and_service_exist() { let detected = detected_singbox(true, true, true); let status = build_singbox_setup_status(Some(&detected)); assert!(status.ready); assert_eq!(status.missing_count, 0); assert!(status.items.iter().all(|item| item.installed)); } #[test] fn parses_last_json_service_command_output_line() { let output = br#" noise {"success":true,"code":"started","serviceName":"ProxyWardenSingBox","status":"Running","processId":42} "#; let parsed = parse_service_command_output(output).expect("service json should parse"); assert!(parsed.success); assert_eq!(parsed.code, "started"); assert_eq!(parsed.service_name, Some("ProxyWardenSingBox".to_string())); assert_eq!(parsed.status, Some("Running".to_string())); assert_eq!(parsed.process_id, Some(42)); } #[test] fn safe_install_dir_allows_only_proxywarden_singbox_folder() { assert!( ensure_safe_singbox_install_dir(Path::new(r"C:\Program Files\ProxyWarden\sing-box")) .is_ok() ); assert!(ensure_safe_singbox_install_dir(Path::new(r"C:\Windows")).is_err()); assert!(ensure_safe_singbox_install_dir(Path::new(r"C:\Program Files\sing-box")).is_err()); } #[test] fn service_control_script_targets_named_service_and_action() { let script = service_control_script( SingBoxServiceAction::Start, "ProxyWardenSingBox", None, None, ); assert!(script.contains("$serviceName = 'ProxyWardenSingBox'")); assert!(script.contains("$action = 'start'")); assert!(script.contains("ConvertTo-Json -Compress")); } #[test] fn service_control_script_syncs_generated_config_before_start() { let source = Path::new(r"C:\ProgramData\ProxyWarden\generated\sing-box-config.json"); let target = Path::new(r"C:\Program Files\ProxyWarden\sing-box\config.json"); let script = service_control_script( SingBoxServiceAction::Start, "ProxyWardenSingBox", Some(source), Some(target), ); assert!(script.contains( "$configSource = 'C:\\ProgramData\\ProxyWarden\\generated\\sing-box-config.json'" )); assert!( script.contains("$configTarget = 'C:\\Program Files\\ProxyWarden\\sing-box\\config.json'") ); assert!(script.contains("Copy-Item -LiteralPath $configSource")); assert!(script.contains("'config_sync_failed'")); } #[test] #[cfg(windows)] fn install_singbox_script_parses_as_powershell() { let script_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("..") .join("scripts") .join("install-singbox.ps1"); let escaped_path = script_path.display().to_string().replace('\'', "''"); let parser = format!( "$tokens = $null; $errors = $null; [System.Management.Automation.Language.Parser]::ParseFile('{escaped_path}', [ref]$tokens, [ref]$errors) | Out-Null; if ($errors.Count -gt 0) {{ $errors | ForEach-Object {{ $_.Message }}; exit 1 }}" ); let output = ProcessCommand::new("powershell") .args(["-NoProfile", "-NonInteractive", "-Command", &parser]) .output() .expect("powershell parser should run"); assert!( output.status.success(), "install-singbox.ps1 should parse\nstdout:\n{}\nstderr:\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr), ); } fn detected_singbox(binary_exists: bool, wrapper_exists: bool, running: bool) -> DetectedSingBox { DetectedSingBox { install_dir: PathBuf::from(r"C:\Program Files\ProxyWarden\sing-box"), executable_path: PathBuf::from(r"C:\Program Files\ProxyWarden\sing-box\sing-box.exe"), wrapper_path: PathBuf::from( r"C:\Program Files\ProxyWarden\sing-box\ProxyWardenSingBox.exe", ), binary_exists, wrapper_exists, running, service_name: "ProxyWardenSingBox".to_string(), } }