1use clap::{builder::PossibleValue, error::ErrorKind, Arg, ArgAction, Command};
2
3#[cfg(feature = "error-context")]
4use super::utils;
5
6#[test]
7fn possible_values_of_positional() {
8    let m = Command::new("possible_values")
9        .arg(Arg::new("positional").index(1).value_parser(["test123"]))
10        .try_get_matches_from(vec!["myprog", "test123"]);
11
12    assert!(m.is_ok(), "{}", m.unwrap_err());
13    let m = m.unwrap();
14
15    assert!(m.contains_id("positional"));
16    assert_eq!(
17        m.get_one::<String>("positional").map(|v| v.as_str()),
18        Some("test123")
19    );
20}
21
22#[test]
23fn possible_value_arg_value() {
24    let m = Command::new("possible_values")
25        .arg(
26            Arg::new("arg_value")
27                .index(1)
28                .value_parser([PossibleValue::new("test123")
29                    .hide(false)
30                    .help("It's just a test")]),
31        )
32        .try_get_matches_from(vec!["myprog", "test123"]);
33
34    assert!(m.is_ok(), "{}", m.unwrap_err());
35    let m = m.unwrap();
36
37    assert!(m.contains_id("arg_value"));
38    assert_eq!(
39        m.get_one::<String>("arg_value").map(|v| v.as_str()),
40        Some("test123")
41    );
42}
43
44#[test]
45fn possible_values_of_positional_fail() {
46    let m = Command::new("possible_values")
47        .arg(Arg::new("positional").index(1).value_parser(["test123"]))
48        .try_get_matches_from(vec!["myprog", "notest"]);
49
50    assert!(m.is_err());
51    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
52}
53
54#[test]
55fn possible_values_of_positional_multiple() {
56    let m = Command::new("possible_values")
57        .arg(
58            Arg::new("positional")
59                .index(1)
60                .action(ArgAction::Set)
61                .value_parser(["test123", "test321"])
62                .num_args(1..),
63        )
64        .try_get_matches_from(vec!["myprog", "test123", "test321"]);
65
66    assert!(m.is_ok(), "{}", m.unwrap_err());
67    let m = m.unwrap();
68
69    assert!(m.contains_id("positional"));
70    assert_eq!(
71        m.get_many::<String>("positional")
72            .unwrap()
73            .map(|v| v.as_str())
74            .collect::<Vec<_>>(),
75        vec!["test123", "test321"]
76    );
77}
78
79#[test]
80fn possible_values_of_positional_multiple_fail() {
81    let m = Command::new("possible_values")
82        .arg(
83            Arg::new("positional")
84                .index(1)
85                .action(ArgAction::Set)
86                .value_parser(["test123", "test321"])
87                .num_args(1..),
88        )
89        .try_get_matches_from(vec!["myprog", "test123", "notest"]);
90
91    assert!(m.is_err());
92    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
93}
94
95#[test]
96fn possible_values_of_option() {
97    let m = Command::new("possible_values")
98        .arg(
99            Arg::new("option")
100                .short('o')
101                .long("option")
102                .action(ArgAction::Set)
103                .value_parser(["test123"]),
104        )
105        .try_get_matches_from(vec!["myprog", "--option", "test123"]);
106
107    assert!(m.is_ok(), "{}", m.unwrap_err());
108    let m = m.unwrap();
109
110    assert!(m.contains_id("option"));
111    assert_eq!(
112        m.get_one::<String>("option").map(|v| v.as_str()),
113        Some("test123")
114    );
115}
116
117#[test]
118fn possible_values_of_option_fail() {
119    let m = Command::new("possible_values")
120        .arg(
121            Arg::new("option")
122                .short('o')
123                .long("option")
124                .action(ArgAction::Set)
125                .value_parser(["test123"]),
126        )
127        .try_get_matches_from(vec!["myprog", "--option", "notest"]);
128
129    assert!(m.is_err());
130    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
131}
132
133#[test]
134fn possible_values_of_option_multiple() {
135    let m = Command::new("possible_values")
136        .arg(
137            Arg::new("option")
138                .short('o')
139                .long("option")
140                .action(ArgAction::Set)
141                .value_parser(["test123", "test321"])
142                .action(ArgAction::Append),
143        )
144        .try_get_matches_from(vec!["", "--option", "test123", "--option", "test321"]);
145
146    assert!(m.is_ok(), "{}", m.unwrap_err());
147    let m = m.unwrap();
148
149    assert!(m.contains_id("option"));
150    assert_eq!(
151        m.get_many::<String>("option")
152            .unwrap()
153            .map(|v| v.as_str())
154            .collect::<Vec<_>>(),
155        vec!["test123", "test321"]
156    );
157}
158
159#[test]
160fn possible_values_of_option_multiple_fail() {
161    let m = Command::new("possible_values")
162        .arg(
163            Arg::new("option")
164                .short('o')
165                .long("option")
166                .action(ArgAction::Set)
167                .value_parser(["test123", "test321"])
168                .action(ArgAction::Append),
169        )
170        .try_get_matches_from(vec!["", "--option", "test123", "--option", "notest"]);
171
172    assert!(m.is_err());
173    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
174}
175
176#[test]
177#[cfg(feature = "error-context")]
178fn possible_values_output() {
179    #[cfg(feature = "suggestions")]
180    static PV_ERROR: &str = "\
181error: invalid value 'slo' for '-O <option>'
182  [possible values: slow, fast, \"ludicrous speed\"]
183
184  note: value 'slow' exists
185
186For more information, try '--help'.
187";
188
189    #[cfg(not(feature = "suggestions"))]
190    static PV_ERROR: &str = "\
191error: invalid value 'slo' for '-O <option>'
192  [possible values: slow, fast, \"ludicrous speed\"]
193
194For more information, try '--help'.
195";
196
197    utils::assert_output(
198        Command::new("test").arg(
199            Arg::new("option")
200                .short('O')
201                .action(ArgAction::Set)
202                .value_parser(["slow", "fast", "ludicrous speed"]),
203        ),
204        "clap-test -O slo",
205        PV_ERROR,
206        true,
207    );
208}
209
210#[test]
211#[cfg(feature = "error-context")]
212fn possible_values_alias_output() {
213    #[cfg(feature = "suggestions")]
214    static PV_ERROR: &str = "\
215error: invalid value 'slo' for '-O <option>'
216  [possible values: slow, fast, \"ludicrous speed\"]
217
218  note: value 'slow' exists
219
220For more information, try '--help'.
221";
222
223    #[cfg(not(feature = "suggestions"))]
224    static PV_ERROR: &str = "\
225error: invalid value 'slo' for '-O <option>'
226  [possible values: slow, fast, \"ludicrous speed\"]
227
228For more information, try '--help'.
229";
230
231    utils::assert_output(
232        Command::new("test").arg(
233            Arg::new("option")
234                .short('O')
235                .action(ArgAction::Set)
236                .value_parser([
237                    "slow".into(),
238                    PossibleValue::new("fast").alias("fost"),
239                    PossibleValue::new("ludicrous speed").aliases(["ls", "lcs"]),
240                ]),
241        ),
242        "clap-test -O slo",
243        PV_ERROR,
244        true,
245    );
246}
247
248#[test]
249#[cfg(feature = "error-context")]
250fn possible_values_hidden_output() {
251    #[cfg(feature = "suggestions")]
252    static PV_ERROR: &str = "\
253error: invalid value 'slo' for '-O <option>'
254  [possible values: slow, fast, \"ludicrous speed\"]
255
256  note: value 'slow' exists
257
258For more information, try '--help'.
259";
260
261    #[cfg(not(feature = "suggestions"))]
262    static PV_ERROR: &str = "\
263error: invalid value 'slo' for '-O <option>'
264  [possible values: slow, fast, \"ludicrous speed\"]
265
266For more information, try '--help'.
267";
268
269    utils::assert_output(
270        Command::new("test").arg(
271            Arg::new("option")
272                .short('O')
273                .action(ArgAction::Set)
274                .value_parser([
275                    "slow".into(),
276                    "fast".into(),
277                    PossibleValue::new("ludicrous speed"),
278                    PossibleValue::new("forbidden speed").hide(true),
279                ]),
280        ),
281        "clap-test -O slo",
282        PV_ERROR,
283        true,
284    );
285}
286
287#[test]
288#[cfg(feature = "error-context")]
289fn escaped_possible_values_output() {
290    #[cfg(feature = "suggestions")]
291    static PV_ERROR_ESCAPED: &str = "\
292error: invalid value 'ludicrous' for '-O <option>'
293  [possible values: slow, fast, \"ludicrous speed\"]
294
295  note: value 'ludicrous speed' exists
296
297For more information, try '--help'.
298";
299
300    #[cfg(not(feature = "suggestions"))]
301    static PV_ERROR_ESCAPED: &str = "\
302error: invalid value 'ludicrous' for '-O <option>'
303  [possible values: slow, fast, \"ludicrous speed\"]
304
305For more information, try '--help'.
306";
307
308    utils::assert_output(
309        Command::new("test").arg(
310            Arg::new("option")
311                .short('O')
312                .action(ArgAction::Set)
313                .value_parser(["slow", "fast", "ludicrous speed"]),
314        ),
315        "clap-test -O ludicrous",
316        PV_ERROR_ESCAPED,
317        true,
318    );
319}
320
321#[test]
322#[cfg(feature = "error-context")]
323fn missing_possible_value_error() {
324    static MISSING_PV_ERROR: &str = "\
325error: a value is required for '-O <option>' but none was supplied
326  [possible values: slow, fast, \"ludicrous speed\"]
327
328For more information, try '--help'.
329";
330
331    utils::assert_output(
332        Command::new("test").arg(
333            Arg::new("option")
334                .short('O')
335                .action(ArgAction::Set)
336                .value_parser([
337                    "slow".into(),
338                    PossibleValue::new("fast").alias("fost"),
339                    PossibleValue::new("ludicrous speed"),
340                    PossibleValue::new("forbidden speed").hide(true),
341                ]),
342        ),
343        "clap-test -O",
344        MISSING_PV_ERROR,
345        true,
346    );
347}
348
349#[test]
350fn alias() {
351    let m = Command::new("pv")
352        .arg(
353            Arg::new("option")
354                .short('o')
355                .long("option")
356                .action(ArgAction::Set)
357                .value_parser([PossibleValue::new("test123").alias("123"), "test321".into()])
358                .ignore_case(true),
359        )
360        .try_get_matches_from(vec!["pv", "--option", "123"]);
361
362    assert!(m.is_ok(), "{}", m.unwrap_err());
363    assert!(m
364        .unwrap()
365        .get_one::<String>("option")
366        .map(|v| v.as_str())
367        .unwrap()
368        .eq("123"));
369}
370
371#[test]
372fn aliases() {
373    let m = Command::new("pv")
374        .arg(
375            Arg::new("option")
376                .short('o')
377                .long("option")
378                .action(ArgAction::Set)
379                .value_parser([
380                    PossibleValue::new("test123").aliases(["1", "2", "3"]),
381                    "test321".into(),
382                ])
383                .ignore_case(true),
384        )
385        .try_get_matches_from(vec!["pv", "--option", "2"]);
386
387    assert!(m.is_ok(), "{}", m.unwrap_err());
388    assert!(m
389        .unwrap()
390        .get_one::<String>("option")
391        .map(|v| v.as_str())
392        .unwrap()
393        .eq("2"));
394}
395
396#[test]
397fn ignore_case() {
398    let m = Command::new("pv")
399        .arg(
400            Arg::new("option")
401                .short('o')
402                .long("option")
403                .action(ArgAction::Set)
404                .value_parser(["test123", "test321"])
405                .ignore_case(true),
406        )
407        .try_get_matches_from(vec!["pv", "--option", "TeSt123"]);
408
409    assert!(m.is_ok(), "{}", m.unwrap_err());
410    assert!(m
411        .unwrap()
412        .get_one::<String>("option")
413        .map(|v| v.as_str())
414        .unwrap()
415        .eq_ignore_ascii_case("test123"));
416}
417
418#[test]
419fn ignore_case_fail() {
420    let m = Command::new("pv")
421        .arg(
422            Arg::new("option")
423                .short('o')
424                .long("option")
425                .action(ArgAction::Set)
426                .value_parser(["test123", "test321"]),
427        )
428        .try_get_matches_from(vec!["pv", "--option", "TeSt123"]);
429
430    assert!(m.is_err());
431    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
432}
433
434#[test]
435fn ignore_case_multiple() {
436    let m = Command::new("pv")
437        .arg(
438            Arg::new("option")
439                .short('o')
440                .long("option")
441                .action(ArgAction::Set)
442                .value_parser(["test123", "test321"])
443                .num_args(1..)
444                .ignore_case(true),
445        )
446        .try_get_matches_from(vec!["pv", "--option", "TeSt123", "teST123", "tESt321"]);
447
448    assert!(m.is_ok(), "{}", m.unwrap_err());
449    assert_eq!(
450        m.unwrap()
451            .get_many::<String>("option")
452            .unwrap()
453            .map(|v| v.as_str())
454            .collect::<Vec<_>>(),
455        ["TeSt123", "teST123", "tESt321"]
456    );
457}
458
459#[test]
460fn ignore_case_multiple_fail() {
461    let m = Command::new("pv")
462        .arg(
463            Arg::new("option")
464                .short('o')
465                .long("option")
466                .action(ArgAction::Set)
467                .value_parser(["test123", "test321"])
468                .num_args(1..),
469        )
470        .try_get_matches_from(vec!["pv", "--option", "test123", "teST123", "test321"]);
471
472    assert!(m.is_err());
473    assert_eq!(m.unwrap_err().kind(), ErrorKind::InvalidValue);
474}
475