1#![cfg(not(windows))]
2
3use clap::{arg, error::ErrorKind, value_parser, Arg, ArgAction, Command};
4use std::ffi::OsString;
5use std::os::unix::ffi::OsStringExt;
6
7#[test]
8fn invalid_utf8_strict_positional() {
9    let m = Command::new("bad_utf8")
10        .arg(Arg::new("arg"))
11        .try_get_matches_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
12    assert!(m.is_err());
13    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
14}
15
16#[test]
17fn invalid_utf8_strict_option_short_space() {
18    let m = Command::new("bad_utf8")
19        .arg(
20            Arg::new("arg")
21                .short('a')
22                .long("arg")
23                .action(ArgAction::Set),
24        )
25        .try_get_matches_from(vec![
26            OsString::from(""),
27            OsString::from("-a"),
28            OsString::from_vec(vec![0xe9]),
29        ]);
30    assert!(m.is_err());
31    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
32}
33
34#[test]
35fn invalid_utf8_strict_option_short_equals() {
36    let m = Command::new("bad_utf8")
37        .arg(
38            Arg::new("arg")
39                .short('a')
40                .long("arg")
41                .action(ArgAction::Set),
42        )
43        .try_get_matches_from(vec![
44            OsString::from(""),
45            OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
46        ]);
47    assert!(m.is_err());
48    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
49}
50
51#[test]
52fn invalid_utf8_strict_option_short_no_space() {
53    let m = Command::new("bad_utf8")
54        .arg(
55            Arg::new("arg")
56                .short('a')
57                .long("arg")
58                .action(ArgAction::Set),
59        )
60        .try_get_matches_from(vec![
61            OsString::from(""),
62            OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
63        ]);
64    assert!(m.is_err());
65    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
66}
67
68#[test]
69fn invalid_utf8_strict_option_long_space() {
70    let m = Command::new("bad_utf8")
71        .arg(
72            Arg::new("arg")
73                .short('a')
74                .long("arg")
75                .action(ArgAction::Set),
76        )
77        .try_get_matches_from(vec![
78            OsString::from(""),
79            OsString::from("--arg"),
80            OsString::from_vec(vec![0xe9]),
81        ]);
82    assert!(m.is_err());
83    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
84}
85
86#[test]
87fn invalid_utf8_strict_option_long_equals() {
88    let m = Command::new("bad_utf8")
89        .arg(
90            Arg::new("arg")
91                .short('a')
92                .long("arg")
93                .action(ArgAction::Set),
94        )
95        .try_get_matches_from(vec![
96            OsString::from(""),
97            OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
98        ]);
99    assert!(m.is_err());
100    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
101}
102
103#[test]
104fn invalid_utf8_strict_invalid_short() {
105    let m = Command::new("bad_utf8").try_get_matches_from(vec![
106        OsString::from(""),
107        OsString::from("-a"),
108        OsString::from_vec(vec![0xe9]),
109    ]);
110    assert!(m.is_err());
111    assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
112}
113
114#[test]
115fn invalid_utf8_strict_invalid_long() {
116    let m = Command::new("bad_utf8").try_get_matches_from(vec![
117        OsString::from(""),
118        OsString::from("--arg"),
119        OsString::from_vec(vec![0xe9]),
120    ]);
121    assert!(m.is_err());
122    assert_eq!(m.unwrap_err().kind(), ErrorKind::UnknownArgument);
123}
124
125#[test]
126fn invalid_utf8_positional() {
127    let r = Command::new("bad_utf8")
128        .arg(Arg::new("arg").value_parser(value_parser!(OsString)))
129        .try_get_matches_from(vec![OsString::from(""), OsString::from_vec(vec![0xe9])]);
130    assert!(r.is_ok(), "{}", r.unwrap_err());
131    let m = r.unwrap();
132    assert!(m.contains_id("arg"));
133    assert_eq!(
134        m.get_one::<OsString>("arg").unwrap(),
135        &*OsString::from_vec(vec![0xe9])
136    );
137}
138
139#[test]
140fn invalid_utf8_option_short_space() {
141    let r = Command::new("bad_utf8")
142        .arg(
143            Arg::new("arg")
144                .short('a')
145                .long("arg")
146                .action(ArgAction::Set)
147                .value_parser(value_parser!(OsString)),
148        )
149        .try_get_matches_from(vec![
150            OsString::from(""),
151            OsString::from("-a"),
152            OsString::from_vec(vec![0xe9]),
153        ]);
154    assert!(r.is_ok(), "{}", r.unwrap_err());
155    let m = r.unwrap();
156    assert!(m.contains_id("arg"));
157    assert_eq!(
158        m.get_one::<OsString>("arg").unwrap(),
159        &*OsString::from_vec(vec![0xe9])
160    );
161}
162
163#[test]
164fn invalid_utf8_option_short_equals() {
165    let r = Command::new("bad_utf8")
166        .arg(
167            Arg::new("arg")
168                .short('a')
169                .long("arg")
170                .action(ArgAction::Set)
171                .value_parser(value_parser!(OsString)),
172        )
173        .try_get_matches_from(vec![
174            OsString::from(""),
175            OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9]),
176        ]);
177    assert!(r.is_ok(), "{}", r.unwrap_err());
178    let m = r.unwrap();
179    assert!(m.contains_id("arg"));
180    assert_eq!(
181        m.get_one::<OsString>("arg").unwrap(),
182        &*OsString::from_vec(vec![0xe9])
183    );
184}
185
186#[test]
187fn invalid_utf8_option_short_no_space() {
188    let r = Command::new("bad_utf8")
189        .arg(
190            Arg::new("arg")
191                .short('a')
192                .long("arg")
193                .action(ArgAction::Set)
194                .value_parser(value_parser!(OsString)),
195        )
196        .try_get_matches_from(vec![
197            OsString::from(""),
198            OsString::from_vec(vec![0x2d, 0x61, 0xe9]),
199        ]);
200    assert!(r.is_ok(), "{}", r.unwrap_err());
201    let m = r.unwrap();
202    assert!(m.contains_id("arg"));
203    assert_eq!(
204        m.get_one::<OsString>("arg").unwrap(),
205        &*OsString::from_vec(vec![0xe9])
206    );
207}
208
209#[test]
210fn invalid_utf8_option_long_space() {
211    let r = Command::new("bad_utf8")
212        .arg(
213            Arg::new("arg")
214                .short('a')
215                .long("arg")
216                .action(ArgAction::Set)
217                .value_parser(value_parser!(OsString)),
218        )
219        .try_get_matches_from(vec![
220            OsString::from(""),
221            OsString::from("--arg"),
222            OsString::from_vec(vec![0xe9]),
223        ]);
224    assert!(r.is_ok(), "{}", r.unwrap_err());
225    let m = r.unwrap();
226    assert!(m.contains_id("arg"));
227    assert_eq!(
228        m.get_one::<OsString>("arg").unwrap(),
229        &*OsString::from_vec(vec![0xe9])
230    );
231}
232
233#[test]
234fn invalid_utf8_option_long_equals() {
235    let r = Command::new("bad_utf8")
236        .arg(
237            Arg::new("arg")
238                .short('a')
239                .long("arg")
240                .action(ArgAction::Set)
241                .value_parser(value_parser!(OsString)),
242        )
243        .try_get_matches_from(vec![
244            OsString::from(""),
245            OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9]),
246        ]);
247    assert!(r.is_ok(), "{}", r.unwrap_err());
248    let m = r.unwrap();
249    assert!(m.contains_id("arg"));
250    assert_eq!(
251        m.get_one::<OsString>("arg").unwrap(),
252        &*OsString::from_vec(vec![0xe9])
253    );
254}
255
256#[test]
257fn refuse_invalid_utf8_subcommand_with_allow_external_subcommands() {
258    let m = Command::new("bad_utf8")
259        .allow_external_subcommands(true)
260        .external_subcommand_value_parser(value_parser!(String))
261        .try_get_matches_from(vec![
262            OsString::from(""),
263            OsString::from_vec(vec![0xe9]),
264            OsString::from("normal"),
265        ]);
266    assert!(m.is_err());
267    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
268}
269
270#[test]
271fn refuse_invalid_utf8_subcommand_when_args_are_allowed_with_allow_external_subcommands() {
272    let m = Command::new("bad_utf8")
273        .allow_external_subcommands(true)
274        .try_get_matches_from(vec![
275            OsString::from(""),
276            OsString::from_vec(vec![0xe9]),
277            OsString::from("normal"),
278        ]);
279    assert!(m.is_err());
280    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
281}
282
283#[test]
284fn refuse_invalid_utf8_subcommand_args_with_allow_external_subcommands() {
285    let m = Command::new("bad_utf8")
286        .allow_external_subcommands(true)
287        .external_subcommand_value_parser(value_parser!(String))
288        .try_get_matches_from(vec![
289            OsString::from(""),
290            OsString::from("subcommand"),
291            OsString::from("normal"),
292            OsString::from_vec(vec![0xe9]),
293            OsString::from("--another_normal"),
294        ]);
295    assert!(m.is_err());
296    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidUtf8);
297}
298
299#[test]
300fn allow_invalid_utf8_subcommand_args_with_allow_external_subcommands() {
301    let m = Command::new("bad_utf8")
302        .allow_external_subcommands(true)
303        .try_get_matches_from(vec![
304            OsString::from(""),
305            OsString::from("subcommand"),
306            OsString::from("normal"),
307            OsString::from_vec(vec![0xe9]),
308            OsString::from("--another_normal"),
309        ]);
310    assert!(m.is_ok(), "{}", m.unwrap_err());
311    let m = m.unwrap();
312    let (subcommand, args) = m.subcommand().unwrap();
313    let args = args
314        .get_many::<OsString>("")
315        .unwrap()
316        .cloned()
317        .collect::<Vec<_>>();
318    assert_eq!(subcommand, OsString::from("subcommand"));
319    assert_eq!(
320        args,
321        vec![
322            OsString::from("normal"),
323            OsString::from_vec(vec![0xe9]),
324            OsString::from("--another_normal"),
325        ]
326    );
327}
328
329#[test]
330fn allow_validated_utf8_value_of() {
331    let a = Command::new("test").arg(arg!(--name <NAME>));
332    let m = a.try_get_matches_from(["test", "--name", "me"]).unwrap();
333    let _ = m.get_one::<String>("name").map(|v| v.as_str());
334}
335
336#[test]
337fn allow_validated_utf8_external_subcommand_values_of() {
338    let a = Command::new("test")
339        .allow_external_subcommands(true)
340        .external_subcommand_value_parser(value_parser!(String));
341    let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
342    let (_ext, args) = m.subcommand().unwrap();
343    args.get_many::<String>("").unwrap_or_default().count();
344}
345
346#[test]
347#[should_panic = "Mismatch between definition and access of ``. Could not downcast to std::ffi::os_str::OsString, need to downcast to alloc::string::String"]
348fn panic_validated_utf8_external_subcommand_values_of_os() {
349    let a = Command::new("test")
350        .allow_external_subcommands(true)
351        .external_subcommand_value_parser(value_parser!(String));
352    let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
353    let (_ext, args) = m.subcommand().unwrap();
354    args.get_many::<OsString>("").unwrap_or_default().count();
355}
356
357#[test]
358fn allow_invalid_utf8_external_subcommand_values_of_os() {
359    let a = Command::new("test").allow_external_subcommands(true);
360    let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
361    let (_ext, args) = m.subcommand().unwrap();
362    args.get_many::<OsString>("").unwrap_or_default().count();
363}
364
365#[test]
366#[should_panic = "Mismatch between definition and access of ``. Could not downcast to alloc::string::String, need to downcast to std::ffi::os_str::OsString"]
367fn panic_invalid_utf8_external_subcommand_values_of() {
368    let a = Command::new("test").allow_external_subcommands(true);
369    let m = a.try_get_matches_from(vec!["test", "cmd", "arg"]).unwrap();
370    let (_ext, args) = m.subcommand().unwrap();
371    args.get_many::<String>("").unwrap_or_default().count();
372}
373