1//! These Windows-only tests are ported from the Unix-only tests in
2//! tests/utf16.rs. The tests that use StrictUtf8 mode are omitted here,
3//! because that's a Unix-only feature.
4
5#![cfg(windows)]
6
7use clap::{arg, value_parser, Command};
8use std::ffi::OsString;
9use std::os::windows::ffi::OsStringExt;
10
11// Take a slice of ASCII bytes, convert them to UTF-16, and then append a
12// dangling surrogate character to make the result invalid UTF-16.
13fn bad_osstring(ascii: &[u8]) -> OsString {
14    let mut wide_chars: Vec<u16> = ascii.iter().map(|&c| c as u16).collect();
15    // UTF-16 surrogate characters are only valid in pairs.
16    let surrogate_char: u16 = 0xDC00;
17    wide_chars.push(surrogate_char);
18    let os = OsString::from_wide(&wide_chars);
19    assert!(os.to_str().is_none(), "invalid Unicode");
20    os
21}
22
23#[test]
24fn invalid_utf16_positional() {
25    let r = Command::new("bad_utf16")
26        .arg(arg!(<arg> "some arg").value_parser(value_parser!(OsString)))
27        .try_get_matches_from(vec![OsString::from(""), bad_osstring(b"")]);
28    assert!(r.is_ok(), "{}", r.unwrap_err());
29    let m = r.unwrap();
30    assert!(m.contains_id("arg"));
31    assert_eq!(&*m.get_one::<OsString>("arg").unwrap(), &*bad_osstring(b""));
32}
33
34#[test]
35fn invalid_utf16_option_short_space() {
36    let r = Command::new("bad_utf16")
37        .arg(arg!(-a --arg <arg> "some arg").value_parser(value_parser!(OsString)))
38        .try_get_matches_from(vec![
39            OsString::from(""),
40            OsString::from("-a"),
41            bad_osstring(b""),
42        ]);
43    assert!(r.is_ok(), "{}", r.unwrap_err());
44    let m = r.unwrap();
45    assert!(m.contains_id("arg"));
46    assert_eq!(&*m.get_one::<OsString>("arg").unwrap(), &*bad_osstring(b""));
47}
48
49#[test]
50fn invalid_utf16_option_short_equals() {
51    let r = Command::new("bad_utf16")
52        .arg(arg!(-a --arg <arg> "some arg").value_parser(value_parser!(OsString)))
53        .try_get_matches_from(vec![OsString::from(""), bad_osstring(b"-a=")]);
54    assert!(r.is_ok(), "{}", r.unwrap_err());
55    let m = r.unwrap();
56    assert!(m.contains_id("arg"));
57    assert_eq!(&*m.get_one::<OsString>("arg").unwrap(), &*bad_osstring(b""));
58}
59
60#[test]
61fn invalid_utf16_option_short_no_space() {
62    let r = Command::new("bad_utf16")
63        .arg(arg!(-a --arg <arg> "some arg").value_parser(value_parser!(OsString)))
64        .try_get_matches_from(vec![OsString::from(""), bad_osstring(b"-a")]);
65    assert!(r.is_ok(), "{}", r.unwrap_err());
66    let m = r.unwrap();
67    assert!(m.contains_id("arg"));
68    assert_eq!(&*m.get_one::<OsString>("arg").unwrap(), &*bad_osstring(b""));
69}
70
71#[test]
72fn invalid_utf16_option_long_space() {
73    let r = Command::new("bad_utf16")
74        .arg(arg!(-a --arg <arg> "some arg").value_parser(value_parser!(OsString)))
75        .try_get_matches_from(vec![
76            OsString::from(""),
77            OsString::from("--arg"),
78            bad_osstring(b""),
79        ]);
80    assert!(r.is_ok(), "{}", r.unwrap_err());
81    let m = r.unwrap();
82    assert!(m.contains_id("arg"));
83    assert_eq!(&*m.get_one::<OsString>("arg").unwrap(), &*bad_osstring(b""));
84}
85
86#[test]
87fn invalid_utf16_option_long_equals() {
88    let r = Command::new("bad_utf16")
89        .arg(arg!(-a --arg <arg> "some arg").value_parser(value_parser!(OsString)))
90        .try_get_matches_from(vec![OsString::from(""), bad_osstring(b"--arg=")]);
91    assert!(r.is_ok(), "{}", r.unwrap_err());
92    let m = r.unwrap();
93    assert!(m.contains_id("arg"));
94    assert_eq!(&*m.get_one::<OsString>("arg").unwrap(), &*bad_osstring(b""));
95}
96