--- /dev/null
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt {
+ /// Fetch stuff from GitHub
+ Fetch {
+ #[structopt(long)]
+ all: bool,
+ #[structopt(short, long)]
+ /// Overwrite local branches.
+ force: bool,
+ repo: String,
+ },
+
+ Add {
+ #[structopt(short, long)]
+ interactive: bool,
+ #[structopt(short, long)]
+ verbose: bool,
+ },
+}
+
+#[test]
+fn test_fetch() {
+ assert_eq!(
+ Opt::Fetch {
+ all: true,
+ force: false,
+ repo: "origin".to_string()
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"]))
+ );
+ assert_eq!(
+ Opt::Fetch {
+ all: false,
+ force: true,
+ repo: "origin".to_string()
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"]))
+ );
+}
+
+#[test]
+fn test_add() {
+ assert_eq!(
+ Opt::Add {
+ interactive: false,
+ verbose: false
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
+ );
+ assert_eq!(
+ Opt::Add {
+ interactive: true,
+ verbose: true
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"]))
+ );
+}
+
+#[test]
+fn test_no_parse() {
+ let result = Opt::clap().get_matches_from_safe(&["test", "badcmd", "-i", "-v"]);
+ assert!(result.is_err());
+
+ let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badoption"]);
+ assert!(result.is_err());
+
+ let result = Opt::clap().get_matches_from_safe(&["test"]);
+ assert!(result.is_err());
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt2 {
+ DoSomething { arg: String },
+}
+
+#[test]
+/// This test is specifically to make sure that hyphenated subcommands get
+/// processed correctly.
+fn test_hyphenated_subcommands() {
+ assert_eq!(
+ Opt2::DoSomething {
+ arg: "blah".to_string()
+ },
+ Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"]))
+ );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt3 {
+ Add,
+ Init,
+ Fetch,
+}
+
+#[test]
+fn test_null_commands() {
+ assert_eq!(
+ Opt3::Add,
+ Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"]))
+ );
+ assert_eq!(
+ Opt3::Init,
+ Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"]))
+ );
+ assert_eq!(
+ Opt3::Fetch,
+ Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"]))
+ );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+#[structopt(about = "Not shown")]
+struct Add {
+ file: String,
+}
+/// Not shown
+#[derive(StructOpt, PartialEq, Debug)]
+struct Fetch {
+ remote: String,
+}
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt4 {
+ // Not shown
+ /// Add a file
+ Add(Add),
+ Init,
+ /// download history from remote
+ Fetch(Fetch),
+}
+
+#[test]
+fn test_tuple_commands() {
+ assert_eq!(
+ Opt4::Add(Add {
+ file: "f".to_string()
+ }),
+ Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "add", "f"]))
+ );
+ assert_eq!(
+ Opt4::Init,
+ Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"]))
+ );
+ assert_eq!(
+ Opt4::Fetch(Fetch {
+ remote: "origin".to_string()
+ }),
+ Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "fetch", "origin"]))
+ );
+
+ let output = get_long_help::<Opt4>();
+
+ assert!(output.contains("download history from remote"));
+ assert!(output.contains("Add a file"));
+ assert!(!output.contains("Not shown"));
+}
+
+#[test]
+fn enum_in_enum_subsubcommand() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub enum Opt {
+ Daemon(DaemonCommand),
+ }
+
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub enum DaemonCommand {
+ Start,
+ Stop,
+ }
+
+ let result = Opt::clap().get_matches_from_safe(&["test"]);
+ assert!(result.is_err());
+
+ let result = Opt::clap().get_matches_from_safe(&["test", "daemon"]);
+ assert!(result.is_err());
+
+ let result = Opt::from_iter(&["test", "daemon", "start"]);
+ assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
+}
+
+#[test]
+fn flatten_enum() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(flatten)]
+ sub_cmd: SubCmd,
+ }
+ #[derive(StructOpt, Debug, PartialEq)]
+ enum SubCmd {
+ Foo,
+ Bar,
+ }
+
+ assert!(Opt::from_iter_safe(&["test"]).is_err());
+ assert_eq!(
+ Opt::from_iter(&["test", "foo"]),
+ Opt {
+ sub_cmd: SubCmd::Foo
+ }
+ );
+}
+
+#[test]
+fn external_subcommand() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ struct Opt {
+ #[structopt(subcommand)]
+ sub: Subcommands,
+ }
+
+ #[derive(Debug, PartialEq, StructOpt)]
+ enum Subcommands {
+ Add,
+ Remove,
+ #[structopt(external_subcommand)]
+ Other(Vec<String>),
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "add"]),
+ Opt {
+ sub: Subcommands::Add
+ }
+ );
+
+ assert_eq!(
+ Opt::from_iter(&["test", "remove"]),
+ Opt {
+ sub: Subcommands::Remove
+ }
+ );
+
+ assert_eq!(
+ Opt::from_iter(&["test", "git", "status"]),
+ Opt {
+ sub: Subcommands::Other(vec!["git".into(), "status".into()])
+ }
+ );
+
+ assert!(Opt::from_iter_safe(&["test"]).is_err());
+}
+
+#[test]
+fn external_subcommand_os_string() {
+ use std::ffi::OsString;
+
+ #[derive(Debug, PartialEq, StructOpt)]
+ struct Opt {
+ #[structopt(subcommand)]
+ sub: Subcommands,
+ }
+
+ #[derive(Debug, PartialEq, StructOpt)]
+ enum Subcommands {
+ #[structopt(external_subcommand)]
+ Other(Vec<OsString>),
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "git", "status"]),
+ Opt {
+ sub: Subcommands::Other(vec!["git".into(), "status".into()])
+ }
+ );
+
+ assert!(Opt::from_iter_safe(&["test"]).is_err());
+}
+
+#[test]
+fn external_subcommand_optional() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ struct Opt {
+ #[structopt(subcommand)]
+ sub: Option<Subcommands>,
+ }
+
+ #[derive(Debug, PartialEq, StructOpt)]
+ enum Subcommands {
+ #[structopt(external_subcommand)]
+ Other(Vec<String>),
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "git", "status"]),
+ Opt {
+ sub: Some(Subcommands::Other(vec!["git".into(), "status".into()]))
+ }
+ );
+
+ assert_eq!(Opt::from_iter(&["test"]), Opt { sub: None });
+}