119625d8cSopenharmony_ci// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
219625d8cSopenharmony_ci// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
319625d8cSopenharmony_ci// Ana Hobden (@hoverbear) <operator@hoverbear.org>
419625d8cSopenharmony_ci//
519625d8cSopenharmony_ci// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
619625d8cSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
719625d8cSopenharmony_ci// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
819625d8cSopenharmony_ci// option. This file may not be copied, modified, or distributed
919625d8cSopenharmony_ci// except according to those terms.
1019625d8cSopenharmony_ci//
1119625d8cSopenharmony_ci// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
1219625d8cSopenharmony_ci// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
1319625d8cSopenharmony_ci// MIT/Apache 2.0 license.
1419625d8cSopenharmony_ci
1519625d8cSopenharmony_ciuse crate::utils;
1619625d8cSopenharmony_ci
1719625d8cSopenharmony_ciuse clap::{Args, Parser, Subcommand};
1819625d8cSopenharmony_ci
1919625d8cSopenharmony_ci#[test]
2019625d8cSopenharmony_cifn flatten() {
2119625d8cSopenharmony_ci    #[derive(Args, PartialEq, Debug)]
2219625d8cSopenharmony_ci    struct Common {
2319625d8cSopenharmony_ci        arg: i32,
2419625d8cSopenharmony_ci    }
2519625d8cSopenharmony_ci
2619625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Debug)]
2719625d8cSopenharmony_ci    struct Opt {
2819625d8cSopenharmony_ci        #[command(flatten)]
2919625d8cSopenharmony_ci        common: Common,
3019625d8cSopenharmony_ci    }
3119625d8cSopenharmony_ci    assert_eq!(
3219625d8cSopenharmony_ci        Opt {
3319625d8cSopenharmony_ci            common: Common { arg: 42 }
3419625d8cSopenharmony_ci        },
3519625d8cSopenharmony_ci        Opt::try_parse_from(["test", "42"]).unwrap()
3619625d8cSopenharmony_ci    );
3719625d8cSopenharmony_ci    assert!(Opt::try_parse_from(["test"]).is_err());
3819625d8cSopenharmony_ci    assert!(Opt::try_parse_from(["test", "42", "24"]).is_err());
3919625d8cSopenharmony_ci}
4019625d8cSopenharmony_ci
4119625d8cSopenharmony_ci#[cfg(debug_assertions)]
4219625d8cSopenharmony_ci#[test]
4319625d8cSopenharmony_ci#[should_panic]
4419625d8cSopenharmony_cifn flatten_twice() {
4519625d8cSopenharmony_ci    #[derive(Args, PartialEq, Debug)]
4619625d8cSopenharmony_ci    struct Common {
4719625d8cSopenharmony_ci        arg: i32,
4819625d8cSopenharmony_ci    }
4919625d8cSopenharmony_ci
5019625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Debug)]
5119625d8cSopenharmony_ci    struct Opt {
5219625d8cSopenharmony_ci        #[command(flatten)]
5319625d8cSopenharmony_ci        c1: Common,
5419625d8cSopenharmony_ci        // Defines "arg" twice, so this should not work.
5519625d8cSopenharmony_ci        #[command(flatten)]
5619625d8cSopenharmony_ci        c2: Common,
5719625d8cSopenharmony_ci    }
5819625d8cSopenharmony_ci    Opt::try_parse_from(["test", "42", "43"]).unwrap();
5919625d8cSopenharmony_ci}
6019625d8cSopenharmony_ci
6119625d8cSopenharmony_ci#[test]
6219625d8cSopenharmony_cifn flatten_in_subcommand() {
6319625d8cSopenharmony_ci    #[derive(Args, PartialEq, Debug)]
6419625d8cSopenharmony_ci    struct Common {
6519625d8cSopenharmony_ci        arg: i32,
6619625d8cSopenharmony_ci    }
6719625d8cSopenharmony_ci
6819625d8cSopenharmony_ci    #[derive(Args, PartialEq, Debug)]
6919625d8cSopenharmony_ci    struct Add {
7019625d8cSopenharmony_ci        #[arg(short)]
7119625d8cSopenharmony_ci        interactive: bool,
7219625d8cSopenharmony_ci        #[command(flatten)]
7319625d8cSopenharmony_ci        common: Common,
7419625d8cSopenharmony_ci    }
7519625d8cSopenharmony_ci
7619625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Debug)]
7719625d8cSopenharmony_ci    enum Opt {
7819625d8cSopenharmony_ci        Fetch {
7919625d8cSopenharmony_ci            #[arg(short)]
8019625d8cSopenharmony_ci            all: bool,
8119625d8cSopenharmony_ci            #[command(flatten)]
8219625d8cSopenharmony_ci            common: Common,
8319625d8cSopenharmony_ci        },
8419625d8cSopenharmony_ci
8519625d8cSopenharmony_ci        Add(Add),
8619625d8cSopenharmony_ci    }
8719625d8cSopenharmony_ci
8819625d8cSopenharmony_ci    assert_eq!(
8919625d8cSopenharmony_ci        Opt::Fetch {
9019625d8cSopenharmony_ci            all: false,
9119625d8cSopenharmony_ci            common: Common { arg: 42 }
9219625d8cSopenharmony_ci        },
9319625d8cSopenharmony_ci        Opt::try_parse_from(["test", "fetch", "42"]).unwrap()
9419625d8cSopenharmony_ci    );
9519625d8cSopenharmony_ci    assert_eq!(
9619625d8cSopenharmony_ci        Opt::Add(Add {
9719625d8cSopenharmony_ci            interactive: true,
9819625d8cSopenharmony_ci            common: Common { arg: 43 }
9919625d8cSopenharmony_ci        }),
10019625d8cSopenharmony_ci        Opt::try_parse_from(["test", "add", "-i", "43"]).unwrap()
10119625d8cSopenharmony_ci    );
10219625d8cSopenharmony_ci}
10319625d8cSopenharmony_ci
10419625d8cSopenharmony_ci#[test]
10519625d8cSopenharmony_cifn update_args_with_flatten() {
10619625d8cSopenharmony_ci    #[derive(Args, PartialEq, Debug)]
10719625d8cSopenharmony_ci    struct Common {
10819625d8cSopenharmony_ci        arg: i32,
10919625d8cSopenharmony_ci    }
11019625d8cSopenharmony_ci
11119625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Debug)]
11219625d8cSopenharmony_ci    struct Opt {
11319625d8cSopenharmony_ci        #[command(flatten)]
11419625d8cSopenharmony_ci        common: Common,
11519625d8cSopenharmony_ci    }
11619625d8cSopenharmony_ci
11719625d8cSopenharmony_ci    let mut opt = Opt {
11819625d8cSopenharmony_ci        common: Common { arg: 42 },
11919625d8cSopenharmony_ci    };
12019625d8cSopenharmony_ci    opt.try_update_from(["test"]).unwrap();
12119625d8cSopenharmony_ci    assert_eq!(Opt::try_parse_from(["test", "42"]).unwrap(), opt);
12219625d8cSopenharmony_ci
12319625d8cSopenharmony_ci    let mut opt = Opt {
12419625d8cSopenharmony_ci        common: Common { arg: 42 },
12519625d8cSopenharmony_ci    };
12619625d8cSopenharmony_ci    opt.try_update_from(["test", "52"]).unwrap();
12719625d8cSopenharmony_ci    assert_eq!(Opt::try_parse_from(["test", "52"]).unwrap(), opt);
12819625d8cSopenharmony_ci}
12919625d8cSopenharmony_ci
13019625d8cSopenharmony_ci#[derive(Subcommand, PartialEq, Debug)]
13119625d8cSopenharmony_cienum BaseCli {
13219625d8cSopenharmony_ci    Command1(Command1),
13319625d8cSopenharmony_ci}
13419625d8cSopenharmony_ci
13519625d8cSopenharmony_ci#[derive(Args, PartialEq, Debug)]
13619625d8cSopenharmony_cistruct Command1 {
13719625d8cSopenharmony_ci    arg1: i32,
13819625d8cSopenharmony_ci
13919625d8cSopenharmony_ci    arg2: i32,
14019625d8cSopenharmony_ci}
14119625d8cSopenharmony_ci
14219625d8cSopenharmony_ci#[derive(Args, PartialEq, Debug)]
14319625d8cSopenharmony_cistruct Command2 {
14419625d8cSopenharmony_ci    arg2: i32,
14519625d8cSopenharmony_ci}
14619625d8cSopenharmony_ci
14719625d8cSopenharmony_ci#[derive(Parser, PartialEq, Debug)]
14819625d8cSopenharmony_cienum Opt {
14919625d8cSopenharmony_ci    #[command(flatten)]
15019625d8cSopenharmony_ci    BaseCli(BaseCli),
15119625d8cSopenharmony_ci    Command2(Command2),
15219625d8cSopenharmony_ci}
15319625d8cSopenharmony_ci
15419625d8cSopenharmony_ci#[test]
15519625d8cSopenharmony_cifn merge_subcommands_with_flatten() {
15619625d8cSopenharmony_ci    assert_eq!(
15719625d8cSopenharmony_ci        Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42, arg2: 44 })),
15819625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command1", "42", "44"]).unwrap()
15919625d8cSopenharmony_ci    );
16019625d8cSopenharmony_ci    assert_eq!(
16119625d8cSopenharmony_ci        Opt::Command2(Command2 { arg2: 43 }),
16219625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command2", "43"]).unwrap()
16319625d8cSopenharmony_ci    );
16419625d8cSopenharmony_ci}
16519625d8cSopenharmony_ci
16619625d8cSopenharmony_ci#[test]
16719625d8cSopenharmony_cifn update_subcommands_with_flatten() {
16819625d8cSopenharmony_ci    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
16919625d8cSopenharmony_ci    opt.try_update_from(["test", "command1", "42", "44"])
17019625d8cSopenharmony_ci        .unwrap();
17119625d8cSopenharmony_ci    assert_eq!(
17219625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command1", "42", "44"]).unwrap(),
17319625d8cSopenharmony_ci        opt
17419625d8cSopenharmony_ci    );
17519625d8cSopenharmony_ci
17619625d8cSopenharmony_ci    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
17719625d8cSopenharmony_ci    opt.try_update_from(["test", "command1", "42"]).unwrap();
17819625d8cSopenharmony_ci    assert_eq!(
17919625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command1", "42", "14"]).unwrap(),
18019625d8cSopenharmony_ci        opt
18119625d8cSopenharmony_ci    );
18219625d8cSopenharmony_ci
18319625d8cSopenharmony_ci    let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
18419625d8cSopenharmony_ci    opt.try_update_from(["test", "command2", "43"]).unwrap();
18519625d8cSopenharmony_ci    assert_eq!(
18619625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command2", "43"]).unwrap(),
18719625d8cSopenharmony_ci        opt
18819625d8cSopenharmony_ci    );
18919625d8cSopenharmony_ci}
19019625d8cSopenharmony_ci
19119625d8cSopenharmony_ci#[test]
19219625d8cSopenharmony_cifn flatten_with_doc_comment() {
19319625d8cSopenharmony_ci    #[derive(Args, PartialEq, Debug)]
19419625d8cSopenharmony_ci    struct Common {
19519625d8cSopenharmony_ci        /// This is an arg. Arg means "argument". Command line argument.
19619625d8cSopenharmony_ci        arg: i32,
19719625d8cSopenharmony_ci    }
19819625d8cSopenharmony_ci
19919625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Debug)]
20019625d8cSopenharmony_ci    struct Opt {
20119625d8cSopenharmony_ci        /// The very important comment that clippy had me put here.
20219625d8cSopenharmony_ci        /// It knows better.
20319625d8cSopenharmony_ci        #[command(flatten)]
20419625d8cSopenharmony_ci        common: Common,
20519625d8cSopenharmony_ci    }
20619625d8cSopenharmony_ci    assert_eq!(
20719625d8cSopenharmony_ci        Opt {
20819625d8cSopenharmony_ci            common: Common { arg: 42 }
20919625d8cSopenharmony_ci        },
21019625d8cSopenharmony_ci        Opt::try_parse_from(["test", "42"]).unwrap()
21119625d8cSopenharmony_ci    );
21219625d8cSopenharmony_ci
21319625d8cSopenharmony_ci    let help = utils::get_help::<Opt>();
21419625d8cSopenharmony_ci    assert!(help.contains("This is an arg."));
21519625d8cSopenharmony_ci    assert!(!help.contains("The very important"));
21619625d8cSopenharmony_ci}
21719625d8cSopenharmony_ci
21819625d8cSopenharmony_ci#[test]
21919625d8cSopenharmony_cifn docstrings_ordering_with_multiple_command() {
22019625d8cSopenharmony_ci    /// This is the docstring for Flattened
22119625d8cSopenharmony_ci    #[derive(Args)]
22219625d8cSopenharmony_ci    struct Flattened {
22319625d8cSopenharmony_ci        #[arg(long)]
22419625d8cSopenharmony_ci        foo: bool,
22519625d8cSopenharmony_ci    }
22619625d8cSopenharmony_ci
22719625d8cSopenharmony_ci    /// This is the docstring for Command
22819625d8cSopenharmony_ci    #[derive(Parser)]
22919625d8cSopenharmony_ci    struct Command {
23019625d8cSopenharmony_ci        #[command(flatten)]
23119625d8cSopenharmony_ci        flattened: Flattened,
23219625d8cSopenharmony_ci    }
23319625d8cSopenharmony_ci
23419625d8cSopenharmony_ci    let short_help = utils::get_help::<Command>();
23519625d8cSopenharmony_ci
23619625d8cSopenharmony_ci    assert!(short_help.contains("This is the docstring for Command"));
23719625d8cSopenharmony_ci}
23819625d8cSopenharmony_ci
23919625d8cSopenharmony_ci#[test]
24019625d8cSopenharmony_cifn docstrings_ordering_with_multiple_clap_partial() {
24119625d8cSopenharmony_ci    /// This is the docstring for Flattened
24219625d8cSopenharmony_ci    #[derive(Args)]
24319625d8cSopenharmony_ci    struct Flattened {
24419625d8cSopenharmony_ci        #[arg(long)]
24519625d8cSopenharmony_ci        foo: bool,
24619625d8cSopenharmony_ci    }
24719625d8cSopenharmony_ci
24819625d8cSopenharmony_ci    #[derive(Parser)]
24919625d8cSopenharmony_ci    struct Command {
25019625d8cSopenharmony_ci        #[command(flatten)]
25119625d8cSopenharmony_ci        flattened: Flattened,
25219625d8cSopenharmony_ci    }
25319625d8cSopenharmony_ci
25419625d8cSopenharmony_ci    let short_help = utils::get_help::<Command>();
25519625d8cSopenharmony_ci
25619625d8cSopenharmony_ci    assert!(short_help.contains("This is the docstring for Flattened"));
25719625d8cSopenharmony_ci}
25819625d8cSopenharmony_ci
25919625d8cSopenharmony_ci#[test]
26019625d8cSopenharmony_cifn optional_flatten() {
26119625d8cSopenharmony_ci    #[derive(Parser, Debug, PartialEq, Eq)]
26219625d8cSopenharmony_ci    struct Opt {
26319625d8cSopenharmony_ci        #[command(flatten)]
26419625d8cSopenharmony_ci        source: Option<Source>,
26519625d8cSopenharmony_ci    }
26619625d8cSopenharmony_ci
26719625d8cSopenharmony_ci    #[derive(clap::Args, Debug, PartialEq, Eq)]
26819625d8cSopenharmony_ci    struct Source {
26919625d8cSopenharmony_ci        crates: Vec<String>,
27019625d8cSopenharmony_ci        #[arg(long)]
27119625d8cSopenharmony_ci        path: Option<std::path::PathBuf>,
27219625d8cSopenharmony_ci        #[arg(long)]
27319625d8cSopenharmony_ci        git: Option<String>,
27419625d8cSopenharmony_ci    }
27519625d8cSopenharmony_ci
27619625d8cSopenharmony_ci    assert_eq!(Opt { source: None }, Opt::try_parse_from(["test"]).unwrap());
27719625d8cSopenharmony_ci    assert_eq!(
27819625d8cSopenharmony_ci        Opt {
27919625d8cSopenharmony_ci            source: Some(Source {
28019625d8cSopenharmony_ci                crates: vec!["serde".to_owned()],
28119625d8cSopenharmony_ci                path: None,
28219625d8cSopenharmony_ci                git: None,
28319625d8cSopenharmony_ci            }),
28419625d8cSopenharmony_ci        },
28519625d8cSopenharmony_ci        Opt::try_parse_from(["test", "serde"]).unwrap()
28619625d8cSopenharmony_ci    );
28719625d8cSopenharmony_ci    assert_eq!(
28819625d8cSopenharmony_ci        Opt {
28919625d8cSopenharmony_ci            source: Some(Source {
29019625d8cSopenharmony_ci                crates: Vec::new(),
29119625d8cSopenharmony_ci                path: Some("./".into()),
29219625d8cSopenharmony_ci                git: None,
29319625d8cSopenharmony_ci            }),
29419625d8cSopenharmony_ci        },
29519625d8cSopenharmony_ci        Opt::try_parse_from(["test", "--path=./"]).unwrap()
29619625d8cSopenharmony_ci    );
29719625d8cSopenharmony_ci}
298