[go: up one dir, main page]

ap/
args.rs

1// Copyright (c) 2021 James O. D. Hunt.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6use std::cell::RefCell;
7use std::collections::{hash_map::Entry, HashMap};
8use std::env;
9use std::fmt;
10use std::io::Write;
11use std::rc::Rc;
12
13use crate::error::{Error, Result};
14
15const OPT_PREFIX: char = '-';
16const HELP_OPTION: &str = "-h";
17
18/// String to show in usage if an option is required
19const REQUIRED_STR: &str = " (required)";
20
21/// Special argument that is silently consumed and used to denote the end of
22/// all options; all arguments that follow are considered to be positional
23/// arguments (even if they start with `-`!)
24///
25/// See: `getopt(3)`.
26const END_OF_OPTIONS: &str = "--";
27const LONG_OPT_PREFIX: &str = END_OF_OPTIONS;
28
29/// If an [Arg] is registered with this value, all positional (non-option)
30/// arguments will be passed to the handler.
31//
32/// # Notes
33///
34/// - *Similar* to [Settings::ignore_unknown_posn_args], but whereas that
35///   option will entirely ignore positional arguments, this feature will
36///   redirect them to your handler for processing.
37pub const POSITIONAL_HANDLER_OPT: char = '"';
38
39/// Special value that if registered as an [Arg] will pass all unknown options
40/// to the handler to all it to deal with them. When the handler is called in
41/// this scenario, [Arg.option] will be set to [UNKNOWN_OPTION_HANDLER_OPT].
42///
43/// # Notes
44///
45/// - *Similar* to [Settings::ignore_unknown_options], but whereas that
46///   option will entirely ignore unknown options, this feature will redirect
47///   unknown options to your handler for processing.
48/// - You probably don't want to have to deal with this. But if you are
49///   sure, read on...
50/// - Since the option is not registered, the option is treated
51///   as a flag. To handle unknown "normal options" with an argument,
52///   you would need to register an [Arg] for [POSITIONAL_HANDLER_OPT] too.
53///   It would then be up to your handler to decide if the unknown option was
54///   a "normal option", or a flag. If it was a normal option, the handler would
55///   need to save some state and look at the next argument provided to the
56///   handler which, assuming it is a non-option would be either the unknown
57///   option's argument, or a positional argument.
58pub const UNKNOWN_OPTION_HANDLER_OPT: char = '?';
59
60const USAGE_PREFIX_SPACES: &str = "    ";
61
62/// Used to specify whether an option is a "stand-alone" flag option
63/// (needs no value), or whether it requires an option argument.
64#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)]
65pub enum Need {
66    /// Option is stand-alone (no argument required).
67    Nothing,
68    /// Option needs an argument.
69    Argument,
70}
71
72impl Default for Need {
73    fn default() -> Self {
74        Need::Nothing
75    }
76}
77
78impl Need {
79    /// Create a new default requirement for an [Arg].
80    pub fn new() -> Self {
81        Need::default()
82    }
83}
84
85/// Trait that an argument handler must implement.
86pub trait Handler {
87    /// Function that will handle all registered options.
88    ///
89    /// Since the handler is provided with a mutable reference to itself,
90    /// it can store and modify its state when called.
91    ///
92    /// # Parameters
93    ///
94    /// `arg` - The [Arg] provides details of the argument found
95    ///         on the command-line.
96    ///
97    /// # Return value
98    //
99    /// - If the handler logic succeeds, return `Ok(())`.
100    /// - If the handler needs to fail, it should return one of the [Error]
101    ///   values. If the main errors are not appropriate, make the handler
102    ///   return [Error::HandlerError].
103    ///
104    /// # Notes
105    ///
106    /// If a handler call fails, the command-line parsing will
107    /// stop and the error will be returned to the caller of the parsing function.
108    fn handle(&mut self, arg: Arg) -> Result<()>;
109}
110
111impl<'a> fmt::Debug for dyn Handler + 'a {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        write!(f, "Handler: {:p}", self)
114    }
115}
116
117impl<'a> PartialEq for Box<dyn Handler + 'a> {
118    fn eq(&self, other: &Box<dyn Handler + 'a>) -> bool {
119        self == other
120    }
121}
122
123/// An argument, either an option or a positional argument.
124///
125/// 1) It is used to specify how an argument is to be handled.
126///
127///    If it is to be considered an option, the [Arg.option]
128///    member should be set.
129///
130/// 2) To store the results of the parse for the argument.
131///
132///    For example, the parser records the number of times the argument was
133///    handled in the `count` member.
134///
135/// # Note
136///
137/// - All members are public for handler convenience.
138#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
139pub struct Arg {
140    /// Single character short option name (required).
141    /// Can be set to special values for non-standard behaviour:
142    ///
143    /// - [POSITIONAL_HANDLER_OPT] (to handle positional arguments).
144    /// - [UNKNOWN_OPTION_HANDLER_OPT] (to handle unknown options).
145    pub option: char,
146    /// Type of option (required, but defaults).
147    pub needs: Need,
148    /// Description of the option.
149    pub help: Option<String>,
150    /// Set if the option must be specified.
151    pub required: bool,
152
153    //----------------------------------------
154    // The following are set by the parser.
155    //----------------------------------------
156    /// Value specified for this option
157    /// (if the `needs` member is not [Need::Nothing]).
158    ///
159    /// # Notes
160    ///
161    /// - This is equivalent to `getopt(3)`'s `optarg` value.
162    /// - This will be [None] for flag options.
163    pub value: Option<String>,
164    /// Number of times the option was specified.
165    ///
166    /// # Notes
167    ///
168    /// - Used internally for [Error::MissingReqOpt].
169    /// - If a positional argument handler has been registered,
170    ///   value will be incremented for each positional argument specified.
171    /// - This is _similar_ to `getopt(3)`'s `optind` value, but rather than
172    ///   being the overall index, it is a value incremented each time the
173    ///   particular option is specified on the command-line.
174    pub count: usize,
175}
176
177impl Arg {
178    /// Create a new argument handler.
179    pub fn new(option: char) -> Self {
180        Arg::default().option(option)
181    }
182
183    /// Specify the option character (name) for the option.
184    pub fn option(self, option: char) -> Self {
185        Arg { option, ..self }
186    }
187
188    /// Specify the requirement for the option.
189    pub fn needs(self, needs: Need) -> Self {
190        Arg { needs, ..self }
191    }
192
193    /// Specify the help text for the option.
194    pub fn help(self, help: &str) -> Self {
195        Arg {
196            help: Some(help.into()),
197            ..self
198        }
199    }
200
201    /// Specify that the option must be provided on the command-line.
202    pub fn required(self) -> Self {
203        Arg {
204            required: true,
205            ..self
206        }
207    }
208}
209
210impl fmt::Display for Arg {
211    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212        let value = if self.needs == Need::Argument {
213            " <value>"
214        } else {
215            ""
216        };
217
218        let required = if self.required { REQUIRED_STR } else { "" };
219
220        let help: String = match &self.help {
221            Some(help) => format!(" # {}", help),
222            _ => "".into(),
223        };
224
225        write!(
226            f,
227            "{}{}{}{}{}",
228            OPT_PREFIX, self.option, value, required, help
229        )
230    }
231}
232
233/// Settings used to control the parsers behaviour.
234#[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd, Default, PartialEq)]
235pub struct Settings {
236    /// If set, ignore any unknown options; by default an unknown option is
237    /// considered an error.
238    ignore_unknown_options: bool,
239
240    /// If set and no [POSITIONAL_HANDLER_OPT] [Arg] has been registered,
241    /// ignore positional arguments rather than erroring.
242    ignore_unknown_posn_args: bool,
243
244    /// Don't automatically consume the argument immediately _after_
245    /// a [Need::Argument] option. This effectively stops option _values_ from
246    /// starting with a dash which is permitted by `getopt(3)`.
247    ///
248    /// > **Notes:** Setting this to `true` means the parsing will
249    /// > no longer be "`getopt`-like".
250    no_strict_options: bool,
251}
252
253impl Settings {
254    /// Create a new settings object.
255    pub fn new() -> Self {
256        Settings::default()
257    }
258
259    /// Specify that unknown options should be silently ignored
260    /// (by default, the first unknown option will generate an error).
261    pub fn ignore_unknown_options(self) -> Self {
262        Settings {
263            ignore_unknown_options: true,
264            ..self
265        }
266    }
267
268    /// Specify that unknown positional arguments should be silently ignored
269    /// (by default, they will generate an error).
270    pub fn ignore_unknown_posn_args(self) -> Self {
271        Settings {
272            ignore_unknown_posn_args: true,
273            ..self
274        }
275    }
276
277    /// By default, arguments are parsed as they would be by `getopt(3)`
278    /// whereby if an option is marked as requiring a value
279    /// ([Need::Argument]) and the option is found on the command line, the
280    /// next argument (whether it starts with a dash or not!) is "consumed" as
281    /// the options argument.
282    ///
283    /// However, when this setting is enabled, option values cannot start with
284    /// a dash.
285    ///
286    /// # Advice
287    ///
288    /// - If you want to your program to behave like the traditional `getopt(3)`,
289    ///   leave this setting unset.
290    /// - If you need your program to accept an argument starting with a dash
291    ///   (for example, you have an option which could accept a negative
292    ///   number), you should leave this setting unset.
293    /// - If your program provides options and flags and you wish to minimse
294    ///   the chance of a flag (particularly a numeric flag such as `-1` or `-2`)
295    ///   being interpreted as an options value, consider setting this option to
296    ///   disable support for option values starting with a dash.
297    ///
298    /// # Example
299    ///
300    /// If a program accepts a flag (`-f`) and an option that
301    /// requires an value (`-r <value>`) and the following command-line is
302    /// specified to the program...
303    ///
304    /// ```bash
305    /// $ prog -r -f
306    /// ```
307    ///
308    /// ... the outcome of the parse will depend on this setting:
309    ///
310    /// - If `no_strict_options=false` (the default), the command line will be
311    ///   passed successfully and the `r` option ([Arg]) will be given the value
312    ///   "`-f`" and the `f` option ([Arg]) will be considered to not have been
313    ///   specified.
314    ///
315    ///   > **Note:**
316    ///   >
317    ///   > This is how the POSIX command line argument `getopt(3)` works.
318    ///
319    /// - If `no_strict_options=true`, the parse will fail with the error
320    ///   `Error::MissingOptArg` since in this mode, option values may not begin
321    ///   with a dash so the `-f` is treated as the next argument meaning the
322    ///   user forgot to specify a value for the previous argument (`-r`), which
323    ///   is an error.
324    ///
325    ///   > **Note:**
326    ///   >
327    ///   > This is an alternative behaviour adopted by some modern
328    ///   > command line argument parsers.
329    ///
330    pub fn no_strict_options(self) -> Self {
331        Settings {
332            no_strict_options: true,
333            ..self
334        }
335    }
336}
337
338/// Get a list of all command-line arguments specified to the program with
339/// the program name (the first argument) removed.
340///
341/// # Note
342///
343/// Used with [App::parse_with_args()]. However, this isn't usually
344/// required: just call [App::parse()].
345pub fn get_args() -> Vec<String> {
346    let mut args: Vec<String> = env::args().collect();
347
348    // Remove program name
349    let _ = args.remove(0);
350
351    args
352}
353
354/// Represents a collection of arguments.
355#[derive(Clone, Debug, Eq, PartialEq)]
356pub struct Args {
357    /// Hash of Arg objects.
358    ///
359    /// - name: option name.
360    /// - value: the argument details for the option.
361    entries: HashMap<char, Rc<RefCell<Arg>>>,
362}
363
364impl Args {
365    /// Create a new argument collection.
366    pub fn new() -> Self {
367        Args {
368            entries: HashMap::<char, Rc<RefCell<Arg>>>::new(),
369        }
370    }
371
372    /// Returns the number of registered arguments.
373    fn len(&self) -> usize {
374        self.entries.len()
375    }
376
377    /// Convenience method to add a set of arguments in one go.
378    ///
379    /// # Note
380    ///
381    /// Used by the test code.
382    #[allow(dead_code)]
383    fn set(&mut self, args: Vec<Arg>) {
384        self.entries.clear();
385
386        for arg in args {
387            self.entries.insert(arg.option, Rc::new(RefCell::new(arg)));
388        }
389    }
390
391    /// Register a single argument.
392    pub fn add(&mut self, arg: Arg) {
393        self.entries.insert(arg.option, Rc::new(RefCell::new(arg)));
394    }
395
396    /// Determine if an [Arg] with the specified option name has been registered.
397    pub fn exists(&self, option: &char) -> bool {
398        self.entries.get(option).is_some()
399    }
400
401    /// Returns the [Arg] with the specified option name.
402    pub fn get(&self, option: char) -> Option<Arg> {
403        // XXX: Lookup the value in the hash. If found, unwrap it, deref the
404        // RefCell ("borrow()") and re-wrap as an Option!
405        self.entries.get(&option).map(|a| a.borrow().clone())
406    }
407}
408
409impl Default for Args {
410    /// Create a default argument handlers object.
411    fn default() -> Self {
412        Self::new()
413    }
414}
415
416/// The main object used to represent the program.
417///
418/// All consumers of the crate need to create a
419/// single object of this type.
420#[derive(Clone, Default, Debug, PartialEq)]
421pub struct App<'a> {
422    name: String,
423    version: String,
424    summary: String,
425    help: String,
426    notes: String,
427    settings: Settings,
428    args: Args,
429    handler: Option<Rc<RefCell<Box<dyn Handler + 'a>>>>,
430}
431
432impl<'a> App<'a> {
433    /// Create a new application object.
434    pub fn new(name: &str) -> Self {
435        App::default().name(name)
436    }
437
438    /// Specify the version of the program.
439    fn name(self, name: &str) -> Self {
440        App {
441            name: name.into(),
442            ..self
443        }
444    }
445
446    /// Specify a set of argument handlers to parse the command-line with.
447    pub fn args(self, args: Args) -> Self {
448        App { args, ..self }
449    }
450
451    /// Specify the version of the program.
452    pub fn version(self, version: &str) -> Self {
453        App {
454            version: version.into(),
455            ..self
456        }
457    }
458
459    /// Specify brief explanatory text for the program.
460    pub fn summary(self, summary: &str) -> Self {
461        App {
462            summary: summary.into(),
463            ..self
464        }
465    }
466
467    /// Specify extended usage information for the program.
468    pub fn help(self, help: &str) -> Self {
469        App {
470            help: help.into(),
471            ..self
472        }
473    }
474
475    /// Specify notes for the program.
476    pub fn notes(self, notes: &str) -> Self {
477        App {
478            notes: notes.into(),
479            ..self
480        }
481    }
482
483    /// Specify any settings for the program.
484    pub fn settings(self, settings: Settings) -> Self {
485        App { settings, ..self }
486    }
487
488    /// If set, don't error if unknown options are specified - just
489    /// ignore them.
490    ///
491    /// # Note
492    ///
493    /// This is an alternative to calling the `settings()` method.
494    pub fn ignore_unknown_options(self) -> Self {
495        App {
496            settings: Settings {
497                ignore_unknown_options: true,
498                ..Default::default()
499            },
500            ..self
501        }
502    }
503
504    /// If set, don't error if unknown positional arguments are specified - just
505    /// ignore them.
506    ///
507    /// # Note
508    ///
509    /// This is an alternative to calling the `settings()` method.
510    pub fn ignore_unknown_posn_args(self) -> Self {
511        App {
512            settings: Settings {
513                ignore_unknown_posn_args: true,
514                ..Default::default()
515            },
516            ..self
517        }
518    }
519
520    /// If set, disallow option values from starting with as dash.
521    ///
522    /// See the [Settings] method of the same name for full details
523    /// and an example showing the effect of this call.
524    ///
525    /// # Note
526    ///
527    /// This is an alternative to calling the `settings()` method.
528    pub fn no_strict_options(self) -> Self {
529        App {
530            settings: Settings {
531                no_strict_options: true,
532                ..Default::default()
533            },
534            ..self
535        }
536    }
537
538    /// Generate a help/usage statement from the registered [Arg]'s.
539    ///
540    /// This is called automatically when the user specifies `-h` _anywhere_
541    /// on the command line; you do not need to register an [Arg] for `-h`.
542    pub fn generate_help<W>(&self, writer: &mut W) -> Result<()>
543    where
544        W: Write + Send + Sync + 'static,
545    {
546        let mut lines = Vec::<String>::new();
547        let mut flag_lines = Vec::<String>::new();
548        let mut option_lines = Vec::<String>::new();
549
550        let mut keys: Vec<char> = self
551            .args
552            .entries
553            .iter()
554            .map(|(key, _)| *key)
555            .filter(|k| *k != POSITIONAL_HANDLER_OPT)
556            .collect();
557
558        keys.sort_unstable();
559
560        //------------------------------------------------------------
561        // Look for flags
562
563        for key in keys.clone() {
564            // Note: unwrap safe as 'keys' must be valid.
565            let arg_ref = self.args.entries.get(&key).unwrap();
566
567            let arg = arg_ref.borrow();
568
569            if arg.needs == Need::Nothing {
570                let line = format!("{}{}", USAGE_PREFIX_SPACES, arg.to_string());
571                flag_lines.push(line);
572            }
573        }
574
575        //------------------------------------------------------------
576        // Look for options
577
578        for key in keys {
579            let arg_ref = self.args.entries.get(&key).unwrap();
580
581            let arg = arg_ref.borrow();
582
583            if arg.needs != Need::Nothing {
584                let line = format!("{}{}", USAGE_PREFIX_SPACES, arg.to_string());
585                option_lines.push(line);
586            }
587        }
588
589        //------------------------------------------------------------
590
591        let line = format!("NAME:\n{}{}\n", USAGE_PREFIX_SPACES, self.name);
592        lines.push(line);
593
594        if !self.version.is_empty() {
595            let line = format!("VERSION:\n{}{}\n", USAGE_PREFIX_SPACES, self.version);
596            lines.push(line);
597        }
598
599        if !self.summary.is_empty() {
600            let line = format!("SUMMARY:\n{}{}\n", USAGE_PREFIX_SPACES, self.summary.trim());
601            lines.push(line);
602        }
603
604        let have_posn_handler = self.args.get(POSITIONAL_HANDLER_OPT).is_some();
605
606        let posn_args = match have_posn_handler {
607            true => " [ARGUMENT]...",
608            false => "",
609        };
610
611        lines.push("USAGE:".into());
612
613        let name: String = if self.name.is_empty() {
614            env::args().collect::<Vec<String>>().pop().unwrap()
615        } else {
616            self.name.clone()
617        };
618
619        let have_flags = !flag_lines.is_empty();
620        let have_options = !option_lines.is_empty();
621
622        let option_types = if have_flags && have_options {
623            "[FLAG/OPTION]..."
624        } else if have_flags {
625            "[FLAG]..."
626        } else if have_options {
627            "[OPTION]..."
628        } else {
629            ""
630        };
631
632        // Show what type of arguments the program supports.
633        let line = format!(
634            "{}{} {}{}\n",
635            USAGE_PREFIX_SPACES, name, option_types, posn_args
636        );
637
638        lines.push(line);
639
640        //------------------------------------------------------------
641
642        if !flag_lines.is_empty() {
643            lines.push("FLAGS:".into());
644
645            lines.extend_from_slice(&flag_lines);
646        }
647
648        if !option_lines.is_empty() {
649            lines.push("\nOPTIONS:".into());
650
651            lines.extend_from_slice(&option_lines);
652        }
653
654        //------------------------------------------------------------
655
656        let pos_arg = self.args.entries.get(&POSITIONAL_HANDLER_OPT);
657        if let Some(arg) = pos_arg {
658            lines.push("\nPOSITIONAL ARGUMENTS:\n".into());
659
660            // Extract the raw text to avoid the formatted Display version of
661            // Arg (which exposes the value of POSITIONAL_HANDLER_OPT and
662            // which also looks ugly).
663            if let Some(help_text) = arg.borrow().help.as_ref() {
664                lines.push(help_text.trim().into());
665            } else {
666                lines.push("Supported.".into());
667            }
668        }
669
670        //------------------------------------------------------------
671
672        if !self.help.is_empty() {
673            let line = format!("\nHELP:\n\n{}", self.help.trim());
674            lines.push(line);
675        }
676
677        if !self.notes.is_empty() {
678            let line = format!("\nNOTES:\n\n{}", self.notes.trim());
679            lines.push(line);
680        }
681
682        // Join all the lines together, remove white space at either and and
683        // finally append a single newline.
684        let mut final_lines = lines.join("\n").trim().to_string();
685        final_lines.push('\n');
686
687        writeln!(writer, "{}", final_lines)?;
688
689        Ok(())
690    }
691
692    /// Parse a set of command line arguments (without the program name).
693    ///
694    /// # Arguments
695    ///
696    /// - `cli_args`: Vector of string arguments. Specify your own,
697    ///    or call [get_args()].
698    ///
699    /// # Notes
700    ///
701    /// - The `cli_args` vector must _not_ specify the command name (which by default
702    ///   is returned as the first element by `env::args().collect()` for example.
703    ///   Use [get_args()] as this handles this for you.
704    ///
705    pub fn parse_with_args(&mut self, cli_args: Vec<String>) -> Result<()> {
706        let mut need = Need::new();
707        let mut end_of_options = false;
708
709        // The short option name for the option that is currently being
710        // handled. This will be None for flags and will only be set for
711        // options if a handler has been specified.
712        //
713        // Ideally, we'd save a reference to the Arg, but there be dragons due
714        // to multiple mutable borrows.
715        let mut current_option: Option<char> = None;
716
717        // Show help if requested.
718        for cli_arg in cli_args.iter() {
719            match cli_arg.as_str() {
720                HELP_OPTION => return self.generate_help(&mut std::io::stdout()),
721                // No more options so help was not requested
722                END_OF_OPTIONS => break,
723                _ => (),
724            }
725        }
726
727        if self.handler.is_none() {
728            return Err(Error::NoHandler);
729        }
730
731        if self.args.len() == 0 {
732            return Err(Error::NoArgs);
733        }
734
735        for (_i, cli_arg) in cli_args.iter().enumerate() {
736            if cli_arg.starts_with(OPT_PREFIX) && !end_of_options {
737                // Found an option argument
738
739                if cli_arg == END_OF_OPTIONS {
740                    end_of_options = true;
741                    continue;
742                }
743
744                // Handle the (relatively rare) scenario where a option's
745                // _value_ starts with a dash.
746                if !self.settings.no_strict_options {
747                    if let Some(option) = current_option {
748                        if need == Need::Argument {
749                            if let Entry::Occupied(entry) = self.args.entries.entry(option) {
750                                let mut arg = entry.get().borrow_mut();
751
752                                // Save the value found
753                                arg.value = Some(cli_arg.into());
754
755                                if let Some(h) = self.handler.clone() {
756                                    // Call the handler
757                                    arg.count += 1;
758                                    h.borrow_mut().handle(arg.clone())?;
759                                }
760
761                                // Job done
762                                need = Need::Nothing;
763                                current_option = None;
764                                continue;
765                            }
766                        }
767                    }
768                }
769
770                if cli_arg.starts_with(LONG_OPT_PREFIX) {
771                    return Err(Error::NoLongOpts);
772                }
773
774                let mut chars = cli_arg.chars();
775
776                if cli_arg.len() > 2 {
777                    let option_name = *chars.nth(1).as_ref().unwrap();
778
779                    if option_name.is_ascii_whitespace() {
780                        return Err(Error::MissingOptName);
781                    } else {
782                        return Err(Error::NoBundling);
783                    }
784                }
785
786                let option = chars.nth(1).ok_or(Error::MissingOptName)?;
787
788                if need == Need::Argument {
789                    return Err(Error::MissingOptArg);
790                }
791
792                if let Entry::Occupied(entry) = self.args.entries.entry(option) {
793                    let arg_ref = entry.get();
794
795                    let mut arg = arg_ref.borrow_mut();
796
797                    need = arg.needs;
798
799                    if need == Need::Nothing {
800                        if let Some(h) = self.handler.clone() {
801                            // Call the handler
802                            arg.count += 1;
803                            h.borrow_mut().handle(arg.clone())?;
804                        }
805                    } else if need == Need::Argument {
806                        // Record the fact that we're "in the middle" of handling
807                        // a particular option and that the next argument will
808                        // be this options value.
809                        current_option = Some(arg.option);
810                    }
811                } else if let Entry::Occupied(entry) =
812                    self.args.entries.entry(UNKNOWN_OPTION_HANDLER_OPT)
813                {
814                    let arg_ref = entry.get();
815
816                    let mut arg = arg_ref.borrow_mut();
817
818                    if let Some(h) = self.handler.clone() {
819                        // Call the handler
820                        arg.count += 1;
821
822                        // Pass a copy of the unknown Arg (which is
823                        // generic) to the handler function for the _specific_
824                        // unknown option found.
825                        //
826                        // This is simple, but has the downside of not having
827                        // an accurate `.count` value. We could handle this in
828                        // a better way (maybe by adding an `Arg` for each
829                        // unknown option found?), but if we do that, we
830                        // should also mark those `Arg`'s somehow to show they
831                        // were "auto-added" rather than being added by the
832                        // caller.
833                        let mut option_specific = arg.clone();
834                        option_specific.option = option;
835
836                        h.borrow_mut().handle(option_specific)?;
837                    }
838                } else if self.settings.ignore_unknown_options {
839                    continue;
840                } else {
841                    return Err(Error::UnknownOpt);
842                }
843            } else if let Some(option) = current_option {
844                if let Entry::Occupied(entry) = self.args.entries.entry(option) {
845                    let mut arg = entry.get().borrow_mut();
846
847                    // Save the value found
848                    arg.value = Some(cli_arg.into());
849
850                    if let Some(h) = self.handler.clone() {
851                        // Call the handler
852                        arg.count += 1;
853                        h.borrow_mut().handle(arg.clone())?;
854                    }
855                } else {
856                    // This strictly is an "impossible" situation whereby
857                    // a previously registered handler was somehow removed.
858                    return Err(Error::NoHandler);
859                }
860
861                // Job done
862                need = Need::Nothing;
863                current_option = None;
864            } else {
865                // Positional (non-option) parameter
866                if let Entry::Occupied(entry) = self.args.entries.entry(POSITIONAL_HANDLER_OPT) {
867                    let arg_ref = entry.get();
868
869                    let mut arg = arg_ref.borrow_mut();
870
871                    // Found the option value, so save it
872                    arg.value = Some(cli_arg.into());
873
874                    if let Some(h) = self.handler.clone() {
875                        // Call the handler
876                        arg.count += 1;
877                        h.borrow_mut().handle(arg.clone())?;
878                    }
879                } else if !self.settings.ignore_unknown_posn_args {
880                    // After all options have been handled, anything
881                    // can follow.
882                    if !end_of_options {
883                        return Err(Error::NoPosnArgs);
884                    }
885                }
886
887                // Job done
888                need = Need::Nothing;
889                current_option = None;
890            }
891        }
892
893        // Final checks
894        for arg_ref in self.args.entries.values() {
895            let arg = arg_ref.borrow();
896
897            // There shouldn't be any half-handled options left
898            if let Some(option) = current_option {
899                if arg.needs == Need::Argument && option == arg.option {
900                    return Err(Error::MissingOptArg);
901                }
902            }
903
904            // Check that mandatory options were specified
905            if arg.required && arg.count == 0 {
906                return Err(Error::MissingReqOpt);
907            }
908        }
909
910        Ok(())
911    }
912
913    /// Specify the handler for the option which must implement the
914    /// [Handler] trait.
915    ///
916    /// # Note
917    ///
918    /// If the handler needs to modify its own state when called,
919    /// the specified boxed trait must provide a mutable reference.
920    pub fn handler(self, boxed_handler: Box<dyn Handler + 'a>) -> Self {
921        let boxed = Rc::new(RefCell::new(boxed_handler));
922
923        App {
924            handler: Some(boxed),
925            ..self
926        }
927    }
928
929    /// Simplest interface to the parser.
930    pub fn parse(&mut self) -> Result<()> {
931        let args = get_args();
932
933        self.parse_with_args(args)
934    }
935}
936
937#[cfg(test)]
938mod tests {
939    use super::*;
940
941    use regex::Regex;
942    use std::sync::{Arc, Mutex};
943
944    /// Writer that stores all data written to it.
945    #[derive(Default, Clone)]
946    struct BufWriter(Arc<Mutex<Vec<u8>>>);
947
948    impl std::io::Write for BufWriter {
949        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
950            self.0.lock().unwrap().write(buf)
951        }
952
953        fn flush(&mut self) -> std::io::Result<()> {
954            self.0.lock().unwrap().flush()
955        }
956    }
957
958    #[allow(dead_code)]
959    impl BufWriter {
960        fn new() -> Self {
961            BufWriter::default()
962        }
963
964        fn clear(&mut self) {
965            self.0.lock().unwrap().clear();
966        }
967
968        fn len(&mut self) -> usize {
969            self.0.lock().unwrap().len()
970        }
971
972        fn capacity(&mut self) -> usize {
973            self.0.lock().unwrap().capacity()
974        }
975    }
976
977    impl ToString for BufWriter {
978        fn to_string(&self) -> String {
979            let data_ref = self.0.clone();
980            let output = data_ref.lock().unwrap();
981            let s = (*output).clone();
982            let output = String::from_utf8(s).unwrap();
983
984            output
985        }
986    }
987
988    #[test]
989    fn test_requirement() {
990        let r1 = Need::new();
991        let r2 = Need::default();
992
993        assert_eq!(r1, Need::Nothing);
994        assert_eq!(r1, r2);
995    }
996
997    #[test]
998    fn test_settings() {
999        let new_settings = Settings::new();
1000        let def_settings = Settings::default();
1001
1002        assert_eq!(new_settings.ignore_unknown_options, false);
1003        assert_eq!(new_settings.ignore_unknown_posn_args, false);
1004        assert_eq!(new_settings.no_strict_options, false);
1005        assert_eq!(new_settings, def_settings);
1006
1007        let settings = Settings::new()
1008            .ignore_unknown_options()
1009            .ignore_unknown_posn_args()
1010            .no_strict_options();
1011
1012        assert_eq!(settings.ignore_unknown_options, true);
1013        assert_eq!(settings.ignore_unknown_posn_args, true);
1014        assert_eq!(settings.no_strict_options, true);
1015    }
1016
1017    #[test]
1018    fn test_arg() {
1019        //--------------------
1020        let default_arg = Arg::default();
1021
1022        let expected_default = Arg {
1023            option: '\u{0}',
1024            needs: Need::Nothing,
1025            help: None,
1026            required: false,
1027            value: None,
1028            count: 0,
1029        };
1030
1031        assert_eq!(default_arg, expected_default);
1032
1033        //--------------------
1034
1035        let new_arg = Arg::new('a');
1036
1037        let expected_new = Arg {
1038            option: 'a',
1039            needs: Need::Nothing,
1040            help: None,
1041            required: false,
1042            value: None,
1043            count: 0,
1044        };
1045
1046        assert_eq!(new_arg, expected_new);
1047
1048        //--------------------
1049
1050        let option_arg = Arg::new('a').option('b');
1051
1052        assert_eq!(option_arg.option, 'b');
1053
1054        //--------------------
1055
1056        let def_option_arg = Arg::default().option('a');
1057
1058        assert_eq!(def_option_arg.option, 'a');
1059
1060        //--------------------
1061
1062        let needs_arg = Arg::new('a').needs(Need::Argument);
1063
1064        assert_eq!(needs_arg.needs, Need::Argument);
1065
1066        //--------------------
1067
1068        let help = "some help text\nfoo bar\nthe end";
1069        let help_arg = Arg::new('a').help(help);
1070        assert_eq!(help_arg.help, Some(help.into()));
1071
1072        //--------------------
1073
1074        let required_arg = Arg::new('a').required();
1075        assert_eq!(required_arg.required, true);
1076    }
1077
1078    #[test]
1079    fn test_args() {
1080        let new_args = Args::new();
1081        let def_args = Args::default();
1082
1083        assert_eq!(new_args, def_args);
1084
1085        let mut args = Args::new();
1086
1087        assert_eq!(args.len(), 0);
1088        assert!(!args.exists(&'a'));
1089        assert!(!args.exists(&'b'));
1090        assert_eq!(args.get('a'), None);
1091        assert_eq!(args.get('b'), None);
1092
1093        let arg_1 = Arg::new('a');
1094        let arg_2 = Arg::new('b');
1095
1096        args.add(arg_1);
1097        assert_eq!(args.len(), 1);
1098        assert!(args.exists(&'a'));
1099        assert!(!args.exists(&'b'));
1100        assert!(args.get('a').is_some());
1101        assert_eq!(args.get('a').unwrap().option, 'a');
1102        assert_eq!(args.get('b'), None);
1103
1104        args.add(arg_2);
1105        assert_eq!(args.len(), 2);
1106        assert!(args.exists(&'a'));
1107        assert!(args.exists(&'b'));
1108        assert!(args.get('a').is_some());
1109        assert!(args.get('b').is_some());
1110        assert_eq!(args.get('a').unwrap().option, 'a');
1111        assert_eq!(args.get('b').unwrap().option, 'b');
1112    }
1113
1114    //----------------------------------------
1115    // Handle that always succeeds
1116
1117    #[derive(Clone, Debug, Default)]
1118    struct OkHandler {}
1119
1120    impl Handler for &OkHandler {
1121        fn handle(&mut self, arg: Arg) -> Result<()> {
1122            assert!(arg.count > 0);
1123
1124            Ok(())
1125        }
1126    }
1127
1128    impl Handler for &mut OkHandler {
1129        fn handle(&mut self, arg: Arg) -> Result<()> {
1130            assert!(arg.count > 0);
1131
1132            Ok(())
1133        }
1134    }
1135
1136    //----------------------------------------
1137    // Handle that always fails
1138
1139    #[derive(Clone, Debug, Default)]
1140    struct ErrHandler {}
1141
1142    const TEST_ERR: &str = "dang";
1143
1144    impl Handler for &ErrHandler {
1145        fn handle(&mut self, arg: Arg) -> Result<()> {
1146            assert!(arg.count > 0);
1147
1148            Err(Error::GenericError(TEST_ERR.into()))
1149        }
1150    }
1151
1152    impl Handler for &mut ErrHandler {
1153        fn handle(&mut self, _arg: Arg) -> Result<()> {
1154            Err(Error::GenericError(TEST_ERR.into()))
1155        }
1156    }
1157
1158    //----------------------------------------
1159    // Handle that modifies itself
1160
1161    #[derive(Clone, Debug, Default, PartialEq)]
1162    struct ModifyHandler {
1163        // Some random fields to demonstrate behaviour
1164        i: usize,
1165        v: Vec<String>,
1166        s: String,
1167
1168        // Overall count of options parsed
1169        count: usize,
1170
1171        a_count: usize,
1172        b_count: usize,
1173        d_count: usize,
1174        e_count: usize,
1175        r_count: usize,
1176    }
1177
1178    const INT_INCREMENT: usize = 17;
1179    const HANDLER_SET_MSG: &str = "set by handler";
1180
1181    impl Handler for &mut ModifyHandler {
1182        fn handle(&mut self, arg: Arg) -> Result<()> {
1183            assert!(arg.count > 0);
1184
1185            self.count += arg.count;
1186
1187            self.i += INT_INCREMENT;
1188            self.s = HANDLER_SET_MSG.into();
1189
1190            if let Some(value) = arg.value {
1191                self.v.push(value);
1192            }
1193
1194            match arg.option {
1195                'a' => self.a_count += 1,
1196                'b' => self.b_count += 1,
1197                'd' => self.d_count += 1,
1198                'e' => self.e_count += 1,
1199                'r' => self.r_count += 1,
1200                _ => (),
1201            };
1202
1203            Ok(())
1204        }
1205    }
1206
1207    #[test]
1208    fn test_parse_with_args() {
1209        #[derive(Debug)]
1210        struct TestData<'a> {
1211            cli_args: Vec<&'a str>,
1212            args: Option<Vec<Arg>>,
1213            use_handler: bool,
1214            result: Result<()>,
1215        }
1216
1217        let mut ok_handler = OkHandler::default();
1218
1219        let need_arg_opt_1 = Arg::new('a').needs(Need::Argument);
1220        let need_arg_opt_2 = Arg::new('b').needs(Need::Argument);
1221        let need_arg_opt_3 = Arg::new('3').needs(Need::Argument);
1222
1223        let flag_opt = Arg::new('d').needs(Need::Nothing);
1224        let flag_opt_2 = Arg::new('人').needs(Need::Nothing);
1225        let flag_opt_3 = Arg::new('0').needs(Need::Nothing);
1226
1227        let required_flag_opt = Arg::new('e').needs(Need::Nothing).required();
1228        let required_need_arg_opt = Arg::new('r').needs(Need::Argument).required();
1229
1230        let tests = &[
1231            TestData {
1232                cli_args: vec![],
1233                args: None,
1234                use_handler: false,
1235                result: Err(Error::NoHandler),
1236            },
1237            TestData {
1238                cli_args: vec![],
1239                args: None,
1240                use_handler: true,
1241                result: Err(Error::NoArgs),
1242            },
1243            TestData {
1244                cli_args: vec![],
1245                args: Some(vec![need_arg_opt_1.clone()]),
1246                use_handler: true,
1247                result: Ok(()),
1248            },
1249            TestData {
1250                cli_args: vec![],
1251                args: Some(vec![need_arg_opt_1.clone(), need_arg_opt_2.clone()]),
1252                use_handler: true,
1253                result: Ok(()),
1254            },
1255            TestData {
1256                cli_args: vec![],
1257                args: Some(vec![required_flag_opt.clone()]),
1258                use_handler: true,
1259                result: Err(Error::MissingReqOpt),
1260            },
1261            TestData {
1262                cli_args: vec![],
1263                args: Some(vec![need_arg_opt_1.clone(), required_flag_opt.clone()]),
1264                use_handler: true,
1265                result: Err(Error::MissingReqOpt),
1266            },
1267            TestData {
1268                cli_args: vec![],
1269                args: Some(vec![required_need_arg_opt.clone()]),
1270                use_handler: true,
1271                result: Err(Error::MissingReqOpt),
1272            },
1273            TestData {
1274                cli_args: vec!["-"],
1275                args: Some(vec![flag_opt.clone()]),
1276                use_handler: true,
1277                result: Err(Error::MissingOptName),
1278            },
1279            TestData {
1280                // Weird
1281                cli_args: vec!["- -"],
1282                args: Some(vec![flag_opt.clone()]),
1283                use_handler: true,
1284                result: Err(Error::MissingOptName),
1285            },
1286            TestData {
1287                // Weird
1288                cli_args: vec!["- - "],
1289                args: Some(vec![flag_opt.clone()]),
1290                use_handler: true,
1291                result: Err(Error::MissingOptName),
1292            },
1293            TestData {
1294                // Odd positional argument
1295                cli_args: vec![" - "],
1296                args: Some(vec![flag_opt.clone()]),
1297                use_handler: true,
1298                result: Err(Error::NoPosnArgs),
1299            },
1300            TestData {
1301                cli_args: vec![END_OF_OPTIONS],
1302                args: Some(vec![flag_opt.clone()]),
1303                use_handler: true,
1304                result: Ok(()),
1305            },
1306            TestData {
1307                // Odd positional argument
1308                cli_args: vec![" -"],
1309                args: Some(vec![flag_opt.clone()]),
1310                use_handler: true,
1311                result: Err(Error::NoPosnArgs),
1312            },
1313            TestData {
1314                // Another odd positional argument
1315                cli_args: vec![" --"],
1316                args: Some(vec![flag_opt.clone()]),
1317                use_handler: true,
1318                result: Err(Error::NoPosnArgs),
1319            },
1320            TestData {
1321                // Another odd positional argument
1322                cli_args: vec![" ---"],
1323                args: Some(vec![flag_opt.clone()]),
1324                use_handler: true,
1325                result: Err(Error::NoPosnArgs),
1326            },
1327            TestData {
1328                // Another odd positional argument
1329                cli_args: vec![" --- "],
1330                args: Some(vec![flag_opt.clone()]),
1331                use_handler: true,
1332                result: Err(Error::NoPosnArgs),
1333            },
1334            TestData {
1335                // An invalid long option
1336                cli_args: vec!["---"],
1337                args: Some(vec![flag_opt.clone()]),
1338                use_handler: true,
1339                result: Err(Error::NoLongOpts),
1340            },
1341            TestData {
1342                cli_args: vec!["--notsupported"],
1343                args: Some(vec![flag_opt.clone()]),
1344                use_handler: true,
1345                result: Err(Error::NoLongOpts),
1346            },
1347            TestData {
1348                cli_args: vec!["--not-supported"],
1349                args: Some(vec![flag_opt.clone()]),
1350                use_handler: true,
1351                result: Err(Error::NoLongOpts),
1352            },
1353            TestData {
1354                cli_args: vec![],
1355                args: Some(vec![required_flag_opt.clone()]),
1356                use_handler: true,
1357                result: Err(Error::MissingReqOpt),
1358            },
1359            TestData {
1360                cli_args: vec![],
1361                args: Some(vec![required_need_arg_opt.clone()]),
1362                use_handler: true,
1363                result: Err(Error::MissingReqOpt),
1364            },
1365            TestData {
1366                cli_args: vec!["--", "-r"],
1367                args: Some(vec![required_need_arg_opt.clone()]),
1368                use_handler: true,
1369                result: Err(Error::MissingReqOpt),
1370            },
1371            TestData {
1372                cli_args: vec!["-r"],
1373                args: Some(vec![required_need_arg_opt.clone()]),
1374                use_handler: true,
1375                result: Err(Error::MissingOptArg),
1376            },
1377            TestData {
1378                cli_args: vec!["-r", "--"],
1379                args: Some(vec![required_need_arg_opt.clone()]),
1380                use_handler: true,
1381                result: Err(Error::MissingOptArg),
1382            },
1383            TestData {
1384                cli_args: vec![],
1385                args: Some(vec![required_flag_opt.clone()]),
1386                use_handler: true,
1387                result: Err(Error::MissingReqOpt),
1388            },
1389            TestData {
1390                cli_args: vec!["-r"],
1391                args: Some(vec![required_need_arg_opt.clone()]),
1392                use_handler: true,
1393                result: Err(Error::MissingOptArg),
1394            },
1395            TestData {
1396                cli_args: vec!["-r", "--"],
1397                args: Some(vec![required_need_arg_opt.clone()]),
1398                use_handler: true,
1399                result: Err(Error::MissingOptArg),
1400            },
1401            TestData {
1402                cli_args: vec!["-r"],
1403                args: Some(vec![required_need_arg_opt.clone()]),
1404                use_handler: true,
1405                result: Err(Error::MissingOptArg),
1406            },
1407            TestData {
1408                cli_args: vec!["-r", "foo"],
1409                args: Some(vec![required_need_arg_opt.clone()]),
1410                use_handler: true,
1411                result: Ok(()),
1412            },
1413            TestData {
1414                cli_args: vec!["-3", "three", "-0"],
1415                args: Some(vec![need_arg_opt_3.clone(), flag_opt_3.clone()]),
1416                use_handler: true,
1417                result: Ok(()),
1418            },
1419            TestData {
1420                cli_args: vec!["-人"],
1421                args: Some(vec![flag_opt_2.clone()]),
1422                use_handler: true,
1423                // Since the UTF-8 char is >1 byte long and we don't support
1424                // unicode chars.
1425                result: Err(Error::NoBundling),
1426            },
1427            TestData {
1428                cli_args: vec!["-ab"],
1429                args: Some(vec![flag_opt.clone()]),
1430                use_handler: true,
1431                result: Err(Error::NoBundling),
1432            },
1433            TestData {
1434                cli_args: vec!["-abc"],
1435                args: Some(vec![flag_opt.clone()]),
1436                use_handler: true,
1437                result: Err(Error::NoBundling),
1438            },
1439            TestData {
1440                cli_args: vec!["--", "-abc"],
1441                args: Some(vec![flag_opt.clone()]),
1442                use_handler: true,
1443                result: Ok(()),
1444            },
1445            TestData {
1446                cli_args: vec!["--", "abc", "def", "hello world", "--wibble", "-abc"],
1447                args: Some(vec![flag_opt.clone()]),
1448                use_handler: true,
1449                result: Ok(()),
1450            },
1451            TestData {
1452                cli_args: vec!["--foo"],
1453                args: Some(vec![flag_opt.clone()]),
1454                use_handler: true,
1455                result: Err(Error::NoLongOpts),
1456            },
1457            TestData {
1458                cli_args: vec!["-y"],
1459                args: Some(vec![flag_opt.clone()]),
1460                use_handler: true,
1461                result: Err(Error::UnknownOpt),
1462            },
1463        ];
1464
1465        for (i, d) in tests.iter().enumerate() {
1466            // Create a string containing details of the test
1467            //
1468            // Note: Ideally we'd just format 'd', but we can't since rust
1469            // doesn't implement Debug for (all) function pointers at the time
1470            // of writing.
1471            let msg = format!("test[{}]: {:?}", i, d);
1472
1473            let string_args = d.cli_args.clone().into_iter().map(String::from).collect();
1474
1475            let mut app: App;
1476
1477            if d.use_handler {
1478                app = App::default().handler(Box::new(&mut ok_handler));
1479            } else {
1480                app = App::default();
1481            }
1482
1483            let mut args = Args::default();
1484
1485            if let Some(a) = d.args.clone() {
1486                args.set(a);
1487            }
1488
1489            app = app.args(args);
1490
1491            // Call the function under test
1492            let result = app.parse_with_args(string_args);
1493
1494            // Update the test details string with the results of the call
1495            let msg = format!("{}, result: {:?}", msg, result);
1496
1497            // Perform the checks
1498            if d.result.is_ok() {
1499                assert!(result.is_ok(), "{}", msg);
1500                continue;
1501            }
1502
1503            assert!(result.is_err(), "{}", msg);
1504
1505            let expected_err = format!("{:?}", d.result.as_ref().err());
1506            let actual_err = format!("{:?}", result.as_ref().err());
1507
1508            assert_eq!(actual_err, expected_err, "{}", msg);
1509        }
1510    }
1511
1512    #[test]
1513    fn test_parse_with_handler() {
1514        #[derive(Debug)]
1515        struct TestData<'a> {
1516            cli_args: Vec<&'a str>,
1517            args: Vec<Arg>,
1518            result: Result<()>,
1519            // The expected state of the handler after parsing.
1520            handler_result: ModifyHandler,
1521        }
1522
1523        let need_arg_opt_1 = Arg::new('a').needs(Need::Argument);
1524
1525        let flag_opt = Arg::new('d').needs(Need::Nothing);
1526
1527        let tests = &[
1528            TestData {
1529                cli_args: vec![],
1530                args: vec![flag_opt.clone()],
1531                result: Ok(()),
1532                handler_result: ModifyHandler::default(),
1533            },
1534            TestData {
1535                cli_args: vec!["-d"],
1536                args: vec![flag_opt.clone()],
1537                result: Ok(()),
1538                handler_result: ModifyHandler {
1539                    i: INT_INCREMENT,
1540                    s: HANDLER_SET_MSG.into(),
1541                    count: 1,
1542                    d_count: 1,
1543                    ..ModifyHandler::default()
1544                },
1545            },
1546            TestData {
1547                cli_args: vec!["-a", "foo"],
1548                args: vec![need_arg_opt_1.clone()],
1549                result: Ok(()),
1550                handler_result: ModifyHandler {
1551                    i: INT_INCREMENT,
1552                    s: HANDLER_SET_MSG.into(),
1553                    v: vec!["foo".into()],
1554                    count: 1,
1555                    a_count: 1,
1556                    ..ModifyHandler::default()
1557                },
1558            },
1559            TestData {
1560                cli_args: vec!["-a", "foo", "-a", "bar", "-a", "baz"],
1561                args: vec![need_arg_opt_1.clone()],
1562                result: Ok(()),
1563                handler_result: ModifyHandler {
1564                    i: INT_INCREMENT * 3,
1565                    s: HANDLER_SET_MSG.into(),
1566                    v: vec!["foo".into(), "bar".into(), "baz".into()],
1567                    // XXX: arg.count was 1 initially, then 2, then 3.
1568                    count: (1 + 2 + 3),
1569                    a_count: 3,
1570                    ..ModifyHandler::default()
1571                },
1572            },
1573            TestData {
1574                cli_args: vec!["-d", "-a", "foo", "-d", "-a", "bar", "-a", "baz"],
1575                args: vec![flag_opt.clone(), need_arg_opt_1.clone()],
1576                result: Ok(()),
1577                handler_result: ModifyHandler {
1578                    i: INT_INCREMENT * 5,
1579                    s: HANDLER_SET_MSG.into(),
1580                    v: vec!["foo".into(), "bar".into(), "baz".into()],
1581                    // Values for the '-a' handler plus values for the '-d'
1582                    // handler.
1583                    count: (1 + 2 + 3) + (1 + 2),
1584                    a_count: 3,
1585                    d_count: 2,
1586                    ..ModifyHandler::default()
1587                },
1588            },
1589        ];
1590
1591        for (i, d) in tests.iter().enumerate() {
1592            let msg = format!("test[{}]: {:?}", i, d);
1593            let string_args: Vec<String> =
1594                d.cli_args.clone().into_iter().map(String::from).collect();
1595
1596            let mut args = Args::default();
1597
1598            args.set(d.args.clone());
1599
1600            let mut handler = ModifyHandler::default();
1601            let mut app = App::default().args(args).handler(Box::new(&mut handler));
1602
1603            let result = app.parse_with_args(string_args);
1604
1605            drop(app);
1606
1607            if result.is_err() {
1608                assert!(d.result.is_err(), "{}", msg);
1609
1610                let expected_err = format!("{:?}", d.result.as_ref().err());
1611                let actual_err = format!("{:?}", result.as_ref().err());
1612                assert_eq!(expected_err, actual_err, "{}", msg);
1613
1614                continue;
1615            }
1616
1617            assert!(result.is_ok(), "{}", msg);
1618            assert_eq!(d.handler_result, handler, "{}", msg);
1619        }
1620    }
1621
1622    #[test]
1623    fn test_parse_with_bad_handler() {
1624        let flag_opt = Arg::new('d').needs(Need::Nothing);
1625
1626        let mut args = Args::default();
1627        args.add(flag_opt);
1628
1629        // Handler that should fail the parse
1630        let mut handler = ErrHandler::default();
1631        let mut app = App::default().args(args).handler(Box::new(&mut handler));
1632
1633        let result = app.parse_with_args(vec!["-d".into()]);
1634        assert!(result.is_err());
1635
1636        let expected_err = format!("{:?}", Error::GenericError(TEST_ERR.into()));
1637        let actual_err = format!("{:?}", result.err().unwrap());
1638
1639        assert_eq!(expected_err, actual_err);
1640    }
1641
1642    #[test]
1643    fn test_ensure_handler_not_called_on_parse_fail() {
1644        let mut handler = ModifyHandler::default();
1645        let mut args = Args::default();
1646
1647        let need_arg_opt_1 = Arg::new('a').needs(Need::Argument);
1648        let need_arg_opt_2 = Arg::new('b').needs(Need::Argument);
1649        let flag_opt = Arg::new('d').needs(Need::Nothing);
1650
1651        args.add(flag_opt);
1652        args.add(need_arg_opt_1);
1653        args.add(need_arg_opt_2);
1654
1655        // An incorrect CLI (since the '-b' option is missing its required arg)
1656        let cli_args = vec!["-d", "-a", "foo bar", "-d", "-a", "hello world", "-b"];
1657
1658        let string_args = cli_args.clone().into_iter().map(String::from).collect();
1659
1660        let mut app = App::default().args(args).handler(Box::new(&mut handler));
1661        let result = app.parse_with_args(string_args);
1662
1663        assert!(result.is_err());
1664
1665        drop(app);
1666
1667        let expected_handler = ModifyHandler {
1668            i: INT_INCREMENT * 4,
1669            s: HANDLER_SET_MSG.into(),
1670            v: vec!["foo bar".into(), "hello world".into()],
1671            // Values for the '-a' handler plus values for the '-d'
1672            // handler.
1673            count: (1 + 2) + (1 + 2),
1674            a_count: 2,
1675            d_count: 2,
1676            b_count: 0, // XXX: Crucially, this should not be set!
1677            ..ModifyHandler::default()
1678        };
1679
1680        assert_eq!(expected_handler, handler);
1681    }
1682
1683    #[test]
1684    fn test_parse_positional_args() {
1685        let posn_arg = Arg::new(POSITIONAL_HANDLER_OPT);
1686
1687        #[derive(Debug)]
1688        struct TestData<'a> {
1689            cli_args: Vec<&'a str>,
1690            result: Result<()>,
1691            // The expected state of the handler after parsing.
1692            handler_result: ModifyHandler,
1693        }
1694
1695        let tests = &[
1696            TestData {
1697                cli_args: vec![],
1698                result: Ok(()),
1699                handler_result: ModifyHandler::default(),
1700            },
1701            TestData {
1702                cli_args: vec!["foo"],
1703                result: Ok(()),
1704                handler_result: ModifyHandler {
1705                    i: INT_INCREMENT,
1706                    v: vec!["foo".into()],
1707                    s: HANDLER_SET_MSG.into(),
1708                    count: 1,
1709                    ..Default::default()
1710                },
1711            },
1712            TestData {
1713                cli_args: vec!["\\- -"],
1714                result: Ok(()),
1715                handler_result: ModifyHandler {
1716                    i: INT_INCREMENT,
1717                    v: vec!["\\- -".into()],
1718                    s: HANDLER_SET_MSG.into(),
1719                    count: 1,
1720                    ..Default::default()
1721                },
1722            },
1723            TestData {
1724                cli_args: vec!["\\- - "],
1725                result: Ok(()),
1726                handler_result: ModifyHandler {
1727                    i: INT_INCREMENT,
1728                    v: vec!["\\- - ".into()],
1729                    s: HANDLER_SET_MSG.into(),
1730                    count: 1,
1731                    ..Default::default()
1732                },
1733            },
1734            TestData {
1735                cli_args: vec![" - "],
1736                result: Ok(()),
1737                handler_result: ModifyHandler {
1738                    i: INT_INCREMENT,
1739                    v: vec![" - ".into()],
1740                    s: HANDLER_SET_MSG.into(),
1741                    count: 1,
1742                    ..Default::default()
1743                },
1744            },
1745            TestData {
1746                cli_args: vec![" - -"],
1747                result: Ok(()),
1748                handler_result: ModifyHandler {
1749                    i: INT_INCREMENT,
1750                    v: vec![" - -".into()],
1751                    s: HANDLER_SET_MSG.into(),
1752                    count: 1,
1753                    ..Default::default()
1754                },
1755            },
1756            TestData {
1757                cli_args: vec![" - - "],
1758                result: Ok(()),
1759                handler_result: ModifyHandler {
1760                    i: INT_INCREMENT,
1761                    v: vec![" - - ".into()],
1762                    s: HANDLER_SET_MSG.into(),
1763                    count: 1,
1764                    ..Default::default()
1765                },
1766            },
1767            TestData {
1768                cli_args: vec![" -"],
1769                result: Ok(()),
1770                handler_result: ModifyHandler {
1771                    i: INT_INCREMENT,
1772                    v: vec![" -".into()],
1773                    s: HANDLER_SET_MSG.into(),
1774                    count: 1,
1775                    ..Default::default()
1776                },
1777            },
1778            TestData {
1779                cli_args: vec![" --"],
1780                result: Ok(()),
1781                handler_result: ModifyHandler {
1782                    i: INT_INCREMENT,
1783                    v: vec![" --".into()],
1784                    s: HANDLER_SET_MSG.into(),
1785                    count: 1,
1786                    ..Default::default()
1787                },
1788            },
1789            TestData {
1790                cli_args: vec![" ---"],
1791                result: Ok(()),
1792                handler_result: ModifyHandler {
1793                    i: INT_INCREMENT,
1794                    v: vec![" ---".into()],
1795                    s: HANDLER_SET_MSG.into(),
1796                    count: 1,
1797                    ..Default::default()
1798                },
1799            },
1800            TestData {
1801                cli_args: vec![" --- "],
1802                result: Ok(()),
1803                handler_result: ModifyHandler {
1804                    i: INT_INCREMENT,
1805                    v: vec![" --- ".into()],
1806                    s: HANDLER_SET_MSG.into(),
1807                    count: 1,
1808                    ..Default::default()
1809                },
1810            },
1811            TestData {
1812                cli_args: vec!["-d", "foo"],
1813                result: Err(Error::UnknownOpt),
1814                handler_result: ModifyHandler::default(),
1815            },
1816        ];
1817
1818        for (i, d) in tests.iter().enumerate() {
1819            let msg = format!("test[{}]: {:?}", i, d);
1820            let string_args: Vec<String> =
1821                d.cli_args.clone().into_iter().map(String::from).collect();
1822
1823            let mut args = Args::default();
1824            args.add(posn_arg.clone());
1825
1826            let mut handler = ModifyHandler::default();
1827            let mut app = App::default().args(args).handler(Box::new(&mut handler));
1828
1829            let result = app.parse_with_args(string_args);
1830
1831            let msg = format!("{}, result: {:?}", msg, result);
1832
1833            drop(app);
1834
1835            if result.is_err() {
1836                assert!(d.result.is_err(), "{}", msg);
1837
1838                let expected_err = format!("{:?}", d.result.as_ref().err());
1839                let actual_err = format!("{:?}", result.as_ref().err());
1840                assert_eq!(expected_err, actual_err, "{}", msg);
1841
1842                continue;
1843            }
1844
1845            assert!(result.is_ok(), "{}", msg);
1846            assert_eq!(d.handler_result, handler, "{}", msg);
1847        }
1848    }
1849
1850    #[test]
1851    fn test_parse_unknown_options() {
1852        let unknown_opts_arg = Arg::new(UNKNOWN_OPTION_HANDLER_OPT);
1853
1854        let mut args = Args::default();
1855        args.add(Arg::new('d'));
1856        args.add(unknown_opts_arg);
1857
1858        let cli_args = vec!["-d", "-a", "-b", "-r", "-d"];
1859
1860        let string_args = cli_args.clone().into_iter().map(String::from).collect();
1861
1862        let mut handler = ModifyHandler::default();
1863        assert_eq!(handler.count, 0);
1864
1865        let mut app = App::default()
1866            .args(args)
1867            .ignore_unknown_options()
1868            .handler(Box::new(&mut handler));
1869
1870        let result = app.parse_with_args(string_args);
1871
1872        assert!(result.is_ok());
1873
1874        drop(app);
1875
1876        // '-d' was specified twice and '-?' was specified three times
1877        let expected_count = (1 + 2) + (1 + 2 + 3);
1878        assert_eq!(handler.count, expected_count);
1879
1880        assert_eq!(handler.a_count, 1);
1881        assert_eq!(handler.b_count, 1);
1882        assert_eq!(handler.d_count, 2);
1883        assert_eq!(handler.r_count, 1);
1884    }
1885
1886    #[test]
1887    fn test_intermingling_arguments() {
1888        let mut handler = ModifyHandler::default();
1889        let mut args = Args::default();
1890
1891        args.add(Arg::new('a').needs(Need::Argument));
1892        args.add(Arg::new('d').needs(Need::Nothing));
1893        args.add(Arg::new(POSITIONAL_HANDLER_OPT));
1894
1895        let mut app = App::default()
1896            .help("some text")
1897            .args(args)
1898            .handler(Box::new(&mut handler));
1899
1900        // A mixture of options, flags and positional arguments.
1901        let cli_args = vec![
1902            "the start",
1903            "-d",
1904            "foo bar",
1905            "-a",
1906            "hello world",
1907            "-d",
1908            "alpha omega",
1909            "one",
1910            "two",
1911            "-d",
1912            "-a",
1913            "moo bar haz",
1914            "the end",
1915        ];
1916
1917        let string_args = cli_args.clone().into_iter().map(String::from).collect();
1918        let result = app.parse_with_args(string_args);
1919
1920        assert!(result.is_ok());
1921
1922        drop(app);
1923
1924        let expected_handler = ModifyHandler {
1925            i: 187,
1926            v: vec![
1927                "the start".into(),
1928                "foo bar".into(),
1929                "hello world".into(),
1930                "alpha omega".into(),
1931                "one".into(),
1932                "two".into(),
1933                "moo bar haz".into(),
1934                "the end".into(),
1935            ],
1936            s: "set by handler".into(),
1937            count: 30,
1938            a_count: 2,
1939            d_count: 3,
1940            ..Default::default()
1941        };
1942
1943        assert_eq!(handler, expected_handler);
1944    }
1945
1946    #[test]
1947    fn test_ignore_unknown_options() {
1948        #[derive(Debug)]
1949        struct TestData<'a> {
1950            cli_args: Vec<&'a str>,
1951            args: Vec<Arg>,
1952            allow_unknown_options: bool,
1953            result: Result<()>,
1954        }
1955
1956        let need_arg_opt = Arg::new('a').needs(Need::Argument);
1957        let flag_opt = Arg::new('d').needs(Need::Nothing);
1958
1959        let tests = &[
1960            TestData {
1961                cli_args: vec!["-z"],
1962                args: vec![need_arg_opt.clone()],
1963                allow_unknown_options: false,
1964                result: Err(Error::UnknownOpt),
1965            },
1966            TestData {
1967                cli_args: vec!["-z"],
1968                args: vec![need_arg_opt.clone()],
1969                allow_unknown_options: true,
1970                result: Ok(()),
1971            },
1972            //------------------------------
1973            TestData {
1974                cli_args: vec!["-z"],
1975                args: vec![flag_opt.clone()],
1976                allow_unknown_options: false,
1977                result: Err(Error::UnknownOpt),
1978            },
1979            TestData {
1980                cli_args: vec!["-z"],
1981                args: vec![flag_opt.clone()],
1982                allow_unknown_options: true,
1983                result: Ok(()),
1984            },
1985            //------------------------------
1986            TestData {
1987                cli_args: vec!["-z", "-a", "foo"],
1988                args: vec![need_arg_opt.clone()],
1989                allow_unknown_options: false,
1990                result: Err(Error::UnknownOpt),
1991            },
1992            TestData {
1993                cli_args: vec!["-a", "foo", "-z"],
1994                args: vec![need_arg_opt.clone()],
1995                allow_unknown_options: false,
1996                result: Err(Error::UnknownOpt),
1997            },
1998            //------------------------------
1999            TestData {
2000                cli_args: vec!["-z", "-a", "foo"],
2001                args: vec![need_arg_opt.clone()],
2002                allow_unknown_options: true,
2003                result: Err(Error::UnknownOpt),
2004            },
2005            TestData {
2006                cli_args: vec!["-a", "foo", "-z"],
2007                args: vec![need_arg_opt.clone()],
2008                allow_unknown_options: true,
2009                result: Ok(()),
2010            },
2011            //------------------------------
2012            TestData {
2013                cli_args: vec!["-z", "-d"],
2014                args: vec![flag_opt.clone()],
2015                allow_unknown_options: false,
2016                result: Err(Error::UnknownOpt),
2017            },
2018            TestData {
2019                cli_args: vec!["-d", "-z"],
2020                args: vec![flag_opt.clone()],
2021                allow_unknown_options: false,
2022                result: Err(Error::UnknownOpt),
2023            },
2024            //------------------------------
2025            TestData {
2026                cli_args: vec!["-z", "-d"],
2027                args: vec![flag_opt.clone()],
2028                allow_unknown_options: true,
2029                result: Ok(()),
2030            },
2031            TestData {
2032                cli_args: vec!["-d", "-z"],
2033                args: vec![flag_opt.clone()],
2034                allow_unknown_options: true,
2035                result: Ok(()),
2036            },
2037        ];
2038
2039        for (i, d) in tests.iter().enumerate() {
2040            let msg = format!("test[{}]: {:?}", i, d);
2041            let string_args: Vec<String> =
2042                d.cli_args.clone().into_iter().map(String::from).collect();
2043
2044            let mut args = Args::default();
2045            args.set(d.args.clone());
2046
2047            let mut handler = OkHandler::default();
2048            let mut app = App::default().args(args).handler(Box::new(&mut handler));
2049
2050            if d.allow_unknown_options {
2051                app = app.ignore_unknown_options();
2052            }
2053
2054            let result = app.parse_with_args(string_args);
2055
2056            let msg = format!("{}, result: {:?}", msg, result);
2057
2058            if result.is_err() {
2059                assert!(d.result.is_err(), "{}", msg);
2060
2061                let expected_err = format!("{:?}", d.result.as_ref().err());
2062                let actual_err = format!("{:?}", result.as_ref().err());
2063                assert_eq!(expected_err, actual_err, "{}", msg);
2064
2065                continue;
2066            }
2067
2068            assert!(result.is_ok(), "{}", msg);
2069        }
2070    }
2071
2072    #[test]
2073    fn test_ignore_unknown_posn_args() {
2074        #[derive(Debug)]
2075        struct TestData<'a> {
2076            cli_args: Vec<&'a str>,
2077            args: Vec<Arg>,
2078            allow_unknown_posn_args: bool,
2079            result: Result<()>,
2080        }
2081
2082        let need_arg_opt = Arg::new('a').needs(Need::Argument);
2083        let flag_opt = Arg::new('d').needs(Need::Nothing);
2084
2085        let tests = &[
2086            TestData {
2087                cli_args: vec!["foo bar"],
2088                args: vec![need_arg_opt.clone()],
2089                allow_unknown_posn_args: false,
2090                result: Err(Error::NoPosnArgs),
2091            },
2092            TestData {
2093                cli_args: vec!["foo bar"],
2094                args: vec![need_arg_opt.clone()],
2095                allow_unknown_posn_args: true,
2096                result: Ok(()),
2097            },
2098            //------------------------------
2099            TestData {
2100                cli_args: vec!["foo bar"],
2101                args: vec![flag_opt.clone()],
2102                allow_unknown_posn_args: false,
2103                result: Err(Error::NoPosnArgs),
2104            },
2105            TestData {
2106                cli_args: vec!["foo bar"],
2107                args: vec![flag_opt.clone()],
2108                allow_unknown_posn_args: true,
2109                result: Ok(()),
2110            },
2111            //------------------------------
2112            TestData {
2113                cli_args: vec!["foo bar", "-a", "foo"],
2114                args: vec![need_arg_opt.clone()],
2115                allow_unknown_posn_args: false,
2116                result: Err(Error::NoPosnArgs),
2117            },
2118            TestData {
2119                cli_args: vec!["-a", "foo", "foo bar"],
2120                args: vec![need_arg_opt.clone()],
2121                allow_unknown_posn_args: false,
2122                result: Err(Error::NoPosnArgs),
2123            },
2124            //------------------------------
2125            TestData {
2126                cli_args: vec!["foo bar", "-a", "foo"],
2127                args: vec![need_arg_opt.clone()],
2128                allow_unknown_posn_args: true,
2129                result: Err(Error::NoPosnArgs),
2130            },
2131            TestData {
2132                cli_args: vec!["-a", "foo", "foo bar"],
2133                args: vec![need_arg_opt.clone()],
2134                allow_unknown_posn_args: true,
2135                result: Ok(()),
2136            },
2137            //------------------------------
2138            TestData {
2139                cli_args: vec!["foo bar", "-d"],
2140                args: vec![flag_opt.clone()],
2141                allow_unknown_posn_args: false,
2142                result: Err(Error::NoPosnArgs),
2143            },
2144            TestData {
2145                cli_args: vec!["-d", "foo bar"],
2146                args: vec![flag_opt.clone()],
2147                allow_unknown_posn_args: false,
2148                result: Err(Error::NoPosnArgs),
2149            },
2150            //------------------------------
2151            TestData {
2152                cli_args: vec!["foo bar", "-d"],
2153                args: vec![flag_opt.clone()],
2154                allow_unknown_posn_args: true,
2155                result: Ok(()),
2156            },
2157            TestData {
2158                cli_args: vec!["-d", "foo bar"],
2159                args: vec![flag_opt.clone()],
2160                allow_unknown_posn_args: true,
2161                result: Ok(()),
2162            },
2163        ];
2164
2165        for (i, d) in tests.iter().enumerate() {
2166            let msg = format!("test[{}]: {:?}", i, d);
2167            let string_args: Vec<String> =
2168                d.cli_args.clone().into_iter().map(String::from).collect();
2169
2170            let mut args = Args::default();
2171            args.set(d.args.clone());
2172
2173            let mut handler = OkHandler::default();
2174            let mut app = App::default().args(args).handler(Box::new(&mut handler));
2175
2176            if d.allow_unknown_posn_args {
2177                app = app.ignore_unknown_posn_args();
2178            }
2179
2180            let result = app.parse_with_args(string_args);
2181
2182            let msg = format!("{}, result: {:?}", msg, result);
2183
2184            if result.is_err() {
2185                assert!(d.result.is_err(), "{}", msg);
2186
2187                let expected_err = format!("{:?}", d.result.as_ref().err());
2188                let actual_err = format!("{:?}", result.as_ref().err());
2189                assert_eq!(expected_err, actual_err, "{}", msg);
2190
2191                continue;
2192            }
2193
2194            assert!(result.is_ok(), "{}", msg);
2195        }
2196    }
2197
2198    #[test]
2199    fn test_app_creation() {
2200        let new_app = App::new("foo bar");
2201        let def_app = App::default();
2202
2203        let expected_def_app = App {
2204            name: "".into(),
2205            version: "".into(),
2206            summary: "".into(),
2207            help: "".into(),
2208            notes: "".into(),
2209            settings: Settings::default(),
2210            args: Args::default(),
2211            handler: None,
2212        };
2213
2214        let expected_new_app = App {
2215            name: "foo bar".into(),
2216            ..Default::default()
2217        };
2218
2219        assert_eq!(def_app, expected_def_app);
2220        assert_eq!(new_app, expected_new_app);
2221    }
2222
2223    #[test]
2224    fn test_app() {
2225        let mut app = App::default();
2226
2227        assert_eq!(app.name, "");
2228        let name = "foo bar";
2229        app = app.name(name);
2230        assert_eq!(app.name, name);
2231
2232        let version = "1.2.3-beta5";
2233        assert_eq!(app.version, "");
2234        app = app.version(version);
2235        assert_eq!(app.version, version);
2236
2237        let summary = "my awesome app";
2238        assert_eq!(app.summary, "");
2239        app = app.summary(summary);
2240        assert_eq!(app.summary, summary);
2241
2242        let help = "this app does something\nthe end\n";
2243        assert_eq!(app.help, "");
2244        app = app.help(help);
2245        assert_eq!(app.help, help);
2246
2247        let notes = "a b c d e f# g";
2248        assert_eq!(app.notes, "");
2249        app = app.notes(notes);
2250        assert_eq!(app.notes, notes);
2251
2252        let settings = Settings::new().no_strict_options();
2253        let def_settings = Settings::new();
2254        assert_eq!(app.settings, def_settings);
2255
2256        app = app.settings(settings);
2257        assert_eq!(app.settings, settings);
2258    }
2259
2260    #[test]
2261    fn test_generate_help() {
2262        let mut writer = BufWriter::new();
2263
2264        let mut args = Args::default();
2265
2266        // flags
2267        args.add(Arg::new('d').help("enable debug"));
2268        args.add(Arg::new('e').required());
2269        args.add(Arg::new('f').required().help("force mode"));
2270
2271        // options
2272        args.add(Arg::new('n').needs(Need::Argument));
2273        args.add(Arg::new('r').needs(Need::Argument).required());
2274        args.add(
2275            Arg::new('s')
2276                .needs(Need::Argument)
2277                .required()
2278                .help("silly option"),
2279        );
2280
2281        let posn_help = "I am the positional handler \
2282             help text";
2283
2284        // positional parameters magic option
2285        args.add(Arg::new(POSITIONAL_HANDLER_OPT).help(posn_help));
2286
2287        let flags_re = concat!(
2288            r#"FLAGS:\n"#,
2289            r#"\s+-d # enable debug\n"#,
2290            r#"\s+-e \(required\)\n"#,
2291            r#"\s+-f \(required\) # force mode\n"#,
2292        );
2293
2294        let options_re = concat!(
2295            r#"OPTIONS:\n"#,
2296            r#"\s+-n <value>\n"#,
2297            r#"\s+-r <value> \(required\)\n"#,
2298            r#"\s+-s <value> \(required\) # silly option\n"#,
2299        );
2300
2301        let pos_handler_re = concat!(
2302            r#"POSITIONAL ARGUMENTS:\n\n"#,
2303            r#"I am the positional handler help text"#
2304        );
2305
2306        //--------------------
2307
2308        let name = "my app";
2309        let name_re = format!(r#"NAME:\n\s+{}\n"#, name);
2310
2311        let version = "1.2.3-alpha4";
2312        let version_re = format!(r"VERSION:\n\s+{}\n", version);
2313
2314        let summary = "This is one awesome app";
2315        let summary_re = format!(r"SUMMARY:\n\s+{}\n", summary);
2316
2317        let help = concat!(
2318            "help line 1\n",
2319            "help line 2\n",
2320            "help line 3\n",
2321            "help last line\n"
2322        );
2323        let help_re = format!(r"HELP:\n\s+{}\n", help);
2324
2325        let notes = concat!(
2326            "notes line 1\n",
2327            "notes line 2\n",
2328            "notes line 3\n",
2329            "notes last line\n"
2330        );
2331
2332        let notes_re = format!(r"NOTES:\n\s+{}\n", notes);
2333
2334        //--------------------
2335
2336        let mut handler = OkHandler::default();
2337
2338        let app = App::new(name)
2339            .summary(summary)
2340            .version(version)
2341            .help(help)
2342            .notes(notes)
2343            .args(args)
2344            .handler(Box::new(&mut handler));
2345
2346        let result = app.generate_help(&mut writer);
2347
2348        drop(app);
2349
2350        assert!(result.is_ok());
2351
2352        let value = writer.to_string();
2353
2354        let re = Regex::new(&name_re).unwrap();
2355        assert!(re.is_match(&value));
2356
2357        let re = Regex::new(&version_re).unwrap();
2358        assert!(re.is_match(&value));
2359
2360        let re = Regex::new(&summary_re).unwrap();
2361        assert!(re.is_match(&value));
2362
2363        let re = Regex::new(&help_re).unwrap();
2364        assert!(re.is_match(&value));
2365
2366        let re = Regex::new(&notes_re).unwrap();
2367        assert!(re.is_match(&value));
2368
2369        let re = Regex::new(&flags_re).unwrap();
2370        assert!(re.is_match(&value));
2371
2372        let re = Regex::new(&options_re).unwrap();
2373        assert!(re.is_match(&value));
2374
2375        let re = Regex::new(&pos_handler_re).unwrap();
2376        assert!(re.is_match(&value));
2377    }
2378
2379    #[test]
2380    fn test_generate_help_usage() {
2381        #[derive(Debug)]
2382        struct TestData<'a> {
2383            args: Vec<Arg>,
2384            usage: &'a str,
2385        }
2386
2387        let tests = &[
2388            TestData {
2389                args: vec![Arg::new(POSITIONAL_HANDLER_OPT)],
2390                usage: r#"\[ARGUMENT\]..."#,
2391            },
2392            //--------------------
2393            TestData {
2394                args: vec![Arg::new('d')],
2395                usage: r#"\[FLAG\]..."#,
2396            },
2397            TestData {
2398                args: vec![Arg::new('d'), Arg::new('e')],
2399                usage: r#"\[FLAG\]..."#,
2400            },
2401            TestData {
2402                args: vec![Arg::new('d').required()],
2403                usage: r#"\[FLAG\]..."#,
2404            },
2405            TestData {
2406                args: vec![Arg::new('d').required().needs(Need::Nothing)],
2407                usage: r#"\[FLAG\]..."#,
2408            },
2409            TestData {
2410                args: vec![Arg::new('d').required().needs(Need::Nothing), Arg::new('e')],
2411                usage: r#"\[FLAG\]..."#,
2412            },
2413            TestData {
2414                args: vec![Arg::new('d').needs(Need::Nothing), Arg::new('e')],
2415                usage: r#"\[FLAG\]..."#,
2416            },
2417            //--------------------
2418            TestData {
2419                args: vec![Arg::new('a').needs(Need::Argument)],
2420                usage: r#"\[OPTION\]..."#,
2421            },
2422            TestData {
2423                args: vec![
2424                    Arg::new('d').needs(Need::Argument),
2425                    Arg::new('e').needs(Need::Argument),
2426                ],
2427                usage: r#"\[OPTION\]..."#,
2428            },
2429            TestData {
2430                args: vec![Arg::new('d').needs(Need::Argument).required()],
2431                usage: r#"\[OPTION\]..."#,
2432            },
2433            TestData {
2434                args: vec![
2435                    Arg::new('d').needs(Need::Argument).required(),
2436                    Arg::new('e').needs(Need::Argument),
2437                ],
2438                usage: r#"\[OPTION\]..."#,
2439            },
2440            //--------------------
2441            TestData {
2442                args: vec![
2443                    Arg::new('d').needs(Need::Nothing),
2444                    Arg::new('e').needs(Need::Argument),
2445                ],
2446                usage: r#"\[FLAG/OPTION\]..."#,
2447            },
2448            TestData {
2449                args: vec![
2450                    Arg::new('d').needs(Need::Nothing),
2451                    Arg::new(POSITIONAL_HANDLER_OPT),
2452                ],
2453                usage: r#"\[FLAG\]... \[ARGUMENT\]..."#,
2454            },
2455            TestData {
2456                args: vec![
2457                    Arg::new(POSITIONAL_HANDLER_OPT),
2458                    Arg::new('e').needs(Need::Argument),
2459                ],
2460                usage: r#"\[OPTION\]... \[ARGUMENT\]..."#,
2461            },
2462            TestData {
2463                args: vec![
2464                    Arg::new(POSITIONAL_HANDLER_OPT),
2465                    Arg::new('d').needs(Need::Nothing),
2466                    Arg::new('e').needs(Need::Argument),
2467                ],
2468                usage: r#"\[FLAG/OPTION\]... \[ARGUMENT\]..."#,
2469            },
2470            //--------------------
2471        ];
2472
2473        let mut writer = BufWriter::new();
2474
2475        for (i, d) in tests.iter().enumerate() {
2476            let msg = format!("test[{}]: {:?}", i, d);
2477
2478            let mut handler = OkHandler::default();
2479            let mut args = Args::default();
2480
2481            for arg in d.args.clone() {
2482                args.add(arg);
2483            }
2484
2485            let name = "test";
2486            let app = App::new(name).args(args).handler(Box::new(&mut handler));
2487            let result = app.generate_help(&mut writer);
2488            assert!(result.is_ok(), "{}", msg);
2489
2490            drop(app);
2491
2492            let value = writer.to_string();
2493
2494            let usage_re = format!(r"USAGE:\n\s+{}\s+{}\n", name, d.usage);
2495
2496            let re = Regex::new(&usage_re).unwrap();
2497
2498            assert!(re.is_match(&value), "{}", msg);
2499        }
2500    }
2501
2502    #[test]
2503    fn test_get_args() {
2504        let get_args_result = get_args();
2505
2506        let mut args: Vec<String> = env::args().collect();
2507        args.remove(0);
2508
2509        assert_eq!(get_args_result, args);
2510    }
2511
2512    #[test]
2513    fn test_arg_display() {
2514        #[derive(Debug)]
2515        struct TestData<'a> {
2516            arg: Arg,
2517            display: &'a str,
2518        }
2519
2520        let tests = &[
2521            TestData {
2522                arg: Arg::new('d'),
2523                display: "-d",
2524            },
2525            TestData {
2526                arg: Arg::new('d').required(),
2527                display: "-d (required)",
2528            },
2529            //------------------------------
2530            TestData {
2531                arg: Arg::new('d').needs(Need::Nothing),
2532                display: "-d",
2533            },
2534            TestData {
2535                arg: Arg::new('d').required().needs(Need::Nothing),
2536                display: "-d (required)",
2537            },
2538            //------------------------------
2539            TestData {
2540                arg: Arg::new('r').needs(Need::Argument),
2541                display: "-r <value>",
2542            },
2543            TestData {
2544                arg: Arg::new('r').needs(Need::Argument).required(),
2545                display: "-r <value> (required)",
2546            },
2547            //------------------------------
2548            TestData {
2549                arg: Arg::new('r').needs(Need::Argument),
2550                display: "-r <value>",
2551            },
2552            TestData {
2553                arg: Arg::new('r').needs(Need::Argument).required(),
2554                display: "-r <value> (required)",
2555            },
2556            //------------------------------
2557            TestData {
2558                arg: Arg::new('d').help("some help text"),
2559                display: "-d # some help text",
2560            },
2561            TestData {
2562                arg: Arg::new('d').required().help("some help text"),
2563                display: "-d (required) # some help text",
2564            },
2565            //------------------------------
2566        ];
2567
2568        for (i, d) in tests.iter().enumerate() {
2569            let value = format!("{:}", d.arg);
2570
2571            let msg = format!("test[{}]: {:?}, value: {:?}", i, d, value);
2572
2573            assert_eq!(value, d.display, "{}", msg);
2574        }
2575    }
2576
2577    #[test]
2578    fn test_handler_display() {
2579        let mut ok_handler = OkHandler::default();
2580        let mut mod_handler = ModifyHandler::default();
2581        let mut err_handler = ErrHandler::default();
2582
2583        let mut handlers: Vec<Box<dyn Handler>> = Vec::new();
2584        handlers.push(Box::new(&mut ok_handler));
2585        handlers.push(Box::new(&mut err_handler));
2586        handlers.push(Box::new(&mut mod_handler));
2587
2588        for (i, handler) in handlers.iter().enumerate() {
2589            let p = handler;
2590
2591            let value = format!("{:?}", p);
2592
2593            let msg = format!("test[{}]: value: {:?}", i, value);
2594
2595            assert!(value.starts_with("Handler: "), "{}", msg);
2596        }
2597    }
2598
2599    #[test]
2600    fn test_no_strict_options() {
2601        #[derive(Debug)]
2602        struct TestData<'a> {
2603            cli_args: Vec<&'a str>,
2604            args: Vec<Arg>,
2605            no_strict_options: bool,
2606            result: Result<()>,
2607            r_count: usize,
2608            d_count: usize,
2609            values: Vec<&'a str>,
2610        }
2611
2612        let flag_opt = Arg::new('d').needs(Need::Nothing);
2613        let need_arg_opt = Arg::new('r').needs(Need::Argument);
2614
2615        let tests = &[
2616            TestData {
2617                cli_args: vec!["-r", "foo", "-d"],
2618                args: vec![flag_opt.clone(), need_arg_opt.clone()],
2619                no_strict_options: false,
2620                result: Ok(()),
2621                r_count: 1,
2622                d_count: 1,
2623                values: vec!["foo"],
2624            },
2625            TestData {
2626                cli_args: vec!["-r", "foo", "-d"],
2627                args: vec![flag_opt.clone(), need_arg_opt.clone()],
2628                no_strict_options: true,
2629                result: Ok(()),
2630                r_count: 1,
2631                d_count: 1,
2632                values: vec!["foo"],
2633            },
2634            //------------------------------
2635            TestData {
2636                cli_args: vec!["-r", "-d"],
2637                args: vec![flag_opt.clone(), need_arg_opt.clone()],
2638                no_strict_options: false,
2639                result: Ok(()),
2640                r_count: 1,
2641                d_count: 0,
2642                values: vec!["-d"],
2643            },
2644            TestData {
2645                cli_args: vec!["-r", "-d"],
2646                args: vec![flag_opt.clone(), need_arg_opt.clone()],
2647                no_strict_options: true,
2648                result: Err(Error::MissingOptArg),
2649                r_count: 0,
2650                d_count: 0,
2651                values: vec![],
2652            },
2653            //------------------------------
2654            TestData {
2655                cli_args: vec!["-r", "--"],
2656                args: vec![need_arg_opt.clone()],
2657                no_strict_options: false,
2658                result: Err(Error::MissingOptArg),
2659                r_count: 0,
2660                d_count: 0,
2661                values: vec![],
2662            },
2663            TestData {
2664                cli_args: vec!["-r", "--"],
2665                args: vec![need_arg_opt.clone()],
2666                no_strict_options: true,
2667                result: Err(Error::MissingOptArg),
2668                r_count: 0,
2669                d_count: 0,
2670                values: vec![],
2671            },
2672            //------------------------------
2673            TestData {
2674                cli_args: vec!["-r", "-d", "--"],
2675                args: vec![need_arg_opt.clone()],
2676                no_strict_options: false,
2677                result: Ok(()),
2678                r_count: 1,
2679                d_count: 0,
2680                values: vec!["-d"],
2681            },
2682            TestData {
2683                cli_args: vec!["-r", "-d", "--"],
2684                args: vec![need_arg_opt.clone()],
2685                no_strict_options: true,
2686                result: Err(Error::MissingOptArg),
2687                r_count: 0,
2688                d_count: 0,
2689                values: vec![],
2690            },
2691        ];
2692
2693        for (i, d) in tests.iter().enumerate() {
2694            let msg = format!("test[{}]: {:?}", i, d);
2695            let string_args: Vec<String> =
2696                d.cli_args.clone().into_iter().map(String::from).collect();
2697
2698            let mut args = Args::default();
2699            args.set(d.args.clone());
2700
2701            let mut handler = ModifyHandler::default();
2702            let mut app = App::default().args(args).handler(Box::new(&mut handler));
2703
2704            if d.no_strict_options {
2705                app = app.no_strict_options();
2706            }
2707
2708            let result = app.parse_with_args(string_args);
2709
2710            let msg = format!("{}, result: {:?}", msg, result);
2711
2712            if result.is_err() {
2713                assert!(d.result.is_err(), "{}", msg);
2714
2715                let expected_err = format!("{:?}", d.result.as_ref().err());
2716                let actual_err = format!("{:?}", result.as_ref().err());
2717                assert_eq!(expected_err, actual_err, "{}", msg);
2718
2719                continue;
2720            }
2721
2722            assert!(result.is_ok(), "{}", msg);
2723
2724            drop(app);
2725
2726            assert_eq!(d.r_count, handler.r_count);
2727            assert_eq!(d.d_count, handler.d_count);
2728
2729            let v: Vec<String> = d.values.clone().into_iter().map(String::from).collect();
2730            assert_eq!(v, handler.v);
2731        }
2732    }
2733}