• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::cmp::Ordering;
2 
3 use clap_lex::RawOsStr;
4 
5 use crate::builder::arg::ArgProvider;
6 use crate::mkeymap::KeyType;
7 use crate::ArgAction;
8 use crate::{Arg, Command, ValueHint};
9 
assert_app(cmd: &Command)10 pub(crate) fn assert_app(cmd: &Command) {
11     debug!("Command::_debug_asserts");
12 
13     let mut short_flags = vec![];
14     let mut long_flags = vec![];
15 
16     // Invalid version flag settings
17     if cmd.get_version().is_none() && cmd.get_long_version().is_none() {
18         // PropagateVersion is meaningless if there is no version
19         assert!(
20             !cmd.is_propagate_version_set(),
21             "Command {}: No version information via Command::version or Command::long_version to propagate",
22             cmd.get_name(),
23         );
24 
25         // Used `Command::mut_arg("version", ..) but did not provide any version information to display
26         let version_needed = cmd
27             .get_arguments()
28             .filter(|x| {
29                 let action_set = matches!(x.get_action(), ArgAction::Version);
30                 #[cfg(not(feature = "unstable-v4"))]
31                 let provider_set = matches!(x.provider, ArgProvider::GeneratedMutated);
32                 #[cfg(feature = "unstable-v4")]
33                 let provider_set = matches!(
34                     x.provider,
35                     ArgProvider::User | ArgProvider::GeneratedMutated
36                 );
37                 action_set && provider_set
38             })
39             .map(|x| x.get_id())
40             .collect::<Vec<_>>();
41 
42         assert_eq!(version_needed, Vec::<&str>::new(), "Command {}: `ArgAction::Version` used without providing Command::version or Command::long_version"
43             ,cmd.get_name()
44         );
45     }
46 
47     for sc in cmd.get_subcommands() {
48         if let Some(s) = sc.get_short_flag().as_ref() {
49             short_flags.push(Flag::Command(format!("-{}", s), sc.get_name()));
50         }
51 
52         for short_alias in sc.get_all_short_flag_aliases() {
53             short_flags.push(Flag::Command(format!("-{}", short_alias), sc.get_name()));
54         }
55 
56         if let Some(l) = sc.get_long_flag().as_ref() {
57             #[cfg(feature = "unstable-v4")]
58             {
59                 assert!(!l.starts_with('-'), "Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser", sc.get_name(), l);
60             }
61             long_flags.push(Flag::Command(format!("--{}", l), sc.get_name()));
62         }
63 
64         for long_alias in sc.get_all_long_flag_aliases() {
65             long_flags.push(Flag::Command(format!("--{}", long_alias), sc.get_name()));
66         }
67     }
68 
69     for arg in cmd.get_arguments() {
70         assert_arg(arg);
71 
72         assert!(
73             !cmd.is_multicall_set(),
74             "Command {}: Arguments like {} cannot be set on a multicall command",
75             cmd.get_name(),
76             arg.name
77         );
78 
79         if let Some(s) = arg.short.as_ref() {
80             short_flags.push(Flag::Arg(format!("-{}", s), &*arg.name));
81         }
82 
83         for (short_alias, _) in &arg.short_aliases {
84             short_flags.push(Flag::Arg(format!("-{}", short_alias), arg.name));
85         }
86 
87         if let Some(l) = arg.long.as_ref() {
88             #[cfg(feature = "unstable-v4")]
89             {
90                 assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.name, l);
91             }
92             long_flags.push(Flag::Arg(format!("--{}", l), &*arg.name));
93         }
94 
95         for (long_alias, _) in &arg.aliases {
96             long_flags.push(Flag::Arg(format!("--{}", long_alias), arg.name));
97         }
98 
99         // Name conflicts
100         assert!(
101             cmd.two_args_of(|x| x.id == arg.id).is_none(),
102             "Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group",
103             cmd.get_name(),
104             arg.name,
105         );
106 
107         // Long conflicts
108         if let Some(l) = arg.long {
109             if let Some((first, second)) = cmd.two_args_of(|x| x.long == Some(l)) {
110                 panic!(
111                     "Command {}: Long option names must be unique for each argument, \
112                         but '--{}' is in use by both '{}' and '{}'",
113                     cmd.get_name(),
114                     l,
115                     first.name,
116                     second.name
117                 )
118             }
119         }
120 
121         // Short conflicts
122         if let Some(s) = arg.short {
123             if let Some((first, second)) = cmd.two_args_of(|x| x.short == Some(s)) {
124                 panic!(
125                     "Command {}: Short option names must be unique for each argument, \
126                         but '-{}' is in use by both '{}' and '{}'",
127                     cmd.get_name(),
128                     s,
129                     first.name,
130                     second.name
131                 )
132             }
133         }
134 
135         // Index conflicts
136         if let Some(idx) = arg.index {
137             if let Some((first, second)) =
138                 cmd.two_args_of(|x| x.is_positional() && x.index == Some(idx))
139             {
140                 panic!(
141                     "Command {}: Argument '{}' has the same index as '{}' \
142                     and they are both positional arguments\n\n\t \
143                     Use Arg::multiple_values(true) to allow one \
144                     positional argument to take multiple values",
145                     cmd.get_name(),
146                     first.name,
147                     second.name
148                 )
149             }
150         }
151 
152         // requires, r_if, r_unless
153         for req in &arg.requires {
154             assert!(
155                 cmd.id_exists(&req.1),
156                 "Command {}: Argument or group '{:?}' specified in 'requires*' for '{}' does not exist",
157                 cmd.get_name(),
158                 req.1,
159                 arg.name,
160             );
161         }
162 
163         for req in &arg.r_ifs {
164             #[cfg(feature = "unstable-v4")]
165             {
166                 assert!(
167                     !arg.is_required_set(),
168                     "Argument {}: `required` conflicts with `required_if_eq*`",
169                     arg.name
170                 );
171             }
172             assert!(
173                 cmd.id_exists(&req.0),
174                 "Command {}: Argument or group '{:?}' specified in 'required_if_eq*' for '{}' does not exist",
175                     cmd.get_name(),
176                 req.0,
177                 arg.name
178             );
179         }
180 
181         for req in &arg.r_ifs_all {
182             #[cfg(feature = "unstable-v4")]
183             {
184                 assert!(
185                     !arg.is_required_set(),
186                     "Argument {}: `required` conflicts with `required_if_eq_all`",
187                     arg.name
188                 );
189             }
190             assert!(
191                 cmd.id_exists(&req.0),
192                 "Command {}: Argument or group '{:?}' specified in 'required_if_eq_all' for '{}' does not exist",
193                     cmd.get_name(),
194                 req.0,
195                 arg.name
196             );
197         }
198 
199         for req in &arg.r_unless {
200             #[cfg(feature = "unstable-v4")]
201             {
202                 assert!(
203                     !arg.is_required_set(),
204                     "Argument {}: `required` conflicts with `required_unless*`",
205                     arg.name
206                 );
207             }
208             assert!(
209                 cmd.id_exists(req),
210                 "Command {}: Argument or group '{:?}' specified in 'required_unless*' for '{}' does not exist",
211                     cmd.get_name(),
212                 req,
213                 arg.name,
214             );
215         }
216 
217         for req in &arg.r_unless_all {
218             #[cfg(feature = "unstable-v4")]
219             {
220                 assert!(
221                     !arg.is_required_set(),
222                     "Argument {}: `required` conflicts with `required_unless*`",
223                     arg.name
224                 );
225             }
226             assert!(
227                 cmd.id_exists(req),
228                 "Command {}: Argument or group '{:?}' specified in 'required_unless*' for '{}' does not exist",
229                     cmd.get_name(),
230                 req,
231                 arg.name,
232             );
233         }
234 
235         // blacklist
236         for req in &arg.blacklist {
237             assert!(
238                 cmd.id_exists(req),
239                 "Command {}: Argument or group '{:?}' specified in 'conflicts_with*' for '{}' does not exist",
240                     cmd.get_name(),
241                 req,
242                 arg.name,
243             );
244         }
245 
246         if arg.is_last_set() {
247             assert!(
248                 arg.long.is_none(),
249                 "Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
250                     cmd.get_name(),
251                 arg.name
252             );
253             assert!(
254                 arg.short.is_none(),
255                 "Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
256                     cmd.get_name(),
257                 arg.name
258             );
259         }
260 
261         assert!(
262             !(arg.is_required_set() && arg.is_global_set()),
263             "Command {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
264                     cmd.get_name(),
265             arg.name
266         );
267 
268         // validators
269         assert!(
270             arg.validator.is_none() || arg.validator_os.is_none(),
271             "Command {}: Argument '{}' has both `validator` and `validator_os` set which is not allowed",
272                     cmd.get_name(),
273             arg.name
274         );
275 
276         if arg.get_value_hint() == ValueHint::CommandWithArguments {
277             assert!(
278                 arg.is_positional(),
279                 "Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
280                 cmd.get_name(),
281                 arg.name
282             );
283 
284             assert!(
285                 cmd.is_trailing_var_arg_set(),
286                 "Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have TrailingVarArg set.",
287                     cmd.get_name(),
288                 arg.name
289             );
290         }
291     }
292 
293     for group in cmd.get_groups() {
294         // Name conflicts
295         assert!(
296             cmd.get_groups().filter(|x| x.id == group.id).count() < 2,
297             "Command {}: Argument group name must be unique\n\n\t'{}' is already in use",
298             cmd.get_name(),
299             group.name,
300         );
301 
302         // Groups should not have naming conflicts with Args
303         assert!(
304             !cmd.get_arguments().any(|x| x.id == group.id),
305             "Command {}: Argument group name '{}' must not conflict with argument name",
306             cmd.get_name(),
307             group.name,
308         );
309 
310         for arg in &group.args {
311             // Args listed inside groups should exist
312             assert!(
313                 cmd.get_arguments().any(|x| x.id == *arg),
314                 "Command {}: Argument group '{}' contains non-existent argument '{:?}'",
315                 cmd.get_name(),
316                 group.name,
317                 arg
318             );
319         }
320     }
321 
322     // Conflicts between flags and subcommands
323 
324     long_flags.sort_unstable();
325     short_flags.sort_unstable();
326 
327     detect_duplicate_flags(&long_flags, "long");
328     detect_duplicate_flags(&short_flags, "short");
329 
330     _verify_positionals(cmd);
331 
332     if let Some(help_template) = cmd.get_help_template() {
333         assert!(
334             !help_template.contains("{flags}"),
335             "Command {}: {}",
336                     cmd.get_name(),
337             "`{flags}` template variable was removed in clap3, they are now included in `{options}`",
338         );
339         assert!(
340             !help_template.contains("{unified}"),
341             "Command {}: {}",
342             cmd.get_name(),
343             "`{unified}` template variable was removed in clap3, use `{options}` instead"
344         );
345     }
346 
347     cmd._panic_on_missing_help(cmd.is_help_expected_set());
348     assert_app_flags(cmd);
349 }
350 
351 #[derive(Eq)]
352 enum Flag<'a> {
353     Command(String, &'a str),
354     Arg(String, &'a str),
355 }
356 
357 impl PartialEq for Flag<'_> {
eq(&self, other: &Flag) -> bool358     fn eq(&self, other: &Flag) -> bool {
359         self.cmp(other) == Ordering::Equal
360     }
361 }
362 
363 impl PartialOrd for Flag<'_> {
partial_cmp(&self, other: &Flag) -> Option<Ordering>364     fn partial_cmp(&self, other: &Flag) -> Option<Ordering> {
365         use Flag::*;
366 
367         match (self, other) {
368             (Command(s1, _), Command(s2, _))
369             | (Arg(s1, _), Arg(s2, _))
370             | (Command(s1, _), Arg(s2, _))
371             | (Arg(s1, _), Command(s2, _)) => {
372                 if s1 == s2 {
373                     Some(Ordering::Equal)
374                 } else {
375                     s1.partial_cmp(s2)
376                 }
377             }
378         }
379     }
380 }
381 
382 impl Ord for Flag<'_> {
cmp(&self, other: &Self) -> Ordering383     fn cmp(&self, other: &Self) -> Ordering {
384         self.partial_cmp(other).unwrap()
385     }
386 }
387 
detect_duplicate_flags(flags: &[Flag], short_or_long: &str)388 fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
389     use Flag::*;
390 
391     for (one, two) in find_duplicates(flags) {
392         match (one, two) {
393             (Command(flag, one), Command(_, another)) if one != another => panic!(
394                 "the '{}' {} flag is specified for both '{}' and '{}' subcommands",
395                 flag, short_or_long, one, another
396             ),
397 
398             (Arg(flag, one), Arg(_, another)) if one != another => panic!(
399                 "{} option names must be unique, but '{}' is in use by both '{}' and '{}'",
400                 short_or_long, flag, one, another
401             ),
402 
403             (Arg(flag, arg), Command(_, sub)) | (Command(flag, sub), Arg(_, arg)) => panic!(
404                 "the '{}' {} flag for the '{}' argument conflicts with the short flag \
405                      for '{}' subcommand",
406                 flag, short_or_long, arg, sub
407             ),
408 
409             _ => {}
410         }
411     }
412 }
413 
414 /// Find duplicates in a sorted array.
415 ///
416 /// The algorithm is simple: the array is sorted, duplicates
417 /// must be placed next to each other, we can check only adjacent elements.
find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)>418 fn find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)> {
419     slice.windows(2).filter_map(|w| {
420         if w[0] == w[1] {
421             Some((&w[0], &w[1]))
422         } else {
423             None
424         }
425     })
426 }
427 
assert_app_flags(cmd: &Command)428 fn assert_app_flags(cmd: &Command) {
429     macro_rules! checker {
430         ($a:ident requires $($b:ident)|+) => {
431             if cmd.$a() {
432                 let mut s = String::new();
433 
434                 $(
435                     if !cmd.$b() {
436                         s.push_str(&format!("  AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)));
437                     }
438                 )+
439 
440                 if !s.is_empty() {
441                     panic!("{}", s)
442                 }
443             }
444         };
445         ($a:ident conflicts $($b:ident)|+) => {
446             if cmd.$a() {
447                 let mut s = String::new();
448 
449                 $(
450                     if cmd.$b() {
451                         s.push_str(&format!("  AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)));
452                     }
453                 )+
454 
455                 if !s.is_empty() {
456                     panic!("{}\n{}", cmd.get_name(), s)
457                 }
458             }
459         };
460     }
461 
462     checker!(is_allow_invalid_utf8_for_external_subcommands_set requires is_allow_external_subcommands_set);
463     checker!(is_multicall_set conflicts is_no_binary_name_set);
464 }
465 
466 #[cfg(debug_assertions)]
_verify_positionals(cmd: &Command) -> bool467 fn _verify_positionals(cmd: &Command) -> bool {
468     debug!("Command::_verify_positionals");
469     // Because you must wait until all arguments have been supplied, this is the first chance
470     // to make assertions on positional argument indexes
471     //
472     // First we verify that the index highest supplied index, is equal to the number of
473     // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
474     // but no 2)
475 
476     let highest_idx = cmd
477         .get_keymap()
478         .keys()
479         .filter_map(|x| {
480             if let KeyType::Position(n) = x {
481                 Some(*n)
482             } else {
483                 None
484             }
485         })
486         .max()
487         .unwrap_or(0);
488 
489     let num_p = cmd.get_keymap().keys().filter(|x| x.is_position()).count();
490 
491     assert!(
492         highest_idx == num_p,
493         "Found positional argument whose index is {} but there \
494              are only {} positional arguments defined",
495         highest_idx,
496         num_p
497     );
498 
499     // Next we verify that only the highest index has takes multiple arguments (if any)
500     let only_highest = |a: &Arg| a.is_multiple() && (a.index.unwrap_or(0) != highest_idx);
501     if cmd.get_positionals().any(only_highest) {
502         // First we make sure if there is a positional that allows multiple values
503         // the one before it (second to last) has one of these:
504         //  * a value terminator
505         //  * ArgSettings::Last
506         //  * The last arg is Required
507 
508         // We can't pass the closure (it.next()) to the macro directly because each call to
509         // find() (iterator, not macro) gets called repeatedly.
510         let last = &cmd.get_keymap()[&KeyType::Position(highest_idx)];
511         let second_to_last = &cmd.get_keymap()[&KeyType::Position(highest_idx - 1)];
512 
513         // Either the final positional is required
514         // Or the second to last has a terminator or .last(true) set
515         let ok = last.is_required_set()
516             || (second_to_last.terminator.is_some() || second_to_last.is_last_set())
517             || last.is_last_set();
518         assert!(
519             ok,
520             "When using a positional argument with .multiple_values(true) that is *not the \
521                  last* positional argument, the last positional argument (i.e. the one \
522                  with the highest index) *must* have .required(true) or .last(true) set."
523         );
524 
525         // We make sure if the second to last is Multiple the last is ArgSettings::Last
526         let ok = second_to_last.is_multiple() || last.is_last_set();
527         assert!(
528             ok,
529             "Only the last positional argument, or second to last positional \
530                  argument may be set to .multiple_values(true)"
531         );
532 
533         // Next we check how many have both Multiple and not a specific number of values set
534         let count = cmd
535             .get_positionals()
536             .filter(|p| {
537                 #[allow(deprecated)]
538                 {
539                     p.is_multiple_occurrences_set()
540                         || (p.is_multiple_values_set() && p.num_vals.is_none())
541                 }
542             })
543             .count();
544         let ok = count <= 1
545             || (last.is_last_set()
546                 && last.is_multiple()
547                 && second_to_last.is_multiple()
548                 && count == 2);
549         assert!(
550             ok,
551             "Only one positional argument with .multiple_values(true) set is allowed per \
552                  command, unless the second one also has .last(true) set"
553         );
554     }
555 
556     let mut found = false;
557 
558     if cmd.is_allow_missing_positional_set() {
559         // Check that if a required positional argument is found, all positions with a lower
560         // index are also required.
561         let mut foundx2 = false;
562 
563         for p in cmd.get_positionals() {
564             if foundx2 && !p.is_required_set() {
565                 assert!(
566                     p.is_required_set(),
567                     "Found non-required positional argument with a lower \
568                          index than a required positional argument by two or more: {:?} \
569                          index {:?}",
570                     p.name,
571                     p.index
572                 );
573             } else if p.is_required_set() && !p.is_last_set() {
574                 // Args that .last(true) don't count since they can be required and have
575                 // positionals with a lower index that aren't required
576                 // Imagine: prog <req1> [opt1] -- <req2>
577                 // Both of these are valid invocations:
578                 //      $ prog r1 -- r2
579                 //      $ prog r1 o1 -- r2
580                 if found {
581                     foundx2 = true;
582                     continue;
583                 }
584                 found = true;
585                 continue;
586             } else {
587                 found = false;
588             }
589         }
590     } else {
591         // Check that if a required positional argument is found, all positions with a lower
592         // index are also required
593         for p in (1..=num_p).rev().filter_map(|n| cmd.get_keymap().get(&n)) {
594             if found {
595                 assert!(
596                     p.is_required_set(),
597                     "Found non-required positional argument with a lower \
598                          index than a required positional argument: {:?} index {:?}",
599                     p.name,
600                     p.index
601                 );
602             } else if p.is_required_set() && !p.is_last_set() {
603                 // Args that .last(true) don't count since they can be required and have
604                 // positionals with a lower index that aren't required
605                 // Imagine: prog <req1> [opt1] -- <req2>
606                 // Both of these are valid invocations:
607                 //      $ prog r1 -- r2
608                 //      $ prog r1 o1 -- r2
609                 found = true;
610                 continue;
611             }
612         }
613     }
614     assert!(
615         cmd.get_positionals().filter(|p| p.is_last_set()).count() < 2,
616         "Only one positional argument may have last(true) set. Found two."
617     );
618     if cmd
619         .get_positionals()
620         .any(|p| p.is_last_set() && p.is_required_set())
621         && cmd.has_subcommands()
622         && !cmd.is_subcommand_negates_reqs_set()
623     {
624         panic!(
625             "Having a required positional argument with .last(true) set *and* child \
626                  subcommands without setting SubcommandsNegateReqs isn't compatible."
627         );
628     }
629 
630     true
631 }
632 
assert_arg(arg: &Arg)633 fn assert_arg(arg: &Arg) {
634     debug!("Arg::_debug_asserts:{}", arg.name);
635 
636     // Self conflict
637     // TODO: this check should be recursive
638     assert!(
639         !arg.blacklist.iter().any(|x| *x == arg.id),
640         "Argument '{}' cannot conflict with itself",
641         arg.name,
642     );
643 
644     assert_eq!(
645         arg.get_action().takes_values(),
646         arg.is_takes_value_set(),
647         "Argument `{}`'s selected action {:?} contradicts `takes_value`",
648         arg.name,
649         arg.get_action()
650     );
651     if let Some(action_type_id) = arg.get_action().value_type_id() {
652         assert_eq!(
653             action_type_id,
654             arg.get_value_parser().type_id(),
655             "Argument `{}`'s selected action {:?} contradicts `value_parser` ({:?})",
656             arg.name,
657             arg.get_action(),
658             arg.get_value_parser()
659         );
660     }
661 
662     if arg.get_value_hint() != ValueHint::Unknown {
663         assert!(
664             arg.is_takes_value_set(),
665             "Argument '{}' has value hint but takes no value",
666             arg.name
667         );
668 
669         if arg.get_value_hint() == ValueHint::CommandWithArguments {
670             assert!(
671                 arg.is_multiple_values_set(),
672                 "Argument '{}' uses hint CommandWithArguments and must accept multiple values",
673                 arg.name
674             )
675         }
676     }
677 
678     if arg.index.is_some() {
679         assert!(
680             arg.is_positional(),
681             "Argument '{}' is a positional argument and can't have short or long name versions",
682             arg.name
683         );
684         assert!(
685             arg.is_takes_value_set(),
686             "Argument '{}` is positional, it must take a value",
687             arg.name
688         );
689     }
690 
691     #[cfg(feature = "unstable-v4")]
692     {
693         let num_vals = arg.get_num_vals().unwrap_or(usize::MAX);
694         let num_val_names = arg.get_value_names().unwrap_or(&[]).len();
695         if num_vals < num_val_names {
696             panic!(
697                 "Argument {}: Too many value names ({}) compared to number_of_values ({})",
698                 arg.name, num_val_names, num_vals
699             );
700         }
701     }
702 
703     assert_arg_flags(arg);
704 
705     assert_defaults(arg, "default_value", arg.default_vals.iter().copied());
706     assert_defaults(
707         arg,
708         "default_missing_value",
709         arg.default_missing_vals.iter().copied(),
710     );
711     assert_defaults(
712         arg,
713         "default_value_if",
714         arg.default_vals_ifs
715             .iter()
716             .filter_map(|(_, _, default)| *default),
717     );
718 }
719 
assert_arg_flags(arg: &Arg)720 fn assert_arg_flags(arg: &Arg) {
721     macro_rules! checker {
722         ($a:ident requires $($b:ident)|+) => {
723             if arg.$a() {
724                 let mut s = String::new();
725 
726                 $(
727                     if !arg.$b() {
728                         s.push_str(&format!("  Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)));
729                     }
730                 )+
731 
732                 if !s.is_empty() {
733                     panic!("Argument {:?}\n{}", arg.get_id(), s)
734                 }
735             }
736         }
737     }
738 
739     checker!(is_require_value_delimiter_set requires is_takes_value_set);
740     checker!(is_require_value_delimiter_set requires is_use_value_delimiter_set);
741     checker!(is_hide_possible_values_set requires is_takes_value_set);
742     checker!(is_allow_hyphen_values_set requires is_takes_value_set);
743     checker!(is_require_equals_set requires is_takes_value_set);
744     checker!(is_last_set requires is_takes_value_set);
745     checker!(is_hide_default_value_set requires is_takes_value_set);
746     checker!(is_multiple_values_set requires is_takes_value_set);
747     checker!(is_ignore_case_set requires is_takes_value_set);
748     {
749         #![allow(deprecated)]
750         checker!(is_forbid_empty_values_set requires is_takes_value_set);
751         checker!(is_allow_invalid_utf8_set requires is_takes_value_set);
752     }
753 }
754 
assert_defaults<'d>( arg: &Arg, field: &'static str, defaults: impl IntoIterator<Item = &'d std::ffi::OsStr>, )755 fn assert_defaults<'d>(
756     arg: &Arg,
757     field: &'static str,
758     defaults: impl IntoIterator<Item = &'d std::ffi::OsStr>,
759 ) {
760     for default_os in defaults {
761         if let Some(default_s) = default_os.to_str() {
762             if !arg.possible_vals.is_empty() {
763                 if let Some(delim) = arg.get_value_delimiter() {
764                     for part in default_s.split(delim) {
765                         assert!(
766                             arg.possible_vals.iter().any(|possible_val| {
767                                 possible_val.matches(part, arg.is_ignore_case_set())
768                             }),
769                             "Argument `{}`'s {}={} doesn't match possible values",
770                             arg.name,
771                             field,
772                             part
773                         )
774                     }
775                 } else {
776                     assert!(
777                         arg.possible_vals.iter().any(|possible_val| {
778                             possible_val.matches(default_s, arg.is_ignore_case_set())
779                         }),
780                         "Argument `{}`'s {}={} doesn't match possible values",
781                         arg.name,
782                         field,
783                         default_s
784                     );
785                 }
786             }
787 
788             if let Some(validator) = arg.validator.as_ref() {
789                 let mut validator = validator.lock().unwrap();
790                 if let Some(delim) = arg.get_value_delimiter() {
791                     for part in default_s.split(delim) {
792                         if let Err(err) = validator(part) {
793                             panic!(
794                                 "Argument `{}`'s {}={} failed validation: {}",
795                                 arg.name, field, part, err
796                             );
797                         }
798                     }
799                 } else if let Err(err) = validator(default_s) {
800                     panic!(
801                         "Argument `{}`'s {}={} failed validation: {}",
802                         arg.name, field, default_s, err
803                     );
804                 }
805             }
806         }
807 
808         if let Some(validator) = arg.validator_os.as_ref() {
809             let mut validator = validator.lock().unwrap();
810             if let Some(delim) = arg.get_value_delimiter() {
811                 let default_os = RawOsStr::new(default_os);
812                 for part in default_os.split(delim) {
813                     if let Err(err) = validator(&part.to_os_str()) {
814                         panic!(
815                             "Argument `{}`'s {}={:?} failed validation: {}",
816                             arg.name, field, part, err
817                         );
818                     }
819                 }
820             } else if let Err(err) = validator(default_os) {
821                 panic!(
822                     "Argument `{}`'s {}={:?} failed validation: {}",
823                     arg.name, field, default_os, err
824                 );
825             }
826         }
827 
828         let value_parser = arg.get_value_parser();
829         let assert_cmd = Command::new("assert");
830         if let Some(delim) = arg.get_value_delimiter() {
831             let default_os = RawOsStr::new(default_os);
832             for part in default_os.split(delim) {
833                 if let Err(err) = value_parser.parse_ref(&assert_cmd, Some(arg), &part.to_os_str())
834                 {
835                     panic!(
836                         "Argument `{}`'s {}={:?} failed validation: {}",
837                         arg.name,
838                         field,
839                         part.to_str_lossy(),
840                         err
841                     );
842                 }
843             }
844         } else if let Err(err) = value_parser.parse_ref(&assert_cmd, Some(arg), default_os) {
845             panic!(
846                 "Argument `{}`'s {}={:?} failed validation: {}",
847                 arg.name, field, default_os, err
848             );
849         }
850     }
851 }
852