From fe9f31616e574b9c3c4ae97b0b646de6e65705ce Mon Sep 17 00:00:00 2001 From: Razvan Dimescu Date: Thu, 16 Apr 2026 19:31:26 +0300 Subject: [PATCH] test: add SCM output parsing and config path regression tests Extract parse_sc_registered and parse_sc_state as testable pure functions. 8 new tests covering: service registration detection, service state parsing, and Windows config_dir == data_dir invariant. --- src/system_dns.rs | 95 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/src/system_dns.rs b/src/system_dns.rs index 7e2d16a..941c053 100644 --- a/src/system_dns.rs +++ b/src/system_dns.rs @@ -912,35 +912,43 @@ fn delete_service_scm() { #[cfg(windows)] fn is_service_registered() -> bool { run_sc(&["query", crate::windows_service::SERVICE_NAME]) - .map(|o| { - // sc query exits 0 if the service exists (running or stopped). - // Error 1060 = "service does not exist". - if o.status.success() { - return true; - } - let text = String::from_utf8_lossy(&o.stdout); - !text.contains("1060") - }) + .map(|o| parse_sc_registered(o.status.success(), &String::from_utf8_lossy(&o.stdout))) .unwrap_or(false) } +/// Parse `sc query` output to determine if a service is registered. +/// Extracted for testability — the actual `sc` call is in `is_service_registered`. +#[cfg(any(windows, test))] +fn parse_sc_registered(exit_success: bool, stdout: &str) -> bool { + if exit_success { + return true; + } + // Error 1060 = "The specified service does not exist as an installed service." + !stdout.contains("1060") +} + /// Print service state from SCM. #[cfg(windows)] fn service_status_windows() -> Result<(), String> { let out = run_sc(&["query", crate::windows_service::SERVICE_NAME])?; let text = String::from_utf8_lossy(&out.stdout); - if text.contains("1060") { - eprintln!(" Service is not installed.\n"); - return Ok(()); + let display = parse_sc_state(&text); + eprintln!(" {}\n", display); + Ok(()) +} + +/// Parse the STATE line from `sc query` output. Returns a human-readable +/// string like "STATE : 4 RUNNING" or "Service is not installed." +#[cfg(any(windows, test))] +fn parse_sc_state(sc_output: &str) -> String { + if sc_output.contains("1060") { + return "Service is not installed.".to_string(); } - // Parse STATE line, e.g. "STATE : 4 RUNNING" - let state = text + sc_output .lines() .find(|l| l.contains("STATE")) .map(|l| l.trim().to_string()) - .unwrap_or_else(|| "unknown".to_string()); - eprintln!(" {}\n", state); - Ok(()) + .unwrap_or_else(|| "unknown".to_string()) } #[cfg(windows)] @@ -2132,4 +2140,57 @@ Wireless LAN adapter Wi-Fi: let err = std::io::Error::from(std::io::ErrorKind::AddrInUse); assert!(try_port53_advisory("not-an-address", &err).is_none()); } + + #[test] + fn sc_query_running_service_is_registered() { + assert!(parse_sc_registered(true, "")); + } + + #[test] + fn sc_query_stopped_service_is_registered() { + let output = "SERVICE_NAME: Numa\n TYPE: 10 WIN32_OWN\n STATE: 1 STOPPED\n"; + assert!(parse_sc_registered(true, output)); + } + + #[test] + fn sc_query_missing_service_not_registered() { + let output = "[SC] EnumQueryServicesStatus:OpenService FAILED 1060:\n\nThe specified service does not exist as an installed service.\n"; + assert!(!parse_sc_registered(false, output)); + } + + #[test] + fn sc_query_other_error_assumes_registered() { + // Permission denied or other errors — don't assume unregistered. + let output = "[SC] OpenService FAILED 5:\n\nAccess is denied.\n"; + assert!(parse_sc_registered(false, output)); + } + + #[test] + fn parse_sc_state_running() { + let output = "SERVICE_NAME: Numa\n TYPE : 10 WIN32_OWN_PROCESS\n STATE : 4 RUNNING\n WIN32_EXIT_CODE : 0\n"; + assert!(parse_sc_state(output).contains("RUNNING")); + } + + #[test] + fn parse_sc_state_stopped() { + let output = "SERVICE_NAME: Numa\n TYPE : 10 WIN32_OWN_PROCESS\n STATE : 1 STOPPED\n"; + assert!(parse_sc_state(output).contains("STOPPED")); + } + + #[test] + fn parse_sc_state_not_installed() { + let output = "[SC] EnumQueryServicesStatus:OpenService FAILED 1060:\n\n"; + assert_eq!(parse_sc_state(output), "Service is not installed."); + } + + #[test] + fn parse_sc_state_empty_output() { + assert_eq!(parse_sc_state(""), "unknown"); + } + + #[cfg(windows)] + #[test] + fn windows_config_dir_equals_data_dir() { + assert_eq!(crate::config_dir(), crate::data_dir()); + } }