1 // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
2 // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
3 // Ana Hobden (@hoverbear) <operator@hoverbear.org>
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 //
11 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13 // MIT/Apache 2.0 license.
14
15 use crate::utils;
16
17 use clap::{Args, Parser, Subcommand};
18
19 #[test]
flatten()20 fn flatten() {
21 #[derive(Args, PartialEq, Debug)]
22 struct Common {
23 arg: i32,
24 }
25
26 #[derive(Parser, PartialEq, Debug)]
27 struct Opt {
28 #[command(flatten)]
29 common: Common,
30 }
31 assert_eq!(
32 Opt {
33 common: Common { arg: 42 }
34 },
35 Opt::try_parse_from(["test", "42"]).unwrap()
36 );
37 assert!(Opt::try_parse_from(["test"]).is_err());
38 assert!(Opt::try_parse_from(["test", "42", "24"]).is_err());
39 }
40
41 #[cfg(debug_assertions)]
42 #[test]
43 #[should_panic]
flatten_twice()44 fn flatten_twice() {
45 #[derive(Args, PartialEq, Debug)]
46 struct Common {
47 arg: i32,
48 }
49
50 #[derive(Parser, PartialEq, Debug)]
51 struct Opt {
52 #[command(flatten)]
53 c1: Common,
54 // Defines "arg" twice, so this should not work.
55 #[command(flatten)]
56 c2: Common,
57 }
58 Opt::try_parse_from(["test", "42", "43"]).unwrap();
59 }
60
61 #[test]
flatten_in_subcommand()62 fn flatten_in_subcommand() {
63 #[derive(Args, PartialEq, Debug)]
64 struct Common {
65 arg: i32,
66 }
67
68 #[derive(Args, PartialEq, Debug)]
69 struct Add {
70 #[arg(short)]
71 interactive: bool,
72 #[command(flatten)]
73 common: Common,
74 }
75
76 #[derive(Parser, PartialEq, Debug)]
77 enum Opt {
78 Fetch {
79 #[arg(short)]
80 all: bool,
81 #[command(flatten)]
82 common: Common,
83 },
84
85 Add(Add),
86 }
87
88 assert_eq!(
89 Opt::Fetch {
90 all: false,
91 common: Common { arg: 42 }
92 },
93 Opt::try_parse_from(["test", "fetch", "42"]).unwrap()
94 );
95 assert_eq!(
96 Opt::Add(Add {
97 interactive: true,
98 common: Common { arg: 43 }
99 }),
100 Opt::try_parse_from(["test", "add", "-i", "43"]).unwrap()
101 );
102 }
103
104 #[test]
update_args_with_flatten()105 fn update_args_with_flatten() {
106 #[derive(Args, PartialEq, Debug)]
107 struct Common {
108 arg: i32,
109 }
110
111 #[derive(Parser, PartialEq, Debug)]
112 struct Opt {
113 #[command(flatten)]
114 common: Common,
115 }
116
117 let mut opt = Opt {
118 common: Common { arg: 42 },
119 };
120 opt.try_update_from(["test"]).unwrap();
121 assert_eq!(Opt::try_parse_from(["test", "42"]).unwrap(), opt);
122
123 let mut opt = Opt {
124 common: Common { arg: 42 },
125 };
126 opt.try_update_from(["test", "52"]).unwrap();
127 assert_eq!(Opt::try_parse_from(["test", "52"]).unwrap(), opt);
128 }
129
130 #[derive(Subcommand, PartialEq, Debug)]
131 enum BaseCli {
132 Command1(Command1),
133 }
134
135 #[derive(Args, PartialEq, Debug)]
136 struct Command1 {
137 arg1: i32,
138
139 arg2: i32,
140 }
141
142 #[derive(Args, PartialEq, Debug)]
143 struct Command2 {
144 arg2: i32,
145 }
146
147 #[derive(Parser, PartialEq, Debug)]
148 enum Opt {
149 #[command(flatten)]
150 BaseCli(BaseCli),
151 Command2(Command2),
152 }
153
154 #[test]
merge_subcommands_with_flatten()155 fn merge_subcommands_with_flatten() {
156 assert_eq!(
157 Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42, arg2: 44 })),
158 Opt::try_parse_from(["test", "command1", "42", "44"]).unwrap()
159 );
160 assert_eq!(
161 Opt::Command2(Command2 { arg2: 43 }),
162 Opt::try_parse_from(["test", "command2", "43"]).unwrap()
163 );
164 }
165
166 #[test]
update_subcommands_with_flatten()167 fn update_subcommands_with_flatten() {
168 let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
169 opt.try_update_from(["test", "command1", "42", "44"])
170 .unwrap();
171 assert_eq!(
172 Opt::try_parse_from(["test", "command1", "42", "44"]).unwrap(),
173 opt
174 );
175
176 let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
177 opt.try_update_from(["test", "command1", "42"]).unwrap();
178 assert_eq!(
179 Opt::try_parse_from(["test", "command1", "42", "14"]).unwrap(),
180 opt
181 );
182
183 let mut opt = Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 12, arg2: 14 }));
184 opt.try_update_from(["test", "command2", "43"]).unwrap();
185 assert_eq!(
186 Opt::try_parse_from(["test", "command2", "43"]).unwrap(),
187 opt
188 );
189 }
190
191 #[test]
flatten_with_doc_comment()192 fn flatten_with_doc_comment() {
193 #[derive(Args, PartialEq, Debug)]
194 struct Common {
195 /// This is an arg. Arg means "argument". Command line argument.
196 arg: i32,
197 }
198
199 #[derive(Parser, PartialEq, Debug)]
200 struct Opt {
201 /// The very important comment that clippy had me put here.
202 /// It knows better.
203 #[command(flatten)]
204 common: Common,
205 }
206 assert_eq!(
207 Opt {
208 common: Common { arg: 42 }
209 },
210 Opt::try_parse_from(["test", "42"]).unwrap()
211 );
212
213 let help = utils::get_help::<Opt>();
214 assert!(help.contains("This is an arg."));
215 assert!(!help.contains("The very important"));
216 }
217
218 #[test]
docstrings_ordering_with_multiple_command()219 fn docstrings_ordering_with_multiple_command() {
220 /// This is the docstring for Flattened
221 #[derive(Args)]
222 struct Flattened {
223 #[arg(long)]
224 foo: bool,
225 }
226
227 /// This is the docstring for Command
228 #[derive(Parser)]
229 struct Command {
230 #[command(flatten)]
231 flattened: Flattened,
232 }
233
234 let short_help = utils::get_help::<Command>();
235
236 assert!(short_help.contains("This is the docstring for Command"));
237 }
238
239 #[test]
docstrings_ordering_with_multiple_clap_partial()240 fn docstrings_ordering_with_multiple_clap_partial() {
241 /// This is the docstring for Flattened
242 #[derive(Args)]
243 struct Flattened {
244 #[arg(long)]
245 foo: bool,
246 }
247
248 #[derive(Parser)]
249 struct Command {
250 #[command(flatten)]
251 flattened: Flattened,
252 }
253
254 let short_help = utils::get_help::<Command>();
255
256 assert!(short_help.contains("This is the docstring for Flattened"));
257 }
258
259 #[test]
optional_flatten()260 fn optional_flatten() {
261 #[derive(Parser, Debug, PartialEq, Eq)]
262 struct Opt {
263 #[command(flatten)]
264 source: Option<Source>,
265 }
266
267 #[derive(clap::Args, Debug, PartialEq, Eq)]
268 struct Source {
269 crates: Vec<String>,
270 #[arg(long)]
271 path: Option<std::path::PathBuf>,
272 #[arg(long)]
273 git: Option<String>,
274 }
275
276 assert_eq!(Opt { source: None }, Opt::try_parse_from(["test"]).unwrap());
277 assert_eq!(
278 Opt {
279 source: Some(Source {
280 crates: vec!["serde".to_owned()],
281 path: None,
282 git: None,
283 }),
284 },
285 Opt::try_parse_from(["test", "serde"]).unwrap()
286 );
287 assert_eq!(
288 Opt {
289 source: Some(Source {
290 crates: Vec::new(),
291 path: Some("./".into()),
292 git: None,
293 }),
294 },
295 Opt::try_parse_from(["test", "--path=./"]).unwrap()
296 );
297 }
298