1 // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 #[macro_use]
10 extern crate structopt;
11 
12 use structopt::StructOpt;
13 
14 #[derive(StructOpt, PartialEq, Debug)]
15 struct Opt {
16     #[structopt(short = "f", long = "force")]
17     force: bool,
18     #[structopt(short = "v", long = "verbose", parse(from_occurrences))]
19     verbose: u64,
20     #[structopt(subcommand)]
21     cmd: Sub,
22 }
23 
24 #[derive(StructOpt, PartialEq, Debug)]
25 enum Sub {
26     #[structopt(name = "fetch")]
27     Fetch {},
28     #[structopt(name = "add")]
29     Add {},
30 }
31 
32 #[derive(StructOpt, PartialEq, Debug)]
33 struct Opt2 {
34     #[structopt(short = "f", long = "force")]
35     force: bool,
36     #[structopt(short = "v", long = "verbose", parse(from_occurrences))]
37     verbose: u64,
38     #[structopt(subcommand)]
39     cmd: Option<Sub>,
40 }
41 
42 #[test]
test_no_cmd()43 fn test_no_cmd() {
44     let result = Opt::clap().get_matches_from_safe(&["test"]);
45     assert!(result.is_err());
46 
47     assert_eq!(
48         Opt2 {
49             force: false,
50             verbose: 0,
51             cmd: None
52         },
53         Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"]))
54     );
55 }
56 
57 #[test]
test_fetch()58 fn test_fetch() {
59     assert_eq!(
60         Opt {
61             force: false,
62             verbose: 3,
63             cmd: Sub::Fetch {}
64         },
65         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"]))
66     );
67     assert_eq!(
68         Opt {
69             force: true,
70             verbose: 0,
71             cmd: Sub::Fetch {}
72         },
73         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"]))
74     );
75 }
76 
77 #[test]
test_add()78 fn test_add() {
79     assert_eq!(
80         Opt {
81             force: false,
82             verbose: 0,
83             cmd: Sub::Add {}
84         },
85         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
86     );
87     assert_eq!(
88         Opt {
89             force: false,
90             verbose: 2,
91             cmd: Sub::Add {}
92         },
93         Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"]))
94     );
95 }
96 
97 #[test]
test_badinput()98 fn test_badinput() {
99     let result = Opt::clap().get_matches_from_safe(&["test", "badcmd"]);
100     assert!(result.is_err());
101     let result = Opt::clap().get_matches_from_safe(&["test", "add", "--verbose"]);
102     assert!(result.is_err());
103     let result = Opt::clap().get_matches_from_safe(&["test", "--badopt", "add"]);
104     assert!(result.is_err());
105     let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badopt"]);
106     assert!(result.is_err());
107 }
108 
109 #[derive(StructOpt, PartialEq, Debug)]
110 struct Opt3 {
111     #[structopt(short = "a", long = "all")]
112     all: bool,
113     #[structopt(subcommand)]
114     cmd: Sub2,
115 }
116 
117 #[derive(StructOpt, PartialEq, Debug)]
118 enum Sub2 {
119     #[structopt(name = "foo")]
120     Foo {
121         file: String,
122         #[structopt(subcommand)]
123         cmd: Sub3,
124     },
125     #[structopt(name = "bar")]
126     Bar {},
127 }
128 
129 #[derive(StructOpt, PartialEq, Debug)]
130 enum Sub3 {
131     #[structopt(name = "baz")]
132     Baz {},
133     #[structopt(name = "quux")]
134     Quux {},
135 }
136 
137 #[test]
test_subsubcommand()138 fn test_subsubcommand() {
139     assert_eq!(
140         Opt3 {
141             all: true,
142             cmd: Sub2::Foo {
143                 file: "lib.rs".to_string(),
144                 cmd: Sub3::Quux {}
145             }
146         },
147         Opt3::from_clap(
148             &Opt3::clap().get_matches_from(&["test", "--all", "foo", "lib.rs", "quux"])
149         )
150     );
151 }
152 
153 #[derive(StructOpt, PartialEq, Debug)]
154 enum SubSubCmdWithOption {
155     #[structopt(name = "remote")]
156     Remote {
157         #[structopt(subcommand)]
158         cmd: Option<Remote>,
159     },
160     #[structopt(name = "stash")]
161     Stash {
162         #[structopt(subcommand)]
163         cmd: Stash,
164     },
165 }
166 #[derive(StructOpt, PartialEq, Debug)]
167 enum Remote {
168     #[structopt(name = "add")]
169     Add { name: String, url: String },
170     #[structopt(name = "remove")]
171     Remove { name: String },
172 }
173 
174 #[derive(StructOpt, PartialEq, Debug)]
175 enum Stash {
176     #[structopt(name = "save")]
177     Save,
178     #[structopt(name = "pop")]
179     Pop,
180 }
181 
182 #[test]
sub_sub_cmd_with_option()183 fn sub_sub_cmd_with_option() {
184     fn make(args: &[&str]) -> Option<SubSubCmdWithOption> {
185         SubSubCmdWithOption::clap()
186             .get_matches_from_safe(args)
187             .ok()
188             .map(|m| SubSubCmdWithOption::from_clap(&m))
189     }
190     assert_eq!(
191         Some(SubSubCmdWithOption::Remote { cmd: None }),
192         make(&["", "remote"])
193     );
194     assert_eq!(
195         Some(SubSubCmdWithOption::Remote {
196             cmd: Some(Remote::Add {
197                 name: "origin".into(),
198                 url: "http".into()
199             })
200         }),
201         make(&["", "remote", "add", "origin", "http"])
202     );
203     assert_eq!(
204         Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }),
205         make(&["", "stash", "save"])
206     );
207     assert_eq!(None, make(&["", "stash"]));
208 }
209