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