diff --git a/Cargo.toml b/Cargo.toml index 9d981e9..ac031f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ libc = "0.2" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["libloaderapi", "processthreadsapi", "sysinfoapi", "winbase", "winver"] } + +[dev-dependencies] +regex = "1" diff --git a/src/windows.rs b/src/windows.rs index 182272b..83e4b48 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -26,6 +26,7 @@ use self::winapi::um::winnt::*; use self::winapi::um::winver::*; use super::Uname; use std::borrow::Cow; +use std::convert::TryFrom; use std::ffi::{CStr, OsStr, OsString}; use std::io; use std::iter; @@ -105,7 +106,9 @@ impl PlatformInfo { let mut data: Vec = vec![0; size as usize]; unsafe { if GetComputerNameExW(ComputerNameDnsHostname, data.as_mut_ptr(), &mut size) != 0 { - Ok(String::from_utf16_lossy(&data)) + Ok(String::from_utf16_lossy( + &data[..usize::try_from(size).unwrap()], + )) } else { // XXX: should this error or just return localhost? Err(io::Error::last_os_error()) @@ -424,6 +427,15 @@ fn test_sysname() { assert_eq!(info.sysname(), expected); } +#[test] +#[allow(non_snake_case)] +fn test_nodename_no_trailing_NUL() { + let info = PlatformInfo::new().unwrap(); + let nodename = info.nodename(); + let trimmed = nodename.trim().trim_end_matches(|c| c == '\0'); + assert_eq!(nodename, trimmed); +} + #[test] fn test_machine() { let is_wow64 = is_wow64(); diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 6b97238..71e1b08 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -1,18 +1,26 @@ +// spell-checker:ignore (API) nodename osname sysname + +use regex; + use platform_info::*; #[test] fn platform() -> Result<(), String> { - let uname = match PlatformInfo::new() { - Ok(info) => info, - Err(error) => panic!("{}", error), - }; - - println!("sysname = '{}'", uname.sysname()); - println!("nodename = '{}'", uname.nodename()); - println!("release = '{}'", uname.release()); - println!("version = '{}'", uname.version()); - println!("machine = '{}'", uname.machine()); - println!("osname = '{}'", uname.osname()); + let uname = PlatformInfo::new().unwrap(); + + let sysname = uname.sysname(); + let nodename = uname.nodename(); + let release = uname.release(); + let version = uname.version(); + let machine = uname.machine(); + let osname = uname.osname(); + + println!("sysname = [{}]'{}'", sysname.len(), sysname); + println!("nodename = [{}]'{}'", nodename.len(), nodename); + println!("release = [{}]'{}'", release.len(), release); + println!("version = [{}]'{}'", version.len(), version); + println!("machine = [{}]'{}'", machine.len(), machine); + println!("osname = [{}]'{}'", osname.len(), osname); assert!(!uname.sysname().is_empty()); assert!(!uname.nodename().is_empty()); @@ -23,3 +31,24 @@ fn platform() -> Result<(), String> { Ok(()) } + +#[test] +fn platform_no_invisible_contents() -> Result<(), String> { + let uname = PlatformInfo::new().unwrap(); + + let sysname = uname.sysname(); + let nodename = uname.nodename(); + let release = uname.release(); + let version = uname.version(); + let machine = uname.machine(); + let osname = uname.osname(); + + let s = format!("sysname='{sysname}';nodename='{nodename}';release='{release}';version='{version}';machine='{machine}';osname={osname}"); + println!("s = [{}]\"{}\"", s.len(), s); + + // let re = regex::Regex::new("[^[[:print:]]]").unwrap(); // matches invisible (and emojis) + let re = regex::Regex::new("[^[[:print:]]\\p{Other_Symbol}]").unwrap(); // matches invisible only (not emojis) + assert_eq!(re.find(&s), None); + + Ok(()) +}