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#[derive(Parser, PartialEq, Eq, Debug)]
2019625d8cSopenharmony_cienum Opt {
2119625d8cSopenharmony_ci    /// Fetch stuff from GitHub
2219625d8cSopenharmony_ci    Fetch {
2319625d8cSopenharmony_ci        #[arg(long)]
2419625d8cSopenharmony_ci        all: bool,
2519625d8cSopenharmony_ci        /// Overwrite local branches.
2619625d8cSopenharmony_ci        #[arg(short, long)]
2719625d8cSopenharmony_ci        force: bool,
2819625d8cSopenharmony_ci
2919625d8cSopenharmony_ci        repo: String,
3019625d8cSopenharmony_ci    },
3119625d8cSopenharmony_ci
3219625d8cSopenharmony_ci    Add {
3319625d8cSopenharmony_ci        #[arg(short, long)]
3419625d8cSopenharmony_ci        interactive: bool,
3519625d8cSopenharmony_ci        #[arg(short, long)]
3619625d8cSopenharmony_ci        verbose: bool,
3719625d8cSopenharmony_ci    },
3819625d8cSopenharmony_ci}
3919625d8cSopenharmony_ci
4019625d8cSopenharmony_ci#[test]
4119625d8cSopenharmony_cifn test_fetch() {
4219625d8cSopenharmony_ci    assert_eq!(
4319625d8cSopenharmony_ci        Opt::Fetch {
4419625d8cSopenharmony_ci            all: true,
4519625d8cSopenharmony_ci            force: false,
4619625d8cSopenharmony_ci            repo: "origin".to_string()
4719625d8cSopenharmony_ci        },
4819625d8cSopenharmony_ci        Opt::try_parse_from(["test", "fetch", "--all", "origin"]).unwrap()
4919625d8cSopenharmony_ci    );
5019625d8cSopenharmony_ci    assert_eq!(
5119625d8cSopenharmony_ci        Opt::Fetch {
5219625d8cSopenharmony_ci            all: false,
5319625d8cSopenharmony_ci            force: true,
5419625d8cSopenharmony_ci            repo: "origin".to_string()
5519625d8cSopenharmony_ci        },
5619625d8cSopenharmony_ci        Opt::try_parse_from(["test", "fetch", "-f", "origin"]).unwrap()
5719625d8cSopenharmony_ci    );
5819625d8cSopenharmony_ci}
5919625d8cSopenharmony_ci
6019625d8cSopenharmony_ci#[test]
6119625d8cSopenharmony_cifn test_add() {
6219625d8cSopenharmony_ci    assert_eq!(
6319625d8cSopenharmony_ci        Opt::Add {
6419625d8cSopenharmony_ci            interactive: false,
6519625d8cSopenharmony_ci            verbose: false
6619625d8cSopenharmony_ci        },
6719625d8cSopenharmony_ci        Opt::try_parse_from(["test", "add"]).unwrap()
6819625d8cSopenharmony_ci    );
6919625d8cSopenharmony_ci    assert_eq!(
7019625d8cSopenharmony_ci        Opt::Add {
7119625d8cSopenharmony_ci            interactive: true,
7219625d8cSopenharmony_ci            verbose: true
7319625d8cSopenharmony_ci        },
7419625d8cSopenharmony_ci        Opt::try_parse_from(["test", "add", "-i", "-v"]).unwrap()
7519625d8cSopenharmony_ci    );
7619625d8cSopenharmony_ci}
7719625d8cSopenharmony_ci
7819625d8cSopenharmony_ci#[test]
7919625d8cSopenharmony_cifn test_no_parse() {
8019625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "badcmd", "-i", "-v"]);
8119625d8cSopenharmony_ci    assert!(result.is_err());
8219625d8cSopenharmony_ci
8319625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "add", "--badoption"]);
8419625d8cSopenharmony_ci    assert!(result.is_err());
8519625d8cSopenharmony_ci
8619625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test"]);
8719625d8cSopenharmony_ci    assert!(result.is_err());
8819625d8cSopenharmony_ci}
8919625d8cSopenharmony_ci
9019625d8cSopenharmony_ci#[derive(Parser, PartialEq, Eq, Debug)]
9119625d8cSopenharmony_cienum Opt2 {
9219625d8cSopenharmony_ci    DoSomething { arg: String },
9319625d8cSopenharmony_ci}
9419625d8cSopenharmony_ci
9519625d8cSopenharmony_ci#[test]
9619625d8cSopenharmony_ci/// This test is specifically to make sure that hyphenated subcommands get
9719625d8cSopenharmony_ci/// processed correctly.
9819625d8cSopenharmony_cifn test_hyphenated_subcommands() {
9919625d8cSopenharmony_ci    assert_eq!(
10019625d8cSopenharmony_ci        Opt2::DoSomething {
10119625d8cSopenharmony_ci            arg: "blah".to_string()
10219625d8cSopenharmony_ci        },
10319625d8cSopenharmony_ci        Opt2::try_parse_from(["test", "do-something", "blah"]).unwrap()
10419625d8cSopenharmony_ci    );
10519625d8cSopenharmony_ci}
10619625d8cSopenharmony_ci
10719625d8cSopenharmony_ci#[derive(Parser, PartialEq, Eq, Debug)]
10819625d8cSopenharmony_cienum Opt3 {
10919625d8cSopenharmony_ci    Add,
11019625d8cSopenharmony_ci    Init,
11119625d8cSopenharmony_ci    Fetch,
11219625d8cSopenharmony_ci}
11319625d8cSopenharmony_ci
11419625d8cSopenharmony_ci#[test]
11519625d8cSopenharmony_cifn test_null_commands() {
11619625d8cSopenharmony_ci    assert_eq!(Opt3::Add, Opt3::try_parse_from(["test", "add"]).unwrap());
11719625d8cSopenharmony_ci    assert_eq!(Opt3::Init, Opt3::try_parse_from(["test", "init"]).unwrap());
11819625d8cSopenharmony_ci    assert_eq!(
11919625d8cSopenharmony_ci        Opt3::Fetch,
12019625d8cSopenharmony_ci        Opt3::try_parse_from(["test", "fetch"]).unwrap()
12119625d8cSopenharmony_ci    );
12219625d8cSopenharmony_ci}
12319625d8cSopenharmony_ci
12419625d8cSopenharmony_ci#[derive(Parser, PartialEq, Eq, Debug)]
12519625d8cSopenharmony_ci#[command(about = "Not shown")]
12619625d8cSopenharmony_cistruct Add {
12719625d8cSopenharmony_ci    file: String,
12819625d8cSopenharmony_ci}
12919625d8cSopenharmony_ci/// Not shown
13019625d8cSopenharmony_ci#[derive(Parser, PartialEq, Eq, Debug)]
13119625d8cSopenharmony_cistruct Fetch {
13219625d8cSopenharmony_ci    remote: String,
13319625d8cSopenharmony_ci}
13419625d8cSopenharmony_ci#[derive(Parser, PartialEq, Eq, Debug)]
13519625d8cSopenharmony_cienum Opt4 {
13619625d8cSopenharmony_ci    // Not shown
13719625d8cSopenharmony_ci    /// Add a file
13819625d8cSopenharmony_ci    Add(Add),
13919625d8cSopenharmony_ci    Init,
14019625d8cSopenharmony_ci    /// download history from remote
14119625d8cSopenharmony_ci    Fetch(Fetch),
14219625d8cSopenharmony_ci}
14319625d8cSopenharmony_ci
14419625d8cSopenharmony_ci#[test]
14519625d8cSopenharmony_cifn test_tuple_commands() {
14619625d8cSopenharmony_ci    assert_eq!(
14719625d8cSopenharmony_ci        Opt4::Add(Add {
14819625d8cSopenharmony_ci            file: "f".to_string()
14919625d8cSopenharmony_ci        }),
15019625d8cSopenharmony_ci        Opt4::try_parse_from(["test", "add", "f"]).unwrap()
15119625d8cSopenharmony_ci    );
15219625d8cSopenharmony_ci    assert_eq!(Opt4::Init, Opt4::try_parse_from(["test", "init"]).unwrap());
15319625d8cSopenharmony_ci    assert_eq!(
15419625d8cSopenharmony_ci        Opt4::Fetch(Fetch {
15519625d8cSopenharmony_ci            remote: "origin".to_string()
15619625d8cSopenharmony_ci        }),
15719625d8cSopenharmony_ci        Opt4::try_parse_from(["test", "fetch", "origin"]).unwrap()
15819625d8cSopenharmony_ci    );
15919625d8cSopenharmony_ci
16019625d8cSopenharmony_ci    let output = utils::get_long_help::<Opt4>();
16119625d8cSopenharmony_ci
16219625d8cSopenharmony_ci    assert!(output.contains("download history from remote"));
16319625d8cSopenharmony_ci    assert!(output.contains("Add a file"));
16419625d8cSopenharmony_ci    assert!(!output.contains("Not shown"));
16519625d8cSopenharmony_ci}
16619625d8cSopenharmony_ci
16719625d8cSopenharmony_ci#[test]
16819625d8cSopenharmony_cifn global_passed_down() {
16919625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Parser)]
17019625d8cSopenharmony_ci    struct Opt {
17119625d8cSopenharmony_ci        #[arg(global = true, long)]
17219625d8cSopenharmony_ci        other: bool,
17319625d8cSopenharmony_ci        #[command(subcommand)]
17419625d8cSopenharmony_ci        sub: Subcommands,
17519625d8cSopenharmony_ci    }
17619625d8cSopenharmony_ci
17719625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Subcommand)]
17819625d8cSopenharmony_ci    enum Subcommands {
17919625d8cSopenharmony_ci        Add,
18019625d8cSopenharmony_ci        Global(GlobalCmd),
18119625d8cSopenharmony_ci    }
18219625d8cSopenharmony_ci
18319625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Args)]
18419625d8cSopenharmony_ci    struct GlobalCmd {
18519625d8cSopenharmony_ci        #[arg(from_global)]
18619625d8cSopenharmony_ci        other: bool,
18719625d8cSopenharmony_ci    }
18819625d8cSopenharmony_ci
18919625d8cSopenharmony_ci    assert_eq!(
19019625d8cSopenharmony_ci        Opt::try_parse_from(["test", "global"]).unwrap(),
19119625d8cSopenharmony_ci        Opt {
19219625d8cSopenharmony_ci            other: false,
19319625d8cSopenharmony_ci            sub: Subcommands::Global(GlobalCmd { other: false })
19419625d8cSopenharmony_ci        }
19519625d8cSopenharmony_ci    );
19619625d8cSopenharmony_ci
19719625d8cSopenharmony_ci    assert_eq!(
19819625d8cSopenharmony_ci        Opt::try_parse_from(["test", "global", "--other"]).unwrap(),
19919625d8cSopenharmony_ci        Opt {
20019625d8cSopenharmony_ci            other: true,
20119625d8cSopenharmony_ci            sub: Subcommands::Global(GlobalCmd { other: true })
20219625d8cSopenharmony_ci        }
20319625d8cSopenharmony_ci    );
20419625d8cSopenharmony_ci}
20519625d8cSopenharmony_ci
20619625d8cSopenharmony_ci#[test]
20719625d8cSopenharmony_cifn external_subcommand() {
20819625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Parser)]
20919625d8cSopenharmony_ci    struct Opt {
21019625d8cSopenharmony_ci        #[command(subcommand)]
21119625d8cSopenharmony_ci        sub: Subcommands,
21219625d8cSopenharmony_ci    }
21319625d8cSopenharmony_ci
21419625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Subcommand)]
21519625d8cSopenharmony_ci    enum Subcommands {
21619625d8cSopenharmony_ci        Add,
21719625d8cSopenharmony_ci        Remove,
21819625d8cSopenharmony_ci        #[command(external_subcommand)]
21919625d8cSopenharmony_ci        Other(Vec<String>),
22019625d8cSopenharmony_ci    }
22119625d8cSopenharmony_ci
22219625d8cSopenharmony_ci    assert_eq!(
22319625d8cSopenharmony_ci        Opt::try_parse_from(["test", "add"]).unwrap(),
22419625d8cSopenharmony_ci        Opt {
22519625d8cSopenharmony_ci            sub: Subcommands::Add
22619625d8cSopenharmony_ci        }
22719625d8cSopenharmony_ci    );
22819625d8cSopenharmony_ci
22919625d8cSopenharmony_ci    assert_eq!(
23019625d8cSopenharmony_ci        Opt::try_parse_from(["test", "remove"]).unwrap(),
23119625d8cSopenharmony_ci        Opt {
23219625d8cSopenharmony_ci            sub: Subcommands::Remove
23319625d8cSopenharmony_ci        }
23419625d8cSopenharmony_ci    );
23519625d8cSopenharmony_ci
23619625d8cSopenharmony_ci    assert!(Opt::try_parse_from(["test"]).is_err());
23719625d8cSopenharmony_ci
23819625d8cSopenharmony_ci    assert_eq!(
23919625d8cSopenharmony_ci        Opt::try_parse_from(["test", "git", "status"]).unwrap(),
24019625d8cSopenharmony_ci        Opt {
24119625d8cSopenharmony_ci            sub: Subcommands::Other(vec!["git".into(), "status".into()])
24219625d8cSopenharmony_ci        }
24319625d8cSopenharmony_ci    );
24419625d8cSopenharmony_ci}
24519625d8cSopenharmony_ci
24619625d8cSopenharmony_ci#[test]
24719625d8cSopenharmony_cifn external_subcommand_os_string() {
24819625d8cSopenharmony_ci    use std::ffi::OsString;
24919625d8cSopenharmony_ci
25019625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Parser)]
25119625d8cSopenharmony_ci    struct Opt {
25219625d8cSopenharmony_ci        #[command(subcommand)]
25319625d8cSopenharmony_ci        sub: Subcommands,
25419625d8cSopenharmony_ci    }
25519625d8cSopenharmony_ci
25619625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Subcommand)]
25719625d8cSopenharmony_ci    enum Subcommands {
25819625d8cSopenharmony_ci        #[command(external_subcommand)]
25919625d8cSopenharmony_ci        Other(Vec<OsString>),
26019625d8cSopenharmony_ci    }
26119625d8cSopenharmony_ci
26219625d8cSopenharmony_ci    assert_eq!(
26319625d8cSopenharmony_ci        Opt::try_parse_from(["test", "git", "status"]).unwrap(),
26419625d8cSopenharmony_ci        Opt {
26519625d8cSopenharmony_ci            sub: Subcommands::Other(vec!["git".into(), "status".into()])
26619625d8cSopenharmony_ci        }
26719625d8cSopenharmony_ci    );
26819625d8cSopenharmony_ci
26919625d8cSopenharmony_ci    assert!(Opt::try_parse_from(["test"]).is_err());
27019625d8cSopenharmony_ci}
27119625d8cSopenharmony_ci
27219625d8cSopenharmony_ci#[test]
27319625d8cSopenharmony_cifn external_subcommand_optional() {
27419625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Parser)]
27519625d8cSopenharmony_ci    struct Opt {
27619625d8cSopenharmony_ci        #[command(subcommand)]
27719625d8cSopenharmony_ci        sub: Option<Subcommands>,
27819625d8cSopenharmony_ci    }
27919625d8cSopenharmony_ci
28019625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Subcommand)]
28119625d8cSopenharmony_ci    enum Subcommands {
28219625d8cSopenharmony_ci        #[command(external_subcommand)]
28319625d8cSopenharmony_ci        Other(Vec<String>),
28419625d8cSopenharmony_ci    }
28519625d8cSopenharmony_ci
28619625d8cSopenharmony_ci    assert_eq!(
28719625d8cSopenharmony_ci        Opt::try_parse_from(["test", "git", "status"]).unwrap(),
28819625d8cSopenharmony_ci        Opt {
28919625d8cSopenharmony_ci            sub: Some(Subcommands::Other(vec!["git".into(), "status".into()]))
29019625d8cSopenharmony_ci        }
29119625d8cSopenharmony_ci    );
29219625d8cSopenharmony_ci
29319625d8cSopenharmony_ci    assert_eq!(Opt::try_parse_from(["test"]).unwrap(), Opt { sub: None });
29419625d8cSopenharmony_ci}
29519625d8cSopenharmony_ci
29619625d8cSopenharmony_ci#[test]
29719625d8cSopenharmony_cifn enum_in_enum_subsubcommand() {
29819625d8cSopenharmony_ci    #[derive(Parser, Debug, PartialEq, Eq)]
29919625d8cSopenharmony_ci    pub enum Opt {
30019625d8cSopenharmony_ci        #[command(alias = "l")]
30119625d8cSopenharmony_ci        List,
30219625d8cSopenharmony_ci        #[command(subcommand, alias = "d")]
30319625d8cSopenharmony_ci        Daemon(DaemonCommand),
30419625d8cSopenharmony_ci    }
30519625d8cSopenharmony_ci
30619625d8cSopenharmony_ci    #[derive(Subcommand, Debug, PartialEq, Eq)]
30719625d8cSopenharmony_ci    pub enum DaemonCommand {
30819625d8cSopenharmony_ci        Start,
30919625d8cSopenharmony_ci        Stop,
31019625d8cSopenharmony_ci    }
31119625d8cSopenharmony_ci
31219625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test"]);
31319625d8cSopenharmony_ci    assert!(result.is_err());
31419625d8cSopenharmony_ci
31519625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "list"]).unwrap();
31619625d8cSopenharmony_ci    assert_eq!(Opt::List, result);
31719625d8cSopenharmony_ci
31819625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "l"]).unwrap();
31919625d8cSopenharmony_ci    assert_eq!(Opt::List, result);
32019625d8cSopenharmony_ci
32119625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "daemon"]);
32219625d8cSopenharmony_ci    assert!(result.is_err());
32319625d8cSopenharmony_ci
32419625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "daemon", "start"]).unwrap();
32519625d8cSopenharmony_ci    assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
32619625d8cSopenharmony_ci
32719625d8cSopenharmony_ci    let result = Opt::try_parse_from(["test", "d", "start"]).unwrap();
32819625d8cSopenharmony_ci    assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
32919625d8cSopenharmony_ci}
33019625d8cSopenharmony_ci
33119625d8cSopenharmony_ci#[test]
33219625d8cSopenharmony_cifn update_subcommands() {
33319625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
33419625d8cSopenharmony_ci    enum Opt {
33519625d8cSopenharmony_ci        Command1(Command1),
33619625d8cSopenharmony_ci        Command2(Command2),
33719625d8cSopenharmony_ci    }
33819625d8cSopenharmony_ci
33919625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
34019625d8cSopenharmony_ci    struct Command1 {
34119625d8cSopenharmony_ci        arg1: i32,
34219625d8cSopenharmony_ci
34319625d8cSopenharmony_ci        arg2: i32,
34419625d8cSopenharmony_ci    }
34519625d8cSopenharmony_ci
34619625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
34719625d8cSopenharmony_ci    struct Command2 {
34819625d8cSopenharmony_ci        arg2: i32,
34919625d8cSopenharmony_ci    }
35019625d8cSopenharmony_ci
35119625d8cSopenharmony_ci    // Full subcommand update
35219625d8cSopenharmony_ci    let mut opt = Opt::Command1(Command1 { arg1: 12, arg2: 14 });
35319625d8cSopenharmony_ci    opt.try_update_from(["test", "command1", "42", "44"])
35419625d8cSopenharmony_ci        .unwrap();
35519625d8cSopenharmony_ci    assert_eq!(
35619625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command1", "42", "44"]).unwrap(),
35719625d8cSopenharmony_ci        opt
35819625d8cSopenharmony_ci    );
35919625d8cSopenharmony_ci
36019625d8cSopenharmony_ci    // Partial subcommand update
36119625d8cSopenharmony_ci    let mut opt = Opt::Command1(Command1 { arg1: 12, arg2: 14 });
36219625d8cSopenharmony_ci    opt.try_update_from(["test", "command1", "42"]).unwrap();
36319625d8cSopenharmony_ci    assert_eq!(
36419625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command1", "42", "14"]).unwrap(),
36519625d8cSopenharmony_ci        opt
36619625d8cSopenharmony_ci    );
36719625d8cSopenharmony_ci
36819625d8cSopenharmony_ci    // Change subcommand
36919625d8cSopenharmony_ci    let mut opt = Opt::Command1(Command1 { arg1: 12, arg2: 14 });
37019625d8cSopenharmony_ci    opt.try_update_from(["test", "command2", "43"]).unwrap();
37119625d8cSopenharmony_ci    assert_eq!(
37219625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command2", "43"]).unwrap(),
37319625d8cSopenharmony_ci        opt
37419625d8cSopenharmony_ci    );
37519625d8cSopenharmony_ci}
37619625d8cSopenharmony_ci
37719625d8cSopenharmony_ci#[test]
37819625d8cSopenharmony_cifn update_subcommands_explicit_required() {
37919625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
38019625d8cSopenharmony_ci    #[command(subcommand_required = true)]
38119625d8cSopenharmony_ci    enum Opt {
38219625d8cSopenharmony_ci        Command1(Command1),
38319625d8cSopenharmony_ci        Command2(Command2),
38419625d8cSopenharmony_ci    }
38519625d8cSopenharmony_ci
38619625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
38719625d8cSopenharmony_ci    struct Command1 {
38819625d8cSopenharmony_ci        arg1: i32,
38919625d8cSopenharmony_ci
39019625d8cSopenharmony_ci        arg2: i32,
39119625d8cSopenharmony_ci    }
39219625d8cSopenharmony_ci
39319625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
39419625d8cSopenharmony_ci    struct Command2 {
39519625d8cSopenharmony_ci        arg2: i32,
39619625d8cSopenharmony_ci    }
39719625d8cSopenharmony_ci
39819625d8cSopenharmony_ci    // Full subcommand update
39919625d8cSopenharmony_ci    let mut opt = Opt::Command1(Command1 { arg1: 12, arg2: 14 });
40019625d8cSopenharmony_ci    opt.try_update_from(["test"]).unwrap();
40119625d8cSopenharmony_ci    assert_eq!(Opt::Command1(Command1 { arg1: 12, arg2: 14 }), opt);
40219625d8cSopenharmony_ci}
40319625d8cSopenharmony_ci
40419625d8cSopenharmony_ci#[test]
40519625d8cSopenharmony_cifn update_sub_subcommands() {
40619625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
40719625d8cSopenharmony_ci    enum Opt {
40819625d8cSopenharmony_ci        #[command(subcommand)]
40919625d8cSopenharmony_ci        Child1(Child1),
41019625d8cSopenharmony_ci        #[command(subcommand)]
41119625d8cSopenharmony_ci        Child2(Child2),
41219625d8cSopenharmony_ci    }
41319625d8cSopenharmony_ci
41419625d8cSopenharmony_ci    #[derive(Subcommand, PartialEq, Eq, Debug)]
41519625d8cSopenharmony_ci    enum Child1 {
41619625d8cSopenharmony_ci        Command1(Command1),
41719625d8cSopenharmony_ci        Command2(Command2),
41819625d8cSopenharmony_ci    }
41919625d8cSopenharmony_ci
42019625d8cSopenharmony_ci    #[derive(Subcommand, PartialEq, Eq, Debug)]
42119625d8cSopenharmony_ci    enum Child2 {
42219625d8cSopenharmony_ci        Command1(Command1),
42319625d8cSopenharmony_ci        Command2(Command2),
42419625d8cSopenharmony_ci    }
42519625d8cSopenharmony_ci
42619625d8cSopenharmony_ci    #[derive(Args, PartialEq, Eq, Debug)]
42719625d8cSopenharmony_ci    struct Command1 {
42819625d8cSopenharmony_ci        arg1: i32,
42919625d8cSopenharmony_ci
43019625d8cSopenharmony_ci        arg2: i32,
43119625d8cSopenharmony_ci    }
43219625d8cSopenharmony_ci
43319625d8cSopenharmony_ci    #[derive(Args, PartialEq, Eq, Debug)]
43419625d8cSopenharmony_ci    struct Command2 {
43519625d8cSopenharmony_ci        arg2: i32,
43619625d8cSopenharmony_ci    }
43719625d8cSopenharmony_ci
43819625d8cSopenharmony_ci    // Full subcommand update
43919625d8cSopenharmony_ci    let mut opt = Opt::Child1(Child1::Command1(Command1 { arg1: 12, arg2: 14 }));
44019625d8cSopenharmony_ci    opt.try_update_from(["test", "child1", "command1", "42", "44"])
44119625d8cSopenharmony_ci        .unwrap();
44219625d8cSopenharmony_ci    assert_eq!(
44319625d8cSopenharmony_ci        Opt::try_parse_from(["test", "child1", "command1", "42", "44"]).unwrap(),
44419625d8cSopenharmony_ci        opt
44519625d8cSopenharmony_ci    );
44619625d8cSopenharmony_ci
44719625d8cSopenharmony_ci    // Partial subcommand update
44819625d8cSopenharmony_ci    let mut opt = Opt::Child1(Child1::Command1(Command1 { arg1: 12, arg2: 14 }));
44919625d8cSopenharmony_ci    opt.try_update_from(["test", "child1", "command1", "42"])
45019625d8cSopenharmony_ci        .unwrap();
45119625d8cSopenharmony_ci    assert_eq!(
45219625d8cSopenharmony_ci        Opt::try_parse_from(["test", "child1", "command1", "42", "14"]).unwrap(),
45319625d8cSopenharmony_ci        opt
45419625d8cSopenharmony_ci    );
45519625d8cSopenharmony_ci
45619625d8cSopenharmony_ci    // Partial subcommand update
45719625d8cSopenharmony_ci    let mut opt = Opt::Child1(Child1::Command1(Command1 { arg1: 12, arg2: 14 }));
45819625d8cSopenharmony_ci    opt.try_update_from(["test", "child1", "command2", "43"])
45919625d8cSopenharmony_ci        .unwrap();
46019625d8cSopenharmony_ci    assert_eq!(
46119625d8cSopenharmony_ci        Opt::try_parse_from(["test", "child1", "command2", "43"]).unwrap(),
46219625d8cSopenharmony_ci        opt
46319625d8cSopenharmony_ci    );
46419625d8cSopenharmony_ci
46519625d8cSopenharmony_ci    // Change subcommand
46619625d8cSopenharmony_ci    let mut opt = Opt::Child1(Child1::Command1(Command1 { arg1: 12, arg2: 14 }));
46719625d8cSopenharmony_ci    opt.try_update_from(["test", "child2", "command2", "43"])
46819625d8cSopenharmony_ci        .unwrap();
46919625d8cSopenharmony_ci    assert_eq!(
47019625d8cSopenharmony_ci        Opt::try_parse_from(["test", "child2", "command2", "43"]).unwrap(),
47119625d8cSopenharmony_ci        opt
47219625d8cSopenharmony_ci    );
47319625d8cSopenharmony_ci}
47419625d8cSopenharmony_ci
47519625d8cSopenharmony_ci#[test]
47619625d8cSopenharmony_cifn update_ext_subcommand() {
47719625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
47819625d8cSopenharmony_ci    enum Opt {
47919625d8cSopenharmony_ci        Command1(Command1),
48019625d8cSopenharmony_ci        Command2(Command2),
48119625d8cSopenharmony_ci        #[command(external_subcommand)]
48219625d8cSopenharmony_ci        Ext(Vec<String>),
48319625d8cSopenharmony_ci    }
48419625d8cSopenharmony_ci
48519625d8cSopenharmony_ci    #[derive(Args, PartialEq, Eq, Debug)]
48619625d8cSopenharmony_ci    struct Command1 {
48719625d8cSopenharmony_ci        arg1: i32,
48819625d8cSopenharmony_ci
48919625d8cSopenharmony_ci        arg2: i32,
49019625d8cSopenharmony_ci    }
49119625d8cSopenharmony_ci
49219625d8cSopenharmony_ci    #[derive(Args, PartialEq, Eq, Debug)]
49319625d8cSopenharmony_ci    struct Command2 {
49419625d8cSopenharmony_ci        arg2: i32,
49519625d8cSopenharmony_ci    }
49619625d8cSopenharmony_ci
49719625d8cSopenharmony_ci    // Full subcommand update
49819625d8cSopenharmony_ci    let mut opt = Opt::Ext(vec!["12".into(), "14".into()]);
49919625d8cSopenharmony_ci    opt.try_update_from(["test", "ext", "42", "44"]).unwrap();
50019625d8cSopenharmony_ci    assert_eq!(
50119625d8cSopenharmony_ci        Opt::try_parse_from(["test", "ext", "42", "44"]).unwrap(),
50219625d8cSopenharmony_ci        opt
50319625d8cSopenharmony_ci    );
50419625d8cSopenharmony_ci
50519625d8cSopenharmony_ci    // No partial subcommand update
50619625d8cSopenharmony_ci    let mut opt = Opt::Ext(vec!["12".into(), "14".into()]);
50719625d8cSopenharmony_ci    opt.try_update_from(["test", "ext", "42"]).unwrap();
50819625d8cSopenharmony_ci    assert_eq!(Opt::try_parse_from(["test", "ext", "42"]).unwrap(), opt);
50919625d8cSopenharmony_ci
51019625d8cSopenharmony_ci    // Change subcommand
51119625d8cSopenharmony_ci    let mut opt = Opt::Ext(vec!["12".into(), "14".into()]);
51219625d8cSopenharmony_ci    opt.try_update_from(["test", "command2", "43"]).unwrap();
51319625d8cSopenharmony_ci    assert_eq!(
51419625d8cSopenharmony_ci        Opt::try_parse_from(["test", "command2", "43"]).unwrap(),
51519625d8cSopenharmony_ci        opt
51619625d8cSopenharmony_ci    );
51719625d8cSopenharmony_ci
51819625d8cSopenharmony_ci    let mut opt = Opt::Command1(Command1 { arg1: 12, arg2: 14 });
51919625d8cSopenharmony_ci    opt.try_update_from(["test", "ext", "42", "44"]).unwrap();
52019625d8cSopenharmony_ci    assert_eq!(
52119625d8cSopenharmony_ci        Opt::try_parse_from(["test", "ext", "42", "44"]).unwrap(),
52219625d8cSopenharmony_ci        opt
52319625d8cSopenharmony_ci    );
52419625d8cSopenharmony_ci}
52519625d8cSopenharmony_ci#[test]
52619625d8cSopenharmony_cifn subcommand_name_not_literal() {
52719625d8cSopenharmony_ci    fn get_name() -> &'static str {
52819625d8cSopenharmony_ci        "renamed"
52919625d8cSopenharmony_ci    }
53019625d8cSopenharmony_ci
53119625d8cSopenharmony_ci    #[derive(Parser, PartialEq, Eq, Debug)]
53219625d8cSopenharmony_ci    struct Opt {
53319625d8cSopenharmony_ci        #[command(subcommand)]
53419625d8cSopenharmony_ci        subcmd: SubCmd,
53519625d8cSopenharmony_ci    }
53619625d8cSopenharmony_ci
53719625d8cSopenharmony_ci    #[derive(Subcommand, PartialEq, Eq, Debug)]
53819625d8cSopenharmony_ci    enum SubCmd {
53919625d8cSopenharmony_ci        #[command(name = get_name())]
54019625d8cSopenharmony_ci        SubCmd1,
54119625d8cSopenharmony_ci    }
54219625d8cSopenharmony_ci
54319625d8cSopenharmony_ci    assert!(Opt::try_parse_from(["test", "renamed"]).is_ok());
54419625d8cSopenharmony_ci}
54519625d8cSopenharmony_ci
54619625d8cSopenharmony_ci#[test]
54719625d8cSopenharmony_cifn skip_subcommand() {
54819625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Parser)]
54919625d8cSopenharmony_ci    struct Opt {
55019625d8cSopenharmony_ci        #[command(subcommand)]
55119625d8cSopenharmony_ci        sub: Subcommands,
55219625d8cSopenharmony_ci    }
55319625d8cSopenharmony_ci
55419625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Subcommand)]
55519625d8cSopenharmony_ci    enum Subcommands {
55619625d8cSopenharmony_ci        Add,
55719625d8cSopenharmony_ci        Remove,
55819625d8cSopenharmony_ci
55919625d8cSopenharmony_ci        #[allow(dead_code)]
56019625d8cSopenharmony_ci        #[command(skip)]
56119625d8cSopenharmony_ci        Skip,
56219625d8cSopenharmony_ci
56319625d8cSopenharmony_ci        #[allow(dead_code)]
56419625d8cSopenharmony_ci        #[command(skip)]
56519625d8cSopenharmony_ci        Other(Other),
56619625d8cSopenharmony_ci    }
56719625d8cSopenharmony_ci
56819625d8cSopenharmony_ci    #[allow(dead_code)]
56919625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq)]
57019625d8cSopenharmony_ci    enum Other {
57119625d8cSopenharmony_ci        One,
57219625d8cSopenharmony_ci        Twp,
57319625d8cSopenharmony_ci    }
57419625d8cSopenharmony_ci
57519625d8cSopenharmony_ci    assert!(Subcommands::has_subcommand("add"));
57619625d8cSopenharmony_ci    assert!(Subcommands::has_subcommand("remove"));
57719625d8cSopenharmony_ci    assert!(!Subcommands::has_subcommand("skip"));
57819625d8cSopenharmony_ci    assert!(!Subcommands::has_subcommand("other"));
57919625d8cSopenharmony_ci
58019625d8cSopenharmony_ci    assert_eq!(
58119625d8cSopenharmony_ci        Opt::try_parse_from(["test", "add"]).unwrap(),
58219625d8cSopenharmony_ci        Opt {
58319625d8cSopenharmony_ci            sub: Subcommands::Add
58419625d8cSopenharmony_ci        }
58519625d8cSopenharmony_ci    );
58619625d8cSopenharmony_ci
58719625d8cSopenharmony_ci    assert_eq!(
58819625d8cSopenharmony_ci        Opt::try_parse_from(["test", "remove"]).unwrap(),
58919625d8cSopenharmony_ci        Opt {
59019625d8cSopenharmony_ci            sub: Subcommands::Remove
59119625d8cSopenharmony_ci        }
59219625d8cSopenharmony_ci    );
59319625d8cSopenharmony_ci
59419625d8cSopenharmony_ci    let res = Opt::try_parse_from(["test", "skip"]);
59519625d8cSopenharmony_ci    assert_eq!(
59619625d8cSopenharmony_ci        res.unwrap_err().kind(),
59719625d8cSopenharmony_ci        clap::error::ErrorKind::InvalidSubcommand,
59819625d8cSopenharmony_ci    );
59919625d8cSopenharmony_ci
60019625d8cSopenharmony_ci    let res = Opt::try_parse_from(["test", "other"]);
60119625d8cSopenharmony_ci    assert_eq!(
60219625d8cSopenharmony_ci        res.unwrap_err().kind(),
60319625d8cSopenharmony_ci        clap::error::ErrorKind::InvalidSubcommand,
60419625d8cSopenharmony_ci    );
60519625d8cSopenharmony_ci}
60619625d8cSopenharmony_ci
60719625d8cSopenharmony_ci#[test]
60819625d8cSopenharmony_cifn built_in_subcommand_escaped() {
60919625d8cSopenharmony_ci    #[derive(Debug, PartialEq, Eq, Parser)]
61019625d8cSopenharmony_ci    enum Command {
61119625d8cSopenharmony_ci        Install {
61219625d8cSopenharmony_ci            arg: Option<String>,
61319625d8cSopenharmony_ci        },
61419625d8cSopenharmony_ci        #[command(external_subcommand)]
61519625d8cSopenharmony_ci        Custom(Vec<String>),
61619625d8cSopenharmony_ci    }
61719625d8cSopenharmony_ci
61819625d8cSopenharmony_ci    assert_eq!(
61919625d8cSopenharmony_ci        Command::try_parse_from(["test", "install", "arg"]).unwrap(),
62019625d8cSopenharmony_ci        Command::Install {
62119625d8cSopenharmony_ci            arg: Some(String::from("arg"))
62219625d8cSopenharmony_ci        }
62319625d8cSopenharmony_ci    );
62419625d8cSopenharmony_ci    assert_eq!(
62519625d8cSopenharmony_ci        Command::try_parse_from(["test", "--", "install"]).unwrap(),
62619625d8cSopenharmony_ci        Command::Custom(vec![String::from("install")])
62719625d8cSopenharmony_ci    );
62819625d8cSopenharmony_ci    assert_eq!(
62919625d8cSopenharmony_ci        Command::try_parse_from(["test", "--", "install", "arg"]).unwrap(),
63019625d8cSopenharmony_ci        Command::Custom(vec![String::from("install"), String::from("arg")])
63119625d8cSopenharmony_ci    );
63219625d8cSopenharmony_ci}
633