1 #![cfg(not(windows))]
2
3 use clap::{arg, error::ErrorKind, value_parser, Arg, ArgAction, Command};
4 use std::ffi::OsString;
5 use std::os::unix::ffi::OsStringExt;
6
7 #[test]
invalid_utf8_strict_positional()8 fn 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]
invalid_utf8_strict_option_short_space()17 fn 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]
invalid_utf8_strict_option_short_equals()35 fn 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]
invalid_utf8_strict_option_short_no_space()52 fn 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]
invalid_utf8_strict_option_long_space()69 fn 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]
invalid_utf8_strict_option_long_equals()87 fn 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]
invalid_utf8_strict_invalid_short()104 fn 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]
invalid_utf8_strict_invalid_long()115 fn 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]
invalid_utf8_positional()126 fn 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]
invalid_utf8_option_short_space()140 fn 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]
invalid_utf8_option_short_equals()164 fn 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]
invalid_utf8_option_short_no_space()187 fn 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]
invalid_utf8_option_long_space()210 fn 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]
invalid_utf8_option_long_equals()234 fn 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]
refuse_invalid_utf8_subcommand_with_allow_external_subcommands()257 fn 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]
refuse_invalid_utf8_subcommand_when_args_are_allowed_with_allow_external_subcommands()271 fn 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]
refuse_invalid_utf8_subcommand_args_with_allow_external_subcommands()284 fn 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]
allow_invalid_utf8_subcommand_args_with_allow_external_subcommands()300 fn 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]
allow_validated_utf8_value_of()330 fn 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]
allow_validated_utf8_external_subcommand_values_of()337 fn 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"]
panic_validated_utf8_external_subcommand_values_of_os()348 fn 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]
allow_invalid_utf8_external_subcommand_values_of_os()358 fn 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"]
panic_invalid_utf8_external_subcommand_values_of()367 fn 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