#![cfg(all(windows, feature = "std"))]
use std::ffi::OsString;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use wtf_string::Wtf16String;
#[link(name = "kernel32")]
unsafe extern "system" {
fn lstrlenW(lpstring: *const u16) -> i32;
}
#[test]
fn os_str_roundtrip_is_lossless_including_unpaired_surrogates() {
let cases: Vec<OsString> = vec![
OsString::from(""),
OsString::from("simple"),
OsString::from("café 日本語 😀"),
OsString::from("interior\u{0}nul"),
OsString::from_wide(&[0x61, 0xD800, 0x62]), OsString::from_wide(&[0xDC00]), OsString::from_wide(&[0xD83D, 0xDE00, 0xDBFF]), OsString::from_wide(&[0x41, 0x00, 0xD800, 0x00, 0x42]), ];
for os in cases {
let wtf = Wtf16String::from_os_str(&os);
let expected: Vec<u16> = os.encode_wide().collect();
assert_eq!(wtf.as_units(), expected.as_slice(), "units for {os:?}");
assert_eq!(wtf.to_os_string(), os, "roundtrip {os:?}");
}
}
#[test]
fn bulk_roundtrip_is_lossless() {
let alphabet_a = [
0x41u16, 0x00, 0xD800, 0xDC00, 0x00E9, 0x65E5, 0xDFFF, 0xD83D,
];
let alphabet_b = [
0x42u16, 0x00, 0xDC00, 0xD800, 0xDE00, 0xFFFD, 0x07FF, 0xDBFF,
];
let alphabet_c = [0x43u16, 0xD800, 0x00, 0xDFFF, 0x001F, 0xD83D];
let mut count = 0usize;
for &a in &alphabet_a {
for &b in &alphabet_b {
for &c in &alphabet_c {
let wide = [a, b, c, a, b];
let os = OsString::from_wide(&wide);
let wtf = Wtf16String::from_os_str(&os);
assert_eq!(wtf.to_os_string(), os);
let expected: Vec<u16> = os.encode_wide().collect();
assert_eq!(wtf.as_units(), expected.as_slice());
count += 1;
}
}
}
assert!(count >= 256, "expected hundreds of cases, got {count}");
}
#[test]
fn real_wide_win32_call_fed_from_our_pointer() {
for s in ["", "a", "hello world", "café-日本語-😀"] {
let wtf = Wtf16String::from(OsString::from(s).as_os_str());
assert!(!wtf.has_interior_nul(), "{s:?}");
let len = unsafe { lstrlenW(wtf.as_terminated_ptr()) };
assert_eq!(len as usize, wtf.len(), "lstrlenW length for {s:?}");
}
}
#[test]
fn counted_pointer_matches_a_wide_apis_view() {
let os = OsString::from("mixed é 日 😀 text");
let wtf = Wtf16String::from_os_str(&os);
let via_ptr = unsafe { std::slice::from_raw_parts(wtf.as_ptr(), wtf.len()) };
let via_os: Vec<u16> = os.encode_wide().collect();
assert_eq!(via_ptr, via_os.as_slice());
}